Merged branch 'jetty-9.2.x' into 'jetty-9.3.x'.
diff --git a/.gitignore b/.gitignore
index 52260df..699c68b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,7 @@
 
 # merge tooling
 *.orig
+
+# test generated content
+*/src/test/*/WEB-INF/lib/test*.jar
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..84534fe
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,55 @@
+Contributing to Jetty
+=====================
+Thanks for your interest in this project.
+
+Project description
+--------------------
+Jetty is a lightweight highly scalable java based web server and servlet engine.
+Our goal is to support web protocols like HTTP, HTTP/2, and WebSocket in a high
+volume low latency way that provides maximum performance while retaining the ease
+of use and compatibility with years of servlet development.
+Jetty is a modern fully async web server that has a long history as a component
+oriented technology easily embedded into applications while still offering a solid
+traditional distribution for webapp deployment.
+
+- [https://projects.eclipse.org/projects/rt.jetty](https://projects.eclipse.org/projects/rt.jetty)
+
+Developer resources
+--------------------
+Information regarding source code management, builds, coding standards, and more.
+
+- [https://www.eclipse.org/jetty/documentation/current/advanced-contributing.html](https://www.eclipse.org/jetty/documentation/current/advanced-contributing.html)
+
+The canonical Jetty git repository is located at git.eclipse.org and we are unable
+to directly merge pull requests into the GitHub mirrored repository.
+Providing you have completed the contributors agreement mentioned below we will
+endeavor to pull your commit into Jetty proper.
+
+Contributor License Agreement
+------------------------------
+Before your contribution can be accepted by the project, you need to create and electronically sign the
+Eclipse Foundation [Contributor License Agreement](https://www.eclipse.org/legal/CLA.php) (CLA):
+
+1. Log in to the [Eclipse projects forge](https://projects.eclipse.org/user/login/sso). You will need to
+   create an account with the Eclipse Foundation if you have not already done so.
+2. Click on "Contributor License Agreement", and complete the form.
+
+Be sure to use the same email address in your Eclipse account that you intend to use when you commit to Git.
+
+Contact
+--------
+Contact the project developers via the project's "dev" list.
+
+- [https://dev.eclipse.org/mailman/listinfo/jetty-dev](https://dev.eclipse.org/mailman/listinfo/jetty-dev)
+
+Search for bugs
+----------------
+This project uses Bugzilla to track ongoing development and issues.
+
+- [https://bugs.eclipse.org/bugs/buglist.cgi?product=Jetty](https://bugs.eclipse.org/bugs/buglist.cgi?product=Jetty)
+
+Create a new bug
+-----------------
+Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome!
+
+- [https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Jetty](https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Jetty)
diff --git a/NOTICE.txt b/NOTICE.txt
index 2b7d3f7..8ea92af 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -18,20 +18,54 @@
 
 Jetty may be distributed under either license.
 
+------
+Eclipse
+
+The following artifacts are EPL.
+ * org.eclipse.jetty.orbit:org.eclipse.jdt.core
+
+The following artifacts are EPL and ASL2.
+ * org.eclipse.jetty.orbit:javax.security.auth.message
+
+
+The following artifacts are EPL and CDDL 1.0.
+ * org.eclipse.jetty.orbit:javax.mail.glassfish
+
 
 ------
 Oracle
 
 The following artifacts are CDDL + GPLv2 with classpath exception.
-
 https://glassfish.dev.java.net/nonav/public/CDDL+GPL.html
 
-javax.servlet:javax.servlet-api
-javax.servlet.jsp:javax.servlet.jsp-api
-org.glassfish.web:javax.servlet.jsp
-org.glassfish.web:javax.servlet.jsp
-org.glassfish.web:javax.servlet.jsp.jstl
-org.eclipse.jetty.orbit.javax.servlet.jsp.jstl
+ * javax.servlet:javax.servlet-api
+ * javax.annotation:javax.annotation-api
+ * javax.transaction:javax.transaction-api
+ * javax.websocket:javax.websocket-api
+
+------
+Oracle OpenJDK
+
+If ALPN is used to negotiate HTTP/2 connections, then the following
+artifacts may be included in the distribution or downloaded when ALPN 
+module is selected. 
+
+ * java.sun.security.ssl
+
+These artifacts replace/modify OpenJDK classes.  The modififications
+are hosted at github and both modified and original are under GPL v2 with 
+classpath exceptions.
+http://openjdk.java.net/legal/gplv2+ce.html
+
+
+------
+OW2
+
+The following artifacts are licensed by the OW2 Foundation according to the
+terms of http://asm.ow2.org/license.html
+
+org.ow2.asm:asm-commons
+org.ow2.asm:asm
 
 
 ------
diff --git a/README.TXT b/README.TXT
index 9157b3e..f54c476 100644
--- a/README.TXT
+++ b/README.TXT
@@ -1,4 +1,4 @@
-This is a source checkout of the Jetty webserver.
+This is a source checkout of the Eclipse Jetty webserver.
 
 To build, use:
 
@@ -18,4 +18,3 @@
 Bypass tests by building with -Dmaven.test.skip=true but note
 that this will not produce some test jars that are leveraged
 in other places in the build.
-
diff --git a/README.md b/README.md
index 2e9bf5c..9b53ea8 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 ============
 
 Jetty is a lightweight highly scalable java based web server and servlet engine.
-Our goal is to support web protocols like HTTP, SPDY and WebSocket in a high
+Our goal is to support web protocols like HTTP, HTTP/2 and WebSocket in a high
 volume low latency way that provides maximum performance while retaining the ease
 of use and compatibility with years of servlet development. Jetty is a modern
 fully async web server that has a long history as a component oriented technology
diff --git a/VERSION.txt b/VERSION.txt
index 608b2c5..8457779 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,4 +1,35 @@
-jetty-9.2.15-SNAPSHOT
+jetty-9.3.7-SNAPSHOT
+
+jetty-9.3.6.v20151106 - 06 November 2015
+ + 419966 Add ContentProvider that submits multipart/form-data.
+ + 472675 No main manifest attribute, in jetty-runner regression
+ + 476641 Proxy rewriteTarget() null return does not call error handler.
+ + 478757 DebugHandler thread name is mangled
+ + 479179 Fixed NPE from debug
+ + 479378 Incorrect REQUEST_URI.
+ + 479712 Documented --approve-all-licenses
+ + 479832 Use system properties for gcloud config for GCloudDatastore session
+   manager
+ + 479839 Regression when starting application with excessive scan times
+ + 479865 IllegalStateException: Multiple servlets map to path: *.jsp: jsp,jsp
+ + 480061 HTTP/2 server doesn't send GOAWAY frame when shutting down.
+ + 480162 Continuations behavior differences due to HttpURI behavior
+ + 480260 HPack decode error for buffers with offset.
+ + 480272 Update to newer jdt ecj version
+ + 480452 Large downloads via FastCGI proxy keep HttpClient connections active.
+ + 480764 Error parsing empty multipart.
+ + 481006 SSL requests intermittently fail with EOFException when SSL
+   renegotiation is disallowed.
+ + 481203 Add ability to set configurations to apply to WebAppContext for
+   jetty-maven-plugin
+ + 481225 Secondary resources with query parameters are not properly pushed.
+ + 481236 Make ShutdownMonitor java security manager friendly
+ + 481355 Nested Symlinks
+ + 481373 Corner cases where session may remain in JDBCSessionManager memory
+ + 481385 Incorrect parsing of END_REQUEST frames.
+ + 481418 ResourceHandler sets last modified
+ + 481437 Port ConnectHandler connect and context functionality from Jetty 8.
+ + 481554 DispatcherType reset race
 
 jetty-9.2.14.v20151106 - 06 November 2015
  + 428474 Expose batch mode in the Jetty WebSocket API
@@ -20,6 +51,115 @@
  + 481236 Make ShutdownMonitor java security manager friendly
  + 481437 Port ConnectHandler connect and context functionality from Jetty 8.
 
+jetty-9.3.5.v20151012 - 12 October 2015
+ + 479343 calls to MetaData#orderFragments() with relative ordering adds
+   duplicate jars
+ + 479537 Server preface sent after client preface reply.
+ + 479584 WS Session does not contain UpgradeRequest information in
+   WebSocketAdapter.onWebSocketConnect callback
+
+jetty-9.3.4.v20151007 - 07 October 2015
+ + 428474 Expose batch mode in the Jetty WebSocket API
+ + 472082 isOpen returns true on CLOSING Connection
+ + 474936 WebSocketSessions are not always cleaned out from openSessions
+ + 475209 WebSocketServerFactory should not hand null object to
+   DecoratedObjectFactory
+ + 476023 Incorrect trimming of WebSocket close reason
+ + 476049 When using WebSocket Session.close() there should be no status code
+   or reason sent
+ + 476170 Support servers that close connections without sending Connection:
+   close header.
+ + 476720 getTrustStoreResource fixed
+ + 477087 Enforce that the preface contains a SETTINGS frame.
+ + 477123 AsyncListener callbacks need context scope
+ + 477270 Add ability to send a single PRIORITY frame.
+ + 477278 Refactored DefaultServlet for cached Gzip & Etags
+ + 477385 Make jetty osgi manifests only resolve jetty packages against a
+   single distro version
+ + 477641 ALPN classes exposed to webapps - fixed typo
+ + 477680 Encode merged query parameters
+ + 477737 Improve handling of etags with dynamic and static gzip
+ + 477757 Null args in TypeUtil .call & .construct result in confusing
+   exceptions
+ + 477817 Fixed memory leak in QueuedThreadPool
+ + 477878 HttpClient over HTTP/2 doesn't close upload stream.
+ + 477885 Jetty HTTP2 client fails to connect with Netty server - HTTP2 client
+   preface missing or corrupt.
+ + 477890 Overwhelmed HTTP/2 server discards data.
+ + 477895 Prevent leak of handles to deleted files after redeploy
+ + 477900 Increase client authentication default max content size
+ + 478008 Do not reset current value of CounterStatistics
+ + 478021 Client sending Connection: close does not shutdown output.
+ + 478105 prependFilterMapping check for null FilterHolder
+ + 478239 Remove pointless synchronize in infinispan scavenging
+ + 478247 WebappClassLoader pinned after redeploy
+ + 478275 Priority information in HEADERS frame is not sent.
+ + 478280 property file in temp directory
+ + 478372 JavaUtilLog setSourceClass and setSourceMethod
+ + 478434 Priority weights should be between 1 and 256 inclusive.
+ + 478752 Clarify support for HttpServletRequest.upgrade()
+ + 478757 DebugHandler thread name is mangled
+ + 478829 WebsocketSession not cleaned up / memory leak
+ + 478862 Update to jstl 1.2.5
+ + 478923 threads stuck at SharedBlockingCallback$Blocker.block
+ + 479026 Wrong CONNECT request idle timeout.
+ + 479277 HttpClient with HTTP/2 transport does not work for "https" URLs.
+
+jetty-9.3.3.v20150827 - 27 August 2015
+ + 470311 Introduce a proxy-protocol module.
+ + 471055 Restore legacy/experimental WebSocket extensions (deflate-frame)
+ + 472411 PathResource.checkAliasPath() typo
+ + 473321 Overriding SSL context KeyStoreType requires explicit override of
+   TrustStoreType
+ + 474025 SslContextFactory does not work with JCEKS Keystore
+ + 474068 Update WebSocket Extension for permessage-deflate draft-22
+ + 474319 Reintroduce blocking connect().
+ + 474321 Allow synchronous address resolution.
+ + 474344 apache-jstl includes test dependencies
+ + 474358 DefaultServlet bad Content-Type on compressed content
+ + 474361 Handle JVM version extensions like -internal
+ + 474453 Tiny buffers (under 7 bytes) fail to compress in permessage-deflate
+ + 474454 Backport permessage-deflate from Jetty 9.3.x to 9.2.x
+ + 474455 Enable permessage-deflate WebSocket extension
+ + 474558 Debug log ServletContainerInitializer @HandlesTypes contents
+ + 474617 AsyncListener.onError not called for errors
+ + 474618 AsyncListener.onComplete not called when error occurs
+ + 474634 AsyncListener.onError() handling.
+ + 474685 GzipHandler configuration supports csv paths and mimetypes.
+ + 474888 HttpClient JMX support.
+ + 474936 WebSocketSessions are not always cleaned out from openSessions
+ + 474961 Close input stream for classes in AnnotationParser after scanning
+ + 475195 SNI matching fails when keystore does not contain wild certificates.
+ + 475483 Starting Jetty with [exec] should use properties file.
+ + 475546 ClosedChannelException when connecting to HTTPS over HTTP proxy with
+   CONNECT.
+ + 475605 Add support for multi-homed destinations.
+ + 475927 SecureRequestCustomizer fails to match host.
+
+jetty-9.3.2.v20150730 - 30 July 2015
+ + 470351 Fixed SNI matching of wildcard certificates
+ + 470727 Thread Starvation of selector wakeups.
+ + 472601 org.eclipse.jetty.util.log.Log.setLog() does not work as before
+ + 472621 Unjustified timeout when serving static content
+ + 472781 GzipHandler isMimeTypeGzipable() bad logic
+ + 472859 ConcatServlet may expose protected resources.
+ + 472931 HttpConfiguration copy constructor incomplete
+ + 472974 Improved StatisticsHandler 503 generation
+ + 473006 Encode addPath in URLResource
+ + 473118 HTTP/2 server does not retrieve Host header from client.
+ + 473243 Delay resource close for async default content
+ + 473266 Better handling of MultiException
+ + 473294 Fixed include cipher suites support for wildcards
+ + 473307 Add 301 Moved Permanently Rules to jetty-rewrite
+ + 473309 Add special (non-replacement) Terminating rules to jetty-rewrite
+ + 473319 Parameterize status code on Redirect Rules for alternate use
+ + 473321 Overriding SSL context KeyStoreType requires explicit override of
+   TrustStoreType
+ + 473322 GatherWrite limit handling
+ + 473624 ProxyServlet.Transparent / TransparentDelegate add trailing slash
+   before query when using prefix.
+ + 473832 SslConnection flips back buffers on handshake exception
+
 jetty-9.2.13.v20150730 - 30 July 2015
  + 472859 ConcatServlet may expose protected resources.
  + 473006 Encode addPath in URLResource
@@ -30,6 +170,225 @@
    before query when using prefix.
  + 473832 SslConnection flips back buffers on handshake exception
 
+jetty-9.3.1.v20150714 - 14 July 2015
+ + 441020 Support HEADERS followed by CONTINUATION+.
+ + 460671 Rationalize property names (fix for jetty.sh)
+ + 462346 Change classesPattern to scanClassesPattern and testClassesPattern to
+   scanTestClassesPattern to clarify purpose
+ + 464294 AsyncNCSARequestLog blocks JVM exit after failure
+ + 464741 HttpFields declares IllegalArgumentException as checked exception
+ + 464745 Remove @org.apache.xbean.XBean references
+ + 469384 Improved javadoc for ClasspathPattern
+ + 470184 Send the proxy-to-server request more lazily.
+ + 470327 Problem with scope provided dependencies with jspc plugin
+ + 470505 jetty-maven-plugin JettyWebAppContext#setQuickStartWebDescriptor
+   should accept a Maven-friendly type
+ + 470664 Handle multiple RequestLogHandler in chain
+ + 470727 Thread Starvation of selector wakeups.
+ + 470803 If a webapp is not fully started do not fully stop it
+ + 470855 Only log warning for duplicate path mappings to same servlet in same
+   descriptor
+ + 470963 Update jetty-maven-plugin mojo annotations for maven 3
+ + 471071 jetty-infinispan.xml incorrect syntax for remote named cache
+ + 471076 Apache jspc ignores empty list of files to precompile and scans
+   anyway
+ + 471251 Improved debugging on async timeout
+ + 471272 ArrayIndexOutOfBoundsException in
+   org.eclipse.jetty.quickstart.PreconfigureQuickStartWar
+ + 471388 StringIndexOutOfBoundsException when using <c:url> with parameters
+ + 471464 Parsing issues with HttpURI
+ + 471604 Extend CrossOriginFilter to provide a Timing-Allow-Origin header
+ + 471623 Update to apache jsp 8.0.23 Use 8.0.23.M1 for jetty version of apache
+   jsp 8.0.23
+ + 471985 NPE in HttpFields.putField
+ + 472310 Improved logging when no supported included ciphers
+ + 472411 PathResource.checkAliasPath typo
+ + 472422 Custom status codes result in a NumberFormatException while using
+   http2.
+
+jetty-9.3.0.v20150612 - 12 June 2015
+ + 414479 Add WebSocketPingPongListener for those that want PING/PONG payload
+   data
+ + 420678 Add WebSocketPartialListener to support receiving partial WebSocket
+   TEXT/BINARY messages
+ + 420944 Hot Deployment of WAR when Context XML exists doesn't trigger
+   redeploy
+ + 423974 Optimize flow control.
+ + 424368 Add CONTRIBUTING.md
+ + 430951 Support SNI with ExtendedSslContextFactory
+ + 436345 Refactor AbstractSession to minimize burden on subclasses to
+   implement behaviour
+ + 437303 Serving of static filenames with "unwise" characters causes 404 error
+ + 437395 Start / Properties in template sections should be default applied for
+   enabled modules
+ + 438204 getServerName returns IPv6 addresses wrapped in []
+ + 439369 Remove unused class CrossContextPsuedoSession
+ + 439374 Use utf-8 as default charset for html
+ + 439375 preferred rfc7231 format is mime;charset=lowercase-9
+ + 440106 Improve ProtocolHandler APIs.
+ + 440506 Jetty OSGi boot bundle does not support OSGi framework Eclipse
+   Concierge
+ + 442083 Client resets stream, pending server data is failed, connection
+   closed.
+ + 442086 Review HttpOutput blocking writes.
+ + 442477 Allow Symlink aliases by default
+ + 442495 Bad Context ClassLoader in JSR356 WebSocket onOpen
+ + 442950 Embedded Jetty client requests to localhost hangs with high cpu usage
+   (NIO OP_CONNECT Solaris/Sparc).
+ + 443652 Remove dependency on java.lang.management classes
+ + 443661 Rename manifest and service constants for jetty osgi resource
+   fragment code
+ + 443662 Consume buffer in write(ByteBuffer)
+ + 443713 Reduce number of SelectionKey.setInterestOps() calls.
+ + 443893 Make a module for weld
+ + 444124 JSP include with <servlet><jsp-file> can cause infinite recursion
+ + 444214 Socks4Proxy fails when reading less than 8 bytes.
+ + 444222 replace CRLF in header values with whitespace rather than ?
+ + 444416 AsyncProxyServlet recursion.
+ + 444485 Client resets stream, pending server data is failed, write hangs.
+ + 444517 Ensure WebSocketUpgradeFilter is always first in filter chain
+ + 444547 Format exception in ResourceCache.Content.toString()
+ + 444617 Expose local and remote socket address to applications
+ + 444721 PushCacheFilter cleanup/improvements.
+ + 444748 WebSocketClient.stop() does not unregister from ShutdownThread
+ + 444764 HttpClient notifies callbacks for last chunk of content twice.
+ + 444771 JSR356 / EndPointConfig.userProperties are not unique per endpoint
+   upgrade
+ + 445167 Allow configuration of dispatch after select.
+ + 445823 Moved RequestLog calling to HttpChannel
+ + 446559 Avoid spin consuming extra data
+ + 446564 Refactored RequestLog Mechanism
+ + 446944 ServletTester and HttpTester should be in
+   <classifier>tests</classifier>
+ + 447216 putAll Properties in XmlConfiguration
+ + 447515 Remove GzipFilter
+ + 448156 Fixed INACTIVE race in IteratingCallback
+ + 448675 Impossible to set own Threadpool when using jetty-maven-plugin
+ + 449003 WARNING: Cannot enable requested module [protonego-impl]: not a valid
+   module name
+ + 449811 handle unquoted etags when gzipping
+ + 450467 Integer overflow in Session expiry calculation in MongoSessionManager
+ + 451973 Ambiguous module init location when mixing --add-to-start &
+   --add-to-startd in the same exec
+ + 451974 Combine multiple start license acknowledgement into one
+ + 452188 Delay dispatch until content optimisation
+ + 452322 Restore progress messages for --add-to-start(d) use
+ + 452323 Start --list-config makes no hint on transitive enabled modules
+ + 452329 Transitive modules in start.jar --add-to-start(d) are not added if
+   enabled already in tree
+ + 452465 100% CPU spin on page reload.
+ + 452503 Start.jar --add-to-start=jstl results in GraphException: Unable to
+   expand property in name: jsp-impl/${jsp-impl}-jstl
+ + 453487 Recycle HttpChannelOverHTTP2
+ + 453627 Fixed FileSystem test for nanosecond filesystems
+ + 453636 Improved spin detection on test
+ + 453829 Added HeaderRegexRule
+ + 453834 CDI Support for WebSocket
+ + 454152 Remove mux remnants from WebSocketClient
+ + 454934 WebSocketClient / connectToServer can block indefinitely during
+   upgrade failure
+ + 454952 Allow Jetty to run in Java 8 compact 3 profile
+ + 456209 Bad ContextClassLoader in WebSocket onMessage
+ + 456956 Reduce ThreadLocal.remove() weak reference garbage
+ + 457130 HTTPS request with IP host and HTTP proxy throws
+   IllegalArgumentException.
+ + 457309 Add test to ensure GET and HEAD response headers same for gzip
+ + 457508 Add flag to scan exploded jars in jetty-jspc-maven-plugin
+ + 457788 Powered By in o.e.j.util.Jetty conditional on sendServerVersion
+ + 458478 JarFileResource improve performance of exist method
+ + 458527 Implement an async proxy servlet that can perform content
+   transformations.
+ + 458663 Handle null header values
+ + 459081 http2 push failures.
+ + 459542 AsyncMiddleManServlet race condition on first download content.
+ + 459655 Remove SPDY and NPN
+ + 459681 Remove dead code after removal of glassfish jasper support
+ + 459731 Update for drafts hpack-11 and http2-17
+ + 459734 Update to apache jsp 8.0.20
+ + 459845 Support upgrade from http1 to http2.
+ + 460187 infinite recursion in sending error.
+ + 460210 ExecutionStragegy producer for SelectManager calls onOpen from
+   produce method
+ + 460211 Fixed Idle race in ExecuteProduceRun
+ + 460297 Parameterize infinispan.mod
+ + 460670 Support multiple names in <Property> elements.
+ + 460671 Rationalize property names.
+ + 460746 HttpConfiguration#setPersistentConnectionsEnabled(boolean)
+ + 461052 Local streams created after INITIAL_WINDOW_SIZE setting have wrong
+   send window.
+ + 461350 Update HttpParser IllegalCharacter handling to RFC7230
+ + 461415 Maven Jetty Plugin ignores ZIP overlays
+ + 462040 reverted and deprecated getStringField methods
+ + 462098 Support setting ThreadGroup in ScheduledExecutorScheduler
+ + 462162 StackOverflowException when response commit fails.
+ + 462193 Asynchronous HttpOutput.close()
+ + 463036 system properties to set ssl password and keypasword
+ + 463144 modules do not see pre-downloaded ALPN libs
+ + 464419 Removed xinetd support
+ + 464438 ClassFileTransformer support in
+   org.eclipse.jetty.webapp.WebAppClassLoader broken
+ + 464442 Enable parallel class loading
+ + 464528 NPE protection in getIncludedCipher suites
+ + 464537 Updated setuid dependency to 1.0.3.
+ + 464555 ALPN module download attempts to download jar before dir exists
+ + 464556 Restrict start module downloads to ${jetty.base} paths only
+ + 464564 NoSql sessions created inside a forward not persisted correctly
+ + 464606 Support property expansion in "default" attribute of Property.
+ + 464629 JDK8 Socket customization
+ + 464630 Cannot configure Configuration classlist in osgi
+ + 464633 Change Selection.how to Selection.criteria
+ + 464706 HTTP/2 and async I/O: onDataAvailable() not called.
+ + 464708 Support HttpConfiguration.delayDispatchUntilContent in HTTP/2.
+ + 464724 MultiPartInputStreamParser.parse ServletException never thrown
+ + 464727 Update Javadoc for Java 8 DocLint
+ + 464744 PathMap.match() never throws IllegalArgumentException
+ + 464837 Large META-INF/resources/ jars can significantly impact startup speed
+ + 464839 Add limit to MongoSessionIdManager purge queries
+ + 464869 org.eclipse.jetty.util.resource.PathResource do not work
+ + 465118 Fixed GzipHandler handling of multiple closes
+ + 465606 IteratingCallback.close() does not fail pending callback.
+ + 465754 Unchecked PrintWriter errors
+ + 465854 Provide java.nio.file.WatchService alternative for Scanner
+ + 465857 Support HTTP/2 clear-text server-side upgrade.
+ + 465867 Implement --skip-file-validation=<module>
+ + 466005 Use Files.move(src,trgt) instead of File.rename for
+   Part.write(filename)
+ + 466283 Support specifying ALPN protocols in HTTP2Client.
+ + 466618 Partial WebSocket Text delivery does not like incomplete UTF8
+   sequences
+ + 466619 Add WebSocketFrameListener for receiving WebSocket Frame information
+ + 466628 Improve IllegalStateException on ServletInputStream.setReadListener()
+ + 466645 Allow XmlConfiguration Properties to use Elements or Attributes
+ + 466647 Add ${jetty.tag.version} property and expand URL properties
+ + 466648 jetty-ssl download of keystore should be from tags, not master
+ + 466669 Add nosql.mod into jetty distro
+ + 466678 Make a .mod file for jdbc session management
+ + 466774 Update jetty-all module for Jetty 9.3
+ + 467036 WebSocketClient fails to process immediate frames from server
+ + 467043 WebSocketClient close codes on protocol violation reported as policy
+   violation
+ + 467055 Mongodb session scavenging can result in very slow query
+ + 467165 Add --skip-file-validation to start.jar --help output
+ + 467281 Remove Java 1.7 support from Jetty 9.3
+ + 467289 Not possible to specify jmxrmi port value
+ + 467702 SslContextFactory not backward compatible
+ + 467730 HTTP2 requires enabled ciphers to be sorted by blacklist
+ + 467790 Update default etc files inside jetty-osgi-boot bundle
+ + 468313 PushCacheFilter wrongly associates primary resources to themselves.
+ + 468347 Fix modules/debuglog.mod.
+ + 469241 Use null WatchService as loop terminator for PathWatcher.
+ + 469341 Not possible to use old/deprecated start properties
+ + 469414 Proxied redirects expose upstream server name.
+ + 469633 Make SpinLock behavior pluggable.
+ + 469799 Transitive module dependencies without ini templates are still added
+   to ini
+ + 469860 Add module metadata versioning to support backwards compat
+ + 469863 fixed setNeedClientAuth/setWantClientAuth
+ + 469936 Remove usages of SpinLock.
+ + 469982 Produce warning for dynamic modules with ini-templates seen during
+   --add-to-start
+ + 469991 Fix logging levels in websocket client UpgradeConnection
+
 jetty-9.2.12.v20150709 - 09 July 2015
  + 469414 Proxied redirects expose upstream server name.
  + 469936 Remove usages of SpinLock.
@@ -65,6 +424,118 @@
  + 468714 SelectorManager updateKey race without submit
  + 468747 XSS vulnerability in HttpSpiContextHandler
 
+jetty-9.3.0.RC1 - 22 May 2015
+ + 464839 Add limit to MongoSessionIdManager purge queries
+ + 465053 Prevent gzip buffer overflow on complete
+ + 466774 Update jetty-all module for Jetty 9.3
+ + 467055 Mongodb session scavenging can result in very slow query
+ + 467165 Add --skip-file-validation to start.jar --help output
+ + 467276 NPE protection in SslContextFactory
+ + 467281 Remove Java 1.7 support from Jetty 9.3
+ + 467289 Not possible to specify jmxrmi port value
+ + 467603 Response 401 from server hangs client.
+ + 467702 SslContextFactory not backward compatible
+ + 467730 HTTP2 requires enabled ciphers to be sorted by blacklist
+ + 467790 Update default etc files inside jetty-osgi-boot bundle
+ + 467936 w Check HttpOutput aggregateSize is < bufferSize
+
+jetty-9.3.0.RC0 - 12 May 2015
+ + 414479 Add WebSocketPingPongListener for those that want PING/PONG payload
+   data
+ + 420678 Add WebSocketPartialListener to support receiving partial WebSocket
+   TEXT/BINARY messages
+ + 423974 Optimize flow control.
+ + 430951 Support SNI with ExtendedSslContextFactory
+ + 436345 Refactor AbstractSession to minimize burden on subclasses to
+   implement behaviour
+ + 440106 Improve ProtocolHandler APIs.
+ + 444721 PushCacheFilter cleanup/improvements.
+ + 446564 Refactored RequestLog Mechanism
+ + 451973 Ambiguous module init location when mixing --add-to-start &
+   --add-to-startd in the same exec
+ + 453834 CDI Support for WebSocket
+ + 454934 WebSocketClient / connectToServer can block indefinitely during
+   upgrade failure
+ + 457309 Add test to ensure GET and HEAD response headers same for gzip
+ + 457508 Add flag to scan exploded jars in jetty-jspc-maven-plugin
+ + 457788 Powered By in o.e.j.util.Jetty conditional on sendServerVersion
+ + 458478 JarFileResource improve performance of exist method
+ + 459273 Redundant license notices
+ + 459734 Update to apache jsp 8.0.20
+ + 459845 Support upgrade from http1 to http2.
+ + 460187 infinite recursion in sending error.
+ + 460297 Parameterize infinispan.mod
+ + 460671 Rationalize property names.
+ + 460746 HttpConfiguration#setPersistentConnectionsEnabled(boolean)
+ + 461415 Maven Jetty Plugin ignores ZIP overlays
+ + 461499 ConnectionPool may leak connections.
+ + 461919 Use osgi-friendly serviceloader mechanism for WebSocketServletFactory
+ + 461941 JMX Remote host:port set from start properties
+ + 462040 reverted and deprecated getStringField methods
+ + 462098 Support setting ThreadGroup in ScheduledExecutorScheduler
+ + 462162 StackOverflowException when response commit fails.
+ + 462193 Asynchronous HttpOutput.close()
+ + 462546 ShutdownMonitor should bind to jetty.host
+ + 462616 Race between finishing a connect and timing it out.
+ + 463036 system properties to set ssl password and keypasword
+ + 463144 modules do not see pre-downloaded ALPN libs
+ + 463579 Add support for 308 status code.
+ + 464292 Implement stream-based transformer for AsyncMiddleManServlet.
+ + 464419 Removed xinetd support
+ + 464438 ClassFileTransformer support in
+   org.eclipse.jetty.webapp.WebAppClassLoader broken
+ + 464442 Enable parallel class loading
+ + 464528 NPE protection in getIncludedCipher suites
+ + 464537 Updated setuid dependency to 1.0.3.
+ + 464555 ALPN module download attempts to download jar before dir exists
+ + 464556 Restrict start module downloads to ${jetty.base} paths only
+ + 464564 NoSql sessions created inside a forward not persisted correctly
+ + 464606 Support property expansion in "default" attribute of Property.
+ + 464629 JDK8 Socket customization
+ + 464630 Cannot configure Configuration classlist in osgi
+ + 464633 Change Selection.how to Selection.criteria
+ + 464706 HTTP/2 and async I/O: onDataAvailable() not called.
+ + 464708 Support HttpConfiguration.delayDispatchUntilContent in HTTP/2.
+ + 464724 MultiPartInputStreamParser.parse ServletException never thrown
+ + 464727 Update Javadoc for Java 8 DocLint
+ + 464740 DosFilter whiteList check improvement
+ + 464744 PathMap.match() never throws IllegalArgumentException
+ + 464837 Large META-INF/resources/ jars can significantly impact startup speed
+ + 464869 org.eclipse.jetty.util.resource.PathResource do not work
+ + 464989 AbstractSessionManager.removeEventListener() should remove
+   HttpSessionIdListener
+ + 465181 HttpParser parse full end chunk.
+ + 465202 Forked Mojo does not extract war overlays/dependencies
+ + 465359 Resource.newResource(String res, boolean useCache) does not use
+   useCache argument
+ + 465360 URLResource.addPath should use _useCaches setting to create new
+   Resource
+ + 465606 IteratingCallback.close() does not fail pending callback.
+ + 465700 NullPointerException in ResourceHandler with welcome files
+ + 465734 DosFilter whitelist bit pattern fix
+ + 465747 Jetty is failing to process all HTTP OPTIONS requests.
+ + 465754 Unchecked PrintWriter errors
+ + 465854 Provide java.nio.file.WatchService alternative for Scanner
+ + 465857 Support HTTP/2 clear-text server-side upgrade.
+ + 465867 Implement --skip-file-validation=<module>
+ + 466005 Use Files.move(src,trgt) instead of File.rename for
+   Part.write(filename)
+ + 466283 Support specifying ALPN protocols in HTTP2Client.
+ + 466329 Fixed local only TestFilter
+ + 466618 Partial WebSocket Text delivery does not like incomplete UTF8
+   sequences
+ + 466619 Add WebSocketFrameListener for receiving WebSocket Frame information
+ + 466628 Improve IllegalStateException on ServletInputStream.setReadListener()
+ + 466645 Allow XmlConfiguration Properties to use Elements or Attributes
+ + 466647 Add ${jetty.tag.version} property and expand URL properties
+ + 466648 jetty-ssl download of keystore should be from tags, not master
+ + 466669 Add nosql.mod into jetty distro
+ + 466678 Make a .mod file for jdbc session management
+ + 466774 Update jetty-all module for Jetty 9.3
+ + 467036 WebSocketClient fails to process immediate frames from server
+ + 467043 WebSocketClient close codes on protocol violation reported as policy
+   violation
+
 jetty-9.2.11.M0 - 25 March 2015
  + 454934 WebSocketClient / connectToServer can block indefinitely during
    upgrade failure
@@ -75,6 +546,148 @@
  + 462546 ShutdownMonitor should bind to jetty.host
  + 462616 Race between finishing a connect and timing it out.
 
+jetty-9.3.0.M2 - 11 March 2015
+ + 383207 Use BundleFileLocatorHelperFactory to obtain BundleFileLocatorHelper
+ + 420944 Hot Deployment of WAR when Context XML exists doesn't trigger
+   redeploy
+ + 423974 Optimize flow control.
+ + 424368 Add CONTRIBUTING.md
+ + 430951 Improved ordering of SSL ciphers
+ + 439374 Use utf-8 as default charset for html
+ + 440506 Jetty OSGi boot bundle does not support OSGi framework Eclipse
+   Concierge
+ + 443652 Remove dependency on java.lang.management classes
+ + 445518 Provide different error callbacks to ProxyServlet.
+ + 446564 Refactored RequestLog Mechanism
+ + 447472 Clear async context timeout on async static content
+ + 448446 org.eclipse.jetty.start.Main create classloader duplicate
+ + 448944 Provide m2e lifecycle mapping metadata for jetty-jspc-maven-plugin
+ + 449594 Handle ArrayTrie overflow with false return
+ + 449811 handle unquoted etags when gzipping
+ + 450467 Integer overflow in Session expiry calculation in MongoSessionManager
+ + 450483 Missing parameterization of etc/jetty-deploy.xml.
+ + 450484 Missing parameterization of etc/jetty-http[s].xml.
+ + 450855 GzipFilter MIGHT_COMPRESS exception
+ + 450873 Disable tests that downcaste wrapped GzipFilterResponses
+ + 450894 jetty.sh does not delete JETTY_STATE at start
+ + 451092 Connector will fail if HeaderListener return false.
+ + 451529 Change sentinel class for finding jstl on classpath to
+   org.apache.taglibs.standard.tag.rt.core.WhenTag
+ + 451634 DefaultServlet: useFileMappedBuffer javadoc is misleading
+ + 451973 Ambiguous module init location when mixing --add-to-start &
+   --add-to-startd in the same exec
+ + 451974 Combine multiple start license acknowledgement into one
+ + 452188 Delay dispatch until content optimisation
+ + 452201 Set the container classloader for osgi during webbundle undeploy
+ + 452246 Fixed SSL hang on last chunk
+ + 452261 Ensure <jsp-file> works with new JettyJspServlet
+ + 452322 Restore progress messages for --add-to-start(d) use
+ + 452323 Start --list-config makes no hint on transitive enabled modules
+ + 452329 Transitive modules in start.jar --add-to-start(d) are not added if
+   enabled already in tree
+ + 452424 Do not add Date header if already set
+ + 452465 100% CPU spin on page reload.
+ + 452503 Start.jar --add-to-start=jstl results in GraphException: Unable to
+   expand property in name: jsp-impl/${jsp-impl}-jstl
+ + 452516 Make HttpOutput aggregation size configurable.
+ + 453386 Jetty not working when configuring QueuedThreadPool with
+   minThreads=0.
+ + 453487 Recycle HttpChannelOverHTTP2
+ + 453627 Fixed FileSystem test for nanosecond filesystems
+ + 453629 Fixed big write test
+ + 453636 Improved spin detection on test
+ + 453793 _maxHeaderBytes>0 is not verified in parseNext() when in
+   State.CLOSED.
+ + 453801 Jetty does not check for already registered services when
+   bootstrapping
+ + 453829 removed code with yahoo copyright
+ + 454152 Remove mux remnants from WebSocketClient
+ + 454157 HttpInput.consumeAll spins if input is in async mode.
+ + 454291 Added busy threads JMX attribute to QueuedThreadPool
+ + 454773 SSLConnection use on Android client results in loop
+ + 454952 Allow Jetty to run in Java 8 compact 3 profile
+ + 454954 Jetty osgi should skip fragment and required bundles that are in the
+   uninstalled state
+ + 454955 OSGi AnnotationParser should skip resources that are not in the
+   classpath and close the class inputstream when done scanning it
+ + 454983 Source bundles should not be singleton
+ + 455047 Update JASPI
+ + 455174 jetty-plus JNDI tests should use unique JNDI paths
+ + 455330 Multiple Jetty-ContextFilePath entries separated by commas doesn't
+   work
+ + 455436 ProxyServlet sends two User-Agent values.
+ + 455476 Persist updated session expiry time for MongoSessionManager
+ + 455655 ensure multipart form-data parsing exception thrown to servlet
+ + 455863 Fixed jetty.sh handling of multiple JETTY_ARGS
+ + 456209 Bad ContextClassLoader in WebSocket onMessage
+ + 456426 Exception on context undeploy from EnvConfiguration
+ + 456486 Jar containing ServiceContainerInitializer impl not found in TCCL in
+   osgi
+ + 456521 ShutdownHandler should shut down more gracefully
+ + 456956 Reduce ThreadLocal.remove() weak reference garbage
+ + 457017 Reflective call to websocket methods that fail have ambiguous
+   exceptions
+ + 457032 Request sent from a failed CompleteListener due to connect timeout is
+   failed immediately.
+ + 457130 HTTPS request with IP host and HTTP proxy throws
+   IllegalArgumentException.
+ + 457696 JMX implementation should not be overridden by WebApp classes
+ + 457893 Close temp jar resource
+ + 458101 added test for maxFormContentSize
+ + 458140 Added DispatcherType support to RewriteHandler
+ + 458174 Example Jar Server
+ + 458175 multipart annotation on lazily loaded servlet does not work
+ + 458209 Length check for HttpMethod MOVE lookahead
+ + 458354 ALPNServerConnection.select negotiation.
+ + 458495 CompletableCallback may not notify failures.
+ + 458527 Implement an async proxy servlet that can perform content
+   transformations.
+ + 458568 JDBCLoginService javadoc incorrectly references HashLoginService
+ + 458663 Handle null header values
+ + 458849 org.eclipse.jetty.util.Uptime.DefaultImpl() not available on GAE
+ + 459006 master branch does not build on norwegian locale
+ + 459081 http2 push failures.
+ + 459125 GzipHandler default mimeType behavior incorrect
+ + 459273 Redundant license notices
+ + 459352 AsyncMiddleManServlet should set "Host:" header correctly in proxy to
+   remote request headers.
+ + 459490 Defining a duplicate error page in webdefault.xml and web.xml results
+   in an error
+ + 459542 AsyncMiddleManServlet race condition on first download content.
+ + 459560 jetty.sh handles start.d and no start.ini
+ + 459655 Remove SPDY and NPN
+ + 459681 Remove dead code after removal of glassfish jasper support
+ + 459731 Update for drafts hpack-11 and http2-17
+ + 459769 AsyncMiddleManServlet race condition on last download content.
+ + 459845 Support upgrade from http1 to http2/websocket
+ + 459963 Failure writing content of a committed request leaks connections.
+ + 460176 When checking for precompiled jsp, ensure classname is present
+ + 460180 Jaas demo has wrong doco in html
+ + 460210 ExecutionStragegy producer for SelectManager calls onOpen from
+   produce method
+ + 460211 Fixed Idle race in ExecuteProduceRun
+ + 460291 AsyncGzipFilter Mappings
+ + 460371 AsyncMiddleManServlet.GZipContentTransformer fails if last transform
+   has no output
+ + 460372 if web.xml does not contain jspc maven plugin insertionMarker
+   behavior is wrong
+ + 460443 Race condition releasing the response buffer.
+ + 460642 HttpParser error 400 can expose previous buffer contents in HTTP
+   status reason message
+ + 460670 Support multiple names in <Property> elements.
+ + 460769 ClientUpgradeRequest sends cookies in the wrong format
+ + 460905 Make sure TimeoutCompleteListener is cancelled if the request cannot
+   be sent.
+ + 461052 Local streams created after INITIAL_WINDOW_SIZE setting have wrong
+   send window.
+ + 461070 Handle setReadListener on request with no content
+ + 461133 allow stop port to reuse address
+ + 461350 Update HttpParser IllegalCharacter handling to RFC7230
+ + 461452 Double release of buffer by HttpReceiverOverHTTP
+ + 461499 ConnectionPool may leak connections.
+ + 461623 BufferUtil.writeTo does not update position consistently
+ + 461643 HttpContent.advance() race.
+
 jetty-9.2.10.v20150310 - 10 March 2015
  + 445518 Provide different error callbacks to ProxyServlet.
  + 456521 ShutdownHandler should shut down more gracefully
@@ -192,6 +805,82 @@
  + 450873 Disable tests that downcaste wrapped GzipFilterResponses
  + 450894 jetty.sh does not delete JETTY_STATE at start
 
+jetty-9.3.0.M1 - 03 November 2014
+ + 376365 "jetty.sh start" returns 0 on failure
+ + 396569 'bin/jetty.sh stop' reports 'OK' even when jetty was not running
+ + 396572 Starting jetty from cygwin is not working properly
+ + 437303 Serving of static filenames with "unwise" characters causes 404 error
+ + 440729 SSL requests often fail with EOFException or IllegalStateException.
+ + 440925 NPE when using relative paths for --start-log-file
+ + 442419 CrossOriginFilter javadoc says "exposeHeaders", but should be
+   "exposedHeaders"
+ + 442942 Content sent with status 204 (No Content)
+ + 443529 CrossOriginFilter does not accept wildcard for allowedHeaders
+ + 443530 CrossOriginFilter does not set the Vary header
+ + 443550 improved FileResource encoded alias checking
+ + 444031 Ensure exceptions do not reduce threadpool below minimum
+ + 444595 nosql/mongodb - Cleanup process/Refreshing does not respect encoding
+   of attribute keys
+ + 444676 Goal jetty:deploy-war produces errors with version 9.2.3
+ + 444722 Fixed order of setReuseAddress call
+ + 444896 Overriding of web-default servlet mapping in web.xml not working with
+   quickstart
+ + 445157 First redeployed servlet leaks WebAppContext
+ + 445167 Allow configuration of dispatch after select.
+ + 445239 Rename weld.mod to cdi.mod to be consistent with past module namings
+ + 445258 STOP.WAIT is not really respected
+ + 445374 Reevaluate org.eclipse.jetty.websocket.jsr356 enablement concepts
+ + 445495 Improve Exception message when no jndi resource to bind for a name in
+   web.xml
+ + 445542 Add SecuredRedirectHandler for embedded jetty use to redirect to
+   secure port/scheme
+ + 445821 Error 400 should be logged with RequestLog
+ + 445823 Moved RequestLog calling to HttpChannel
+ + 445830 Support setting environment variables on forked jetty with
+   jetty:run-forked
+ + 445979 jetty.sh fails to start when start-stop-daemon does not exist and the
+   user is not root
+ + 446033 org.eclipse.jetty.websocket.server.WebSocketServerFactory not
+   available in OSGi
+ + 446063 ALPN Fail SSL Handshake if no supported Application Protocols.
+ + 446107 NullPointerException in ProxyServlet when extended by Servlet without
+   a package
+ + 446425 Oracle Sql error on JettySessions table when this table do not exist
+   already
+ + 446506 getAsyncContext ISE before startAsync on async dispatches
+ + 446559 Avoid spin consuming extra data
+ + 446563 Null HttpChannel.getCurrentHttpChannel() in
+   ServletHandler.doFilter().
+ + 446564 Refactored RequestLog Mechanism
+ + 446672 NPN Specification issue in the case no protocols are selected.
+ + 446923 SharedBlockingCallback does not handle connector max idle time of
+   Long.MAX_VALUE; BlockerTimeoutException not serializable
+ + 446944 ServletTester and HttpTester should be in
+   <classifier>tests</classifier>
+ + 447216 putAll Properties in XmlConfiguration
+ + 447381 Disable SSLv3 by default.
+ + 447472 test harness for slow large writes
+ + 447515 Remove GzipFilter
+ + 447627 MultiPart file always created when "filename" set in
+   Content-Disposition
+ + 447629 getPart()/getParts() fails on Multipart request if getParameter is
+   called in a filter first
+ + 447746 HttpClient is always going to send User-Agent header even though I do
+   not want it to.
+ + 447979 Refactor to make MetaData responsible for progressively ordering
+   web-inf jars
+ + 448156 Fixed INACTIVE race in IteratingCallback
+ + 448225 Removed unnecessary synchronize on initParser
+ + 448675 Impossible to set own Threadpool when using jetty-maven-plugin
+ + 448841 Clarified selectors==0 javadoc 448840 Clarified ServerConnector
+   javadoc 448839 Fixed javadoc typo in ServerConnector
+ + 449001 Remove start.d directory from JETTY_HOME
+ + 449003 WARNING: Cannot enable requested module [protonego-impl]: not a valid
+   module name
+ + 449038 WebSocketUpgradeFilter must support async.
+ + 449175 Removed extra space in NCSA log
+ + 449372 Make jvmArgs of jetty:run-forked configurable from command line
+
 jetty-9.2.4.v20141103 - 03 November 2014
  + 376365 "jetty.sh start" returns 0 on failure
  + 396569 'bin/jetty.sh stop' reports 'OK' even when jetty was not running
@@ -228,6 +917,7 @@
  + 444896 Overriding of web-default servlet mapping in web.xml not working with
    quickstart
  + 445157 First redeployed servlet leaks WebAppContext
+ + 445167 Allow configuration of dispatch after select.
  + 445239 Rename weld.mod to cdi.mod to be consistent with past module namings
  + 445258 STOP.WAIT is not really respected
  + 445374 Reevaluate org.eclipse.jetty.websocket.jsr356 enablement concepts
@@ -249,13 +939,19 @@
  + 446425 Oracle Sql error on JettySessions table when this table do not exist
    already
  + 446506 getAsyncContext ISE before startAsync on async dispatches
+ + 446559 Avoid spin consuming extra data
  + 446563 Null HttpChannel.getCurrentHttpChannel() in
    ServletHandler.doFilter().
+ + 446564 Refactored RequestLog Mechanism
  + 446672 NPN Specification issue in the case no protocols are selected.
  + 446923 SharedBlockingCallback does not handle connector max idle time of
    Long.MAX_VALUE; BlockerTimeoutException not serializable
+ + 446944 ServletTester and HttpTester should be in
+   <classifier>tests</classifier>
+ + 447216 putAll Properties in XmlConfiguration
  + 447381 Disable SSLv3 by default.
  + 447472 test harness for slow large writes
+ + 447515 Remove GzipFilter
  + 447627 MultiPart file always created when "filename" set in
    Content-Disposition
  + 447629 getPart()/getParts() fails on Multipart request if getParameter is
@@ -266,6 +962,7 @@
    web-inf jars
  + 448156 Fixed INACTIVE race in IteratingCallback
  + 448225 Removed unnecessary synchronize on initParser
+ + 448675 Impossible to set own Threadpool when using jetty-maven-plugin
  + 448841 Clarified selectors==0 javadoc 448840 Clarified ServerConnector
    javadoc 448839 Fixed javadoc typo in ServerConnector
  + 449001 Remove start.d directory from JETTY_HOME
@@ -277,6 +974,42 @@
  + 449372 Make jvmArgs of jetty:run-forked configurable from command line
  + 449603 OutputStreamContentProvider hangs when host is not available.
 
+jetty-9.3.0.M0 - 24 September 2014
+ + 437395 Start / Properties in template sections should be default applied for
+   enabled modules
+ + 438204 getServerName returns IPv6 addresses wrapped in []
+ + 438387 NullPointerException after ServletUpgradeResponse.sendForbidden is
+   called during WebSocketCreator.createWebSocket
+ + 439369 Remove unused class CrossContextPsuedoSession
+ + 439375 preferred rfc7231 format is mime;charset=lowercase-9
+ + 442083 Client resets stream, pending server data is failed, connection
+   closed.
+ + 442086 Review HttpOutput blocking writes.
+ + 442477 Allow Symlink aliases by default
+ + 442495 Bad Context ClassLoader in JSR356 WebSocket onOpen
+ + 442950 Embedded Jetty client requests to localhost hangs with high cpu usage
+   (NIO OP_CONNECT Solaris/Sparc).
+ + 443652 Remove dependency on java.lang.management classes
+ + 443661 Rename manifest and service constants for jetty osgi resource
+   fragment code
+ + 443662 Consume buffer in write(ByteBuffer)
+ + 443713 Reduce number of SelectionKey.setInterestOps() calls.
+ + 443893 Make a module for weld
+ + 444124 JSP include with <servlet><jsp-file> can cause infinite recursion
+ + 444214 Socks4Proxy fails when reading less than 8 bytes.
+ + 444222 replace CRLF in header values with whitespace rather than ?
+ + 444415 iterative WriteFlusher
+ + 444416 AsyncProxyServlet recursion.
+ + 444485 Client resets stream, pending server data is failed, write hangs.
+ + 444517 Ensure WebSocketUpgradeFilter is always first in filter chain
+ + 444547 Format exception in ResourceCache.Content.toString()
+ + 444617 Expose local and remote socket address to applications
+ + 444748 WebSocketClient.stop() does not unregister from ShutdownThread
+ + 444764 HttpClient notifies callbacks for last chunk of content twice.
+ + 444771 JSR356 / EndPointConfig.userProperties are not unique per endpoint
+   upgrade
+ + 444863 ProxyServlet does not filter headers listed by the Connection header.
+
 jetty-9.2.3.v20140905 - 05 September 2014
  + 347110 renamed class transformer methods
  + 411163 Add embedded jetty code example with JSP enabled
@@ -1050,8 +1783,8 @@
  + 412940 minor threadsafe fixes
  + 413018 ServletContext.addListener() should throw IllegalArgumentException if
    arg is not correct type of listener
- + 413020 Second call to HttpSession.invalidate() should throw exception 413019
-   HttpSession.getCreateTime() should throw exception after session is
+ + 413020 Second call to HttpSession.invalidate() should throw exception
+ + 413019 HttpSession.getCreateTime() should throw exception after session is
    invalidated
  + 413291 Avoid SPDY double dispatch
  + 413387 onResponseHeaders is not called multiple times when multiple
diff --git a/aggregates/jetty-all-compact3/pom.xml b/aggregates/jetty-all-compact3/pom.xml
new file mode 100644
index 0000000..0a23810
--- /dev/null
+++ b/aggregates/jetty-all-compact3/pom.xml
@@ -0,0 +1,247 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty</groupId>
+    <artifactId>jetty-project</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty.aggregate</groupId>
+  <artifactId>jetty-all-compact3</artifactId>
+  <name>Jetty :: Aggregate :: All core Jetty suitable for Java 8 compact 3 profile</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.all.compact3</bundle-symbolic-name>
+  </properties>
+  <build>
+    <sourceDirectory>${project.build.directory}/sources</sourceDirectory>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>8</source>
+          <target>8</target>
+          <compilerArgs>
+            <arg>-profile</arg>
+            <arg>compact3</arg>
+          </compilerArgs>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack-dependencies</id>
+            <goals>
+              <goal>unpack-dependencies</goal>
+            </goals>
+            <configuration>
+              <excludes>**/MANIFEST.MF,javax/**</excludes>
+              <excludeArtifactIds>javax</excludeArtifactIds>
+              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm</excludeGroupIds>
+              <outputDirectory>${project.build.directory}/classes</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>true</overWriteSnapshots>
+            </configuration>
+          </execution>
+          <execution>
+            <id>unpack-source</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>unpack-dependencies</goal>
+            </goals>
+            <configuration>
+              <classifier>sources</classifier>
+              <includes>**/*</includes>
+              <excludes>
+                META-INF/**
+                **/Servlet3Continuation*
+                **/Jetty6Continuation*
+                **/AppContextLeakPreventer*.java
+                **/AWTLeakPreventer*.java
+                **/IntrospectorCleaner*.java
+                **/PostConstructAnnotationHandler*.java
+                **/PreDestroyAnnotationHandler*.java
+                **/ResourceAnnotationHandler*.java
+                **/ResourcesAnnotationHandler*.java
+              </excludes>
+              <includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.websocket</includeGroupIds>
+              <excludeArtifactIds>javax</excludeArtifactIds>
+              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.slf4j,org.ow2.asm</excludeGroupIds>
+              <outputDirectory>${project.build.directory}/sources</outputDirectory>
+              <overWriteReleases>true</overWriteReleases>
+              <overWriteSnapshots>true</overWriteSnapshots>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins
+        </groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>package</id>
+            <phase>package</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+            <configuration>
+              <archive>
+                <manifest>
+                </manifest>
+                <manifestEntries>
+                  <mode>development</mode>
+                  <url>http://eclipse.org/jetty</url>
+                  <Built-By>${user.name}</Built-By>
+                  <package>org.eclipse.jetty</package>
+                  <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License>
+                  <Bundle-Name>Jetty</Bundle-Name>
+                </manifestEntries>
+              </archive>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <additionalparam>-Xdoclint:none</additionalparam>
+        </configuration>
+        <executions>
+          <execution>
+            <id>javadoc-jar</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-pmd-plugin</artifactId>
+          <configuration>
+            <skip>true</skip>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-client</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-deploy</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>javax-websocket-server-impl</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-client</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-plus</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-jaspi</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-jndi</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-rewrite</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlets</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-quickstart</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- dependencies that jetty-all needs (some optional) -->
+    <dependency>
+      <groupId>javax.websocket</groupId>
+      <artifactId>javax.websocket-api</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.transaction</groupId>
+      <artifactId>javax.transaction-api</artifactId>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.orbit</groupId>
+      <artifactId>javax.mail.glassfish</artifactId>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/aggregates/jetty-all/pom.xml b/aggregates/jetty-all/pom.xml
index c3778ea..01c6a77 100644
--- a/aggregates/jetty-all/pom.xml
+++ b/aggregates/jetty-all/pom.xml
@@ -2,108 +2,124 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.eclipse.jetty.aggregate</groupId>
   <artifactId>jetty-all</artifactId>
   <name>Jetty :: Aggregate :: All core Jetty</name>
+  <description>UberJar for Core Jetty features</description>
+  <packaging>pom</packaging>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <uber-jar>${project.build.directory}/${project.artifactId}-${project.version}-uber.jar</uber-jar>
+    <gen-resources-dir>${project.build.directory}/gen-resources</gen-resources-dir>
+  </properties>
   <build>
-    <sourceDirectory>${project.build.directory}/sources</sourceDirectory>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-dependency-plugin</artifactId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.7</version>
         <executions>
           <execution>
-            <id>unpack-dependencies</id>
+            <id>massage-manifest</id>
+            <phase>generate-resources</phase>
             <goals>
-              <goal>unpack-dependencies</goal>
+              <goal>copy-resources</goal>
             </goals>
             <configuration>
-              <excludes>**/MANIFEST.MF,javax/**</excludes>
-              <excludeArtifactIds>javax</excludeArtifactIds>
-              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.mortbay.jetty.npn,org.slf4j,org.ow2.asm</excludeGroupIds>
-              <outputDirectory>${project.build.directory}/classes</outputDirectory>
-              <overWriteReleases>false</overWriteReleases>
-              <overWriteSnapshots>true</overWriteSnapshots>
-            </configuration>
-          </execution>
-          <execution>
-            <id>unpack-source</id>
-            <phase>generate-sources</phase>
-            <goals>
-              <goal>unpack-dependencies</goal>
-            </goals>
-            <configuration>
-              <classifier>sources</classifier>
-              <includes>**/*</includes>
-              <excludes>META-INF/**,**/Servlet3Continuation*,**/Jetty6Continuation*</excludes>
-              <includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.websocket</includeGroupIds>
-              <excludeArtifactIds>javax</excludeArtifactIds>
-              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.mortbay.jetty.npn,org.slf4j,org.ow2.asm</excludeGroupIds>
-              <outputDirectory>${project.build.directory}/sources</outputDirectory>
-              <overWriteReleases>true</overWriteReleases>
-              <overWriteSnapshots>true</overWriteSnapshots>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins
-        </groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>package</id>
-            <phase>package</phase>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-            <configuration>
-              <archive>
-                <manifest>
-                </manifest>
-                <manifestEntries>
-                  <mode>development</mode>
-                  <url>http://eclipse.org/jetty</url>
-                  <Built-By>${user.name}</Built-By>
-                  <package>org.eclipse.jetty</package>
-                  <Bundle-License>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/NOTICE.txt</Bundle-License>
-                  <Bundle-Name>Jetty</Bundle-Name>
-                </manifestEntries>
-              </archive>
+              <outputDirectory>${gen-resources-dir}</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>src/main/resources</directory>
+                  <filtering>true</filtering>
+                </resource>
+              </resources>
             </configuration>
           </execution>
         </executions>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-javadoc-plugin</artifactId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>2.3</version>
+        <dependencies>
+          <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-build-support</artifactId>
+            <version>1.3</version>
+          </dependency>
+        </dependencies>
         <executions>
           <execution>
-            <id>javadoc-jar</id>
-            <phase>compile</phase>
+            <id>uberjar</id>
+            <phase>package</phase>
             <goals>
-              <goal>jar</goal>
+              <goal>shade</goal>
             </goals>
+            <configuration>
+              <shadedArtifactAttached>true</shadedArtifactAttached>
+              <shadedClassifierName>uber</shadedClassifierName>
+              <outputFile>${uber-jar}</outputFile>
+              <transformers>
+                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+                <transformer implementation="org.eclipse.jetty.toolchain.shade.IncludeDirectoryTransformer">
+                  <directory>${gen-resources-dir}</directory>
+                </transformer>
+              </transformers>
+              <filters>
+                <filter>
+                  <artifact>*:*</artifact>
+                  <excludes>
+                    <exclude>META-INF/LICENSE.txt</exclude>
+                    <exclude>META-INF/*.MF</exclude>
+                    <exclude>META-INF/*.SF</exclude>
+                    <exclude>META-INF/*.DSA</exclude>
+                    <exclude>META-INF/*.RSA</exclude>
+                  </excludes>
+                </filter>
+              </filters>
+              <artifactSet>
+                <excludes>
+                  <exclude>javax:*</exclude>
+                  <exclude>org.eclipse.jetty.orbit:*</exclude>
+                  <exclude>org.mortbay.jetty:*</exclude>
+                  <exclude>org.mortbay.jetty.alpn:*</exclude>
+                  <exclude>org.slf4j:*</exclude>
+                  <exclude>org.ow2.asm:*</exclude>
+                  <exclude>*:javax</exclude>
+                </excludes>
+              </artifactSet>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.9.1</version>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <phase>package</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${uber-jar}</file>
+                  <type>jar</type>
+                  <classifier>uber</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
           </execution>
         </executions>
       </plugin>
     </plugins>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-pmd-plugin</artifactId>
-          <configuration>
-            <skip>true</skip>
-          </configuration>
-        </plugin>
-      </plugins>
-    </pluginManagement>
   </build>
 
   <dependencies>
@@ -111,120 +127,109 @@
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-client</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-deploy</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.websocket</groupId>
-      <artifactId>websocket-servlet</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.websocket</groupId>
-      <artifactId>javax-websocket-server-impl</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.websocket</groupId>
-      <artifactId>websocket-client</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
-      <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-jmx</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-plus</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-annotations</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-util</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-jaspi</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-jndi</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-rewrite</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-servlets</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-quickstart</artifactId>
       <version>${project.version}</version>
-      <scope>provided</scope>
+    </dependency>
+    <!-- websocket support -->
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-servlet</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>javax-websocket-server-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <!-- http/2 support -->
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-alpn-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-client</artifactId>
+      <version>${project.version}</version>
     </dependency>
     <!-- dependencies that jetty-all needs (some optional) -->
     <dependency>
       <groupId>javax.websocket</groupId>
       <artifactId>javax.websocket-api</artifactId>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>javax.transaction</groupId>
       <artifactId>javax.transaction-api</artifactId>
-      <scope>compile</scope>
-      <optional>true</optional>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty.orbit</groupId>
       <artifactId>javax.mail.glassfish</artifactId>
-      <scope>compile</scope>
-      <optional>true</optional>
     </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
-      <scope>compile</scope>
-      <optional>true</optional>
     </dependency>
   </dependencies>
 </project>
diff --git a/aggregates/jetty-all/src/main/resources/META-INF/MANIFEST.MF b/aggregates/jetty-all/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6ffd7d5
--- /dev/null
+++ b/aggregates/jetty-all/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0

+mode: development

+Implementation-Title: Jetty Uber All

+Implementation-Vendor: Eclipse Jetty Project

+Implementation-Vendor-Id: org.eclipse.jetty

+Implementation-Version: @project.version@

+X-License: https://www.eclipse.org/jetty/licenses.php

+

diff --git a/aggregates/jetty-all/src/main/resources/META-INF/javax.annotation-api-LICENSE.txt b/aggregates/jetty-all/src/main/resources/META-INF/javax.annotation-api-LICENSE.txt
new file mode 100644
index 0000000..a0ccc93
--- /dev/null
+++ b/aggregates/jetty-all/src/main/resources/META-INF/javax.annotation-api-LICENSE.txt
@@ -0,0 +1,263 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+   1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications.
+
+   1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor.
+
+   1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+   1.4. Executable. means the Covered Software in any form other than Source Code.
+
+   1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License.
+
+   1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License.
+
+   1.7. License. means this document.
+
+   1.8. Licensable. means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+   1.9. Modifications. means the Source Code and Executable form of any of the following:
+
+        A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original Software or previous Modification; or
+
+        C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+   1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License.
+
+   1.11. Patent Claims. means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.
+
+   1.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code.
+
+   1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, .You. includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, .control. means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+      2.1. The Initial Developer Grant.
+
+      Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+         (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+         (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+      3.1. Availability of Source Code.
+      Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange.
+
+      3.2. Modifications.
+      The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License.
+
+      3.3. Required Notices.
+      You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+      3.4. Application of Additional Terms.
+      You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
+
+      3.5. Distribution of Executable Versions.
+      You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
+
+      3.6. Larger Works.
+      You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+      4.1. New Versions.
+      Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License.
+
+      4.2. Effect of New Versions.
+      You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward.
+
+      4.3. Modified Versions.
+      When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+   COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN .AS IS. BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+      6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
+
+      6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant.
+
+      6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+   UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY.S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+   The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) and .commercial computer software documentation. as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS.
+
+   This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction.s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys. fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+   As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+   NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+
+   The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
+
+
+The GNU General Public License (GPL) Version 2, June 1991
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+   a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+   b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+   c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+   a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+   One line to give the program's name and a brief idea of what it does.
+
+   Copyright (C)
+
+   This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+   Gnomovision version 69, Copyright (C) year name of author
+   Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+   Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+   signature of Ty Coon, 1 April 1989
+   Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL VERSION 2
+
+Certain source files distributed by Sun Microsystems, Inc. are subject to the following clarification and special exception to the GPL Version 2, but only where Sun has expressly included in the particular source file's header the words
+
+"Sun designates this particular file as subject to the "Classpath" exception as provided by Sun in the License file that accompanied this code."
+
+Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License Version 2 cover the whole combination.
+
+As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module.? An independent module is a module which is not derived from or based on this library.? If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so.? If you do not wish to do so, delete this exception statement from your version.
diff --git a/aggregates/jetty-all/src/main/resources/META-INF/javax.servlet-api-LICENSE.txt b/aggregates/jetty-all/src/main/resources/META-INF/javax.servlet-api-LICENSE.txt
new file mode 100644
index 0000000..a0ccc93
--- /dev/null
+++ b/aggregates/jetty-all/src/main/resources/META-INF/javax.servlet-api-LICENSE.txt
@@ -0,0 +1,263 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+   1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications.
+
+   1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor.
+
+   1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+   1.4. Executable. means the Covered Software in any form other than Source Code.
+
+   1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License.
+
+   1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License.
+
+   1.7. License. means this document.
+
+   1.8. Licensable. means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+   1.9. Modifications. means the Source Code and Executable form of any of the following:
+
+        A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original Software or previous Modification; or
+
+        C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+   1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License.
+
+   1.11. Patent Claims. means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.
+
+   1.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code.
+
+   1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, .You. includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, .control. means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+      2.1. The Initial Developer Grant.
+
+      Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+         (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+         (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+      3.1. Availability of Source Code.
+      Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange.
+
+      3.2. Modifications.
+      The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License.
+
+      3.3. Required Notices.
+      You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+      3.4. Application of Additional Terms.
+      You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
+
+      3.5. Distribution of Executable Versions.
+      You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
+
+      3.6. Larger Works.
+      You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+      4.1. New Versions.
+      Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License.
+
+      4.2. Effect of New Versions.
+      You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward.
+
+      4.3. Modified Versions.
+      When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+   COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN .AS IS. BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+      6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
+
+      6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant.
+
+      6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+   UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY.S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+   The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) and .commercial computer software documentation. as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS.
+
+   This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction.s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys. fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+   As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+   NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+
+   The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
+
+
+The GNU General Public License (GPL) Version 2, June 1991
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+   a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+   b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+   c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+   a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+   One line to give the program's name and a brief idea of what it does.
+
+   Copyright (C)
+
+   This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+   Gnomovision version 69, Copyright (C) year name of author
+   Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+   Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+   signature of Ty Coon, 1 April 1989
+   Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL VERSION 2
+
+Certain source files distributed by Sun Microsystems, Inc. are subject to the following clarification and special exception to the GPL Version 2, but only where Sun has expressly included in the particular source file's header the words
+
+"Sun designates this particular file as subject to the "Classpath" exception as provided by Sun in the License file that accompanied this code."
+
+Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License Version 2 cover the whole combination.
+
+As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module.? An independent module is a module which is not derived from or based on this library.? If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so.? If you do not wish to do so, delete this exception statement from your version.
diff --git a/aggregates/jetty-all/src/main/resources/META-INF/javax.transaction-api-LICENSE.txt b/aggregates/jetty-all/src/main/resources/META-INF/javax.transaction-api-LICENSE.txt
new file mode 100644
index 0000000..a0ccc93
--- /dev/null
+++ b/aggregates/jetty-all/src/main/resources/META-INF/javax.transaction-api-LICENSE.txt
@@ -0,0 +1,263 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+   1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications.
+
+   1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor.
+
+   1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof.
+
+   1.4. Executable. means the Covered Software in any form other than Source Code.
+
+   1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License.
+
+   1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License.
+
+   1.7. License. means this document.
+
+   1.8. Licensable. means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+   1.9. Modifications. means the Source Code and Executable form of any of the following:
+
+        A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original Software or previous Modification; or
+
+        C. Any new file that is contributed or otherwise made available under the terms of this License.
+
+   1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License.
+
+   1.11. Patent Claims. means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.
+
+   1.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code.
+
+   1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, .You. includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, .control. means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. License Grants.
+
+      2.1. The Initial Developer Grant.
+
+      Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+         (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and
+
+         (b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+      3.1. Availability of Source Code.
+      Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange.
+
+      3.2. Modifications.
+      The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License.
+
+      3.3. Required Notices.
+      You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
+
+      3.4. Application of Additional Terms.
+      You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
+
+      3.5. Distribution of Executable Versions.
+      You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
+
+      3.6. Larger Works.
+      You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software.
+
+4. Versions of the License.
+
+      4.1. New Versions.
+      Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License.
+
+      4.2. Effect of New Versions.
+      You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward.
+
+      4.3. Modified Versions.
+      When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+   COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN .AS IS. BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+      6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
+
+      6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant.
+
+      6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+   UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY.S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+   The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. ? 252.227-7014(a)(1)) and .commercial computer software documentation. as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
+
+9. MISCELLANEOUS.
+
+   This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction.s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys. fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+   As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+   NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
+
+   The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
+
+
+The GNU General Public License (GPL) Version 2, June 1991
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+   a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+   b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+   c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+   a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+   c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+   One line to give the program's name and a brief idea of what it does.
+
+   Copyright (C)
+
+   This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+   Gnomovision version 69, Copyright (C) year name of author
+   Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+   Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+   signature of Ty Coon, 1 April 1989
+   Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL VERSION 2
+
+Certain source files distributed by Sun Microsystems, Inc. are subject to the following clarification and special exception to the GPL Version 2, but only where Sun has expressly included in the particular source file's header the words
+
+"Sun designates this particular file as subject to the "Classpath" exception as provided by Sun in the License file that accompanied this code."
+
+Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License Version 2 cover the whole combination.
+
+As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module.? An independent module is a module which is not derived from or based on this library.? If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so.? If you do not wish to do so, delete this exception statement from your version.
diff --git a/aggregates/jetty-websocket-all/pom.xml b/aggregates/jetty-websocket-all/pom.xml
index 26138ee..3c9c268 100644
--- a/aggregates/jetty-websocket-all/pom.xml
+++ b/aggregates/jetty-websocket-all/pom.xml
@@ -24,7 +24,7 @@
             </goals>
             <configuration>
               <excludes>**/MANIFEST.MF</excludes>
-              <excludeGroupIds>org.slf4j,org.eclipse.jetty.orbit,org.mortbay.jetty.npn</excludeGroupIds>
+              <excludeGroupIds>org.slf4j,org.eclipse.jetty.orbit,org.mortbay.jetty.alpn</excludeGroupIds>
               <outputDirectory>${project.build.directory}/classes</outputDirectory>
               <overWriteReleases>false</overWriteReleases>
               <overWriteSnapshots>true</overWriteSnapshots>
@@ -42,7 +42,7 @@
               <excludes>META-INF/**,**/Servlet3Continuation*,**/Jetty6Continuation*</excludes>
               <includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.websocket</includeGroupIds>
               <excludeArtifactIds>javax</excludeArtifactIds>
-              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.mortbay.jetty.npn</excludeGroupIds>
+              <excludeGroupIds>javax,org.eclipse.jetty.orbit,org.mortbay.jetty.alpn</excludeGroupIds>
               <outputDirectory>${project.build.directory}/sources</outputDirectory>
               <overWriteReleases>true</overWriteReleases>
               <overWriteSnapshots>true</overWriteSnapshots>
diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml
index 0070cd4..3bc74c2 100644
--- a/apache-jsp/pom.xml
+++ b/apache-jsp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>apache-jsp</artifactId>
@@ -18,12 +18,6 @@
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
         <extensions>true</extensions>
-        <executions>
-          <execution>
-            <id>generate-manifest</id>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
             <configuration>
               <instructions>
                 <Bundle-Description>Jetty-specific ServletContainerInitializer for Jasper</Bundle-Description>
@@ -35,8 +29,6 @@
                 <_nouses>true</_nouses>
               </instructions>
             </configuration>
-          </execution>
-        </executions>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
@@ -61,23 +53,6 @@
           </archive>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 
@@ -113,8 +88,8 @@
 
     <!-- Eclipse Java Compiler (for JSP Compilation) -->
     <dependency>
-      <groupId>org.eclipse.jetty.orbit</groupId>
-      <artifactId>org.eclipse.jdt.core</artifactId>
+      <groupId>org.eclipse.jdt.core.compiler</groupId>
+      <artifactId>ecj</artifactId>
     </dependency>
   </dependencies>
 </project>
diff --git a/apache-jsp/src/main/config/modules/apache-jsp.mod b/apache-jsp/src/main/config/modules/apache-jsp.mod
new file mode 100644
index 0000000..5123670
--- /dev/null
+++ b/apache-jsp/src/main/config/modules/apache-jsp.mod
@@ -0,0 +1,10 @@
+#
+# Apache JSP Module
+#
+
+[name]
+apache-jsp
+
+[lib]
+lib/apache-jsp/*.jar
+
diff --git a/apache-jsp/src/main/config/modules/jsp-impl/apache-jsp.mod b/apache-jsp/src/main/config/modules/jsp-impl/apache-jsp.mod
deleted file mode 100644
index aed547c..0000000
--- a/apache-jsp/src/main/config/modules/jsp-impl/apache-jsp.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Apache JSP Module
-#
-
-[name]
-jsp-impl
-
-[lib]
-lib/apache-jsp/*.jar
-
diff --git a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java
index 995d8e9..060db78 100644
--- a/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java
+++ b/apache-jsp/src/main/java/org/eclipse/jetty/apache/jsp/JettyJasperInitializer.java
@@ -35,7 +35,6 @@
 
 /**
  * JettyJasperInitializer
- *
  */
 public class JettyJasperInitializer extends JasperInitializer
 {
@@ -91,8 +90,6 @@
     /**
      * Make a TldScanner, and prefeed it the tlds that have already been discovered in jar files
      * by the MetaInfConfiguration.
-     * 
-     * @see org.apache.jasper.servlet.JasperInitializer#prepareScanner(javax.servlet.ServletContext, boolean, boolean, boolean)
      */
     @Override
     public TldScanner newTldScanner(ServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal)
diff --git a/apache-jstl/pom.xml b/apache-jstl/pom.xml
index 9b16c2f..89c935b 100644
--- a/apache-jstl/pom.xml
+++ b/apache-jstl/pom.xml
@@ -2,33 +2,27 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>apache-jstl</artifactId>
   <name>Apache :: JSTL module</name>
   <url>http://tomcat.apache.org/taglibs/standard/</url>
   <packaging>jar</packaging>
+  <properties>
+   <bundle-symbolic-name>${project.groupId}.apache.jstl</bundle-symbolic-name>
+  </properties>
 
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+             <useSystemClassLoader>false</useSystemClassLoader>
+          </configuration>
       </plugin>
+
     </plugins>
   </build>
 
@@ -44,6 +38,34 @@
        <groupId>org.apache.taglibs</groupId>
        <artifactId>taglibs-standard-impl</artifactId>
     </dependency>
+    
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+       <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+       <groupId>org.eclipse.jetty</groupId>
+       <artifactId>apache-jsp</artifactId>
+       <version>${project.version}</version>
+       <scope>test</scope>
+    </dependency>
+
+    <dependency>
+       <groupId>org.eclipse.jetty</groupId>
+       <artifactId>jetty-annotations</artifactId>
+       <version>${project.version}</version>
+       <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
 </project>
diff --git a/apache-jstl/src/main/config/modules/apache-jstl.mod b/apache-jstl/src/main/config/modules/apache-jstl.mod
new file mode 100644
index 0000000..e4a9001
--- /dev/null
+++ b/apache-jstl/src/main/config/modules/apache-jstl.mod
@@ -0,0 +1,9 @@
+#
+# Apache JSTL 
+#
+
+[name]
+apache-jstl
+
+[lib]
+lib/apache-jstl/*.jar
diff --git a/apache-jstl/src/main/config/modules/jsp-impl/apache-jstl.mod b/apache-jstl/src/main/config/modules/jsp-impl/apache-jstl.mod
deleted file mode 100644
index 804b191..0000000
--- a/apache-jstl/src/main/config/modules/jsp-impl/apache-jstl.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Apache JSTL 
-#
-[name]
-jstl-impl
-
-[lib]
-lib/apache-jstl/*.jar
diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java
new file mode 100644
index 0000000..0258f2c
--- /dev/null
+++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JspConfig.java
@@ -0,0 +1,40 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.jstl;
+
+import java.io.File;
+import java.net.URI;
+
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * Attempt at collecting up all of the JSP specific configuration bits and pieces into a single place
+ * for WebAppContext users to utilize.
+ */
+public class JspConfig
+{
+    public static void init(WebAppContext context, URI baseUri, File scratchDir)
+    {
+        context.setAttribute("javax.servlet.context.tempdir", scratchDir);
+        context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
+ ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar");
+        context.setWar(baseUri.toASCIIString());
+        context.setResourceBase(baseUri.toASCIIString());
+    }
+}
diff --git a/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java
new file mode 100644
index 0000000..f1c4dd3
--- /dev/null
+++ b/apache-jstl/src/test/java/org/eclipse/jetty/jstl/JstlTest.java
@@ -0,0 +1,134 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.jstl;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.servlet.jsp.JspException;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.JAR;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.eclipse.jetty.webapp.Configuration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class JstlTest
+{
+    private static Server server;
+    private static URI baseUri;
+    
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        // Setup Server
+        server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+        
+        // Setup WebAppContext
+        File testWebAppDir = MavenTestingUtils.getProjectDir("src/test/webapp");
+        
+        // Prepare WebApp libs
+        File libDir = new File(testWebAppDir, "WEB-INF/lib");
+        FS.ensureDirExists(libDir);
+        File testTagLibDir = MavenTestingUtils.getProjectDir("src/test/taglibjar");
+        JAR.create(testTagLibDir,new File(libDir, "testtaglib.jar"));
+        
+        // Configure WebAppContext
+ 
+        Configuration.ClassList classlist = Configuration.ClassList
+                .setServerDefault(server);
+
+        classlist.addBefore(
+                "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
+                "org.eclipse.jetty.annotations.AnnotationConfiguration");
+        
+        WebAppContext context = new WebAppContext();
+        context.setContextPath("/");
+        
+        File scratchDir = MavenTestingUtils.getTargetFile("tests/" + JstlTest.class.getSimpleName() + "-scratch");
+        FS.ensureEmpty(scratchDir);
+        JspConfig.init(context,testWebAppDir.toURI(),scratchDir);
+        
+        server.setHandler(context);
+        
+        // Start Server
+        server.start();
+        
+        // Figure out Base URI
+        String host = connector.getHost();
+        if (host == null)
+        {
+            host = "localhost";
+        }
+        int port = connector.getLocalPort();
+        baseUri = new URI(String.format("http://%s:%d/",host,port));
+    }
+    
+    @AfterClass
+    public static void stopServer() throws Exception
+    {
+        server.stop();
+    }
+    
+    @Test
+    public void testUrlsBasic() throws IOException
+    {
+        SimpleRequest req = new SimpleRequest(baseUri);
+        String resp = req.getString("/urls.jsp");
+        assertThat("Response should be JSP processed", resp, not(containsString("<c:url")));
+        assertThat("Response", resp, containsString("[c:url value] = /ref.jsp;jsessionid="));
+        assertThat("Response", resp, containsString("[c:url param] = ref.jsp;key=value;jsessionid="));
+    }
+    
+    @Test
+    public void testCatchBasic() throws IOException
+    {
+        SimpleRequest req = new SimpleRequest(baseUri);
+        String resp = req.getString("/catch-basic.jsp");
+        assertThat("Response should be JSP processed", resp, not(containsString("<c:catch")));
+        assertThat("Response", resp, containsString("[c:catch] exception : " + JspException.class.getName()));
+        assertThat("Response", resp, containsString("[c:catch] exception.message : In &lt;parseNumber&gt;"));
+    }
+    
+    @Test
+    @Ignore
+    public void testCatchTaglib() throws IOException
+    {
+        SimpleRequest req = new SimpleRequest(baseUri);
+        String resp = req.getString("/catch-taglib.jsp");
+        System.out.println("resp = " + resp);
+        assertThat("Response should be JSP processed", resp, not(containsString("<c:catch>")));
+        assertThat("Response should be JSP processed", resp, not(containsString("<jtest:errorhandler>")));
+        assertThat("Response", resp, not(containsString("[jtest:errorhandler] exception is null")));
+    }
+}
diff --git a/apache-jstl/src/test/taglibjar/META-INF/etag.tld b/apache-jstl/src/test/taglibjar/META-INF/etag.tld
new file mode 100644
index 0000000..de59ff0
--- /dev/null
+++ b/apache-jstl/src/test/taglibjar/META-INF/etag.tld
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
+  version="2.0">
+
+  <description>eclipse jetty test taglib</description>
+  <tlib-version>1.0</tlib-version>
+
+  <short-name>jtest</short-name>
+  <uri>org.eclipse.jetty.jstl.jtest</uri>
+
+  <tag-file>
+    <name>errorhandler</name>
+    <path>/META-INF/tags/errorhandler.tag</path>
+  </tag-file>
+</taglib>
\ No newline at end of file
diff --git a/apache-jstl/src/test/taglibjar/META-INF/tags/errorhandler.tag b/apache-jstl/src/test/taglibjar/META-INF/tags/errorhandler.tag
new file mode 100644
index 0000000..ddd44dd
--- /dev/null
+++ b/apache-jstl/src/test/taglibjar/META-INF/tags/errorhandler.tag
@@ -0,0 +1,12 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
+
+<c:catch var="tossable">
+  <jsp:doBody />
+</c:catch>
+<c:if test="${tossable != null}">
+[jtest:errorhandler] exception : ${tossable}
+[jtest:errorhandler] exception.message : ${tossable.message}
+</c:if>
+<c:if test="${tossable == null}">
+[jtest:errorhandler] exception is null
+</c:if>
diff --git a/apache-jstl/src/test/webapp/WEB-INF/web.xml b/apache-jstl/src/test/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..b05e490
--- /dev/null
+++ b/apache-jstl/src/test/webapp/WEB-INF/web.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+         version="3.1">
+  <description>Test webapp for JSTL</description>
+</web-app>
\ No newline at end of file
diff --git a/apache-jstl/src/test/webapp/catch-basic.jsp b/apache-jstl/src/test/webapp/catch-basic.jsp
new file mode 100644
index 0000000..06e2bcf
--- /dev/null
+++ b/apache-jstl/src/test/webapp/catch-basic.jsp
@@ -0,0 +1,16 @@
+<%@ page contentType="text/plain; charset=UTF-8" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
+Title: JSTL c:catch test
+
+<c:catch var ="catchException">
+  <fmt:parseNumber var="parsedNum" value="aaa" />
+</c:catch>
+
+<c:if test = "${catchException != null}">
+[c:catch] exception : ${catchException}
+[c:catch] exception.message : ${catchException.message}
+</c:if>
+<c:if test = "${catchException == null}">
+[c:catch] exception is null
+</c:if>
diff --git a/apache-jstl/src/test/webapp/catch-taglib.jsp b/apache-jstl/src/test/webapp/catch-taglib.jsp
new file mode 100644
index 0000000..28f7488
--- /dev/null
+++ b/apache-jstl/src/test/webapp/catch-taglib.jsp
@@ -0,0 +1,11 @@
+<%@ page contentType="text/plain; charset=UTF-8" %>
+<%@ taglib uri="org.eclipse.jetty.jstl.jtest" prefix="jtest" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
+Title: JSTL c:catch test
+
+<jtest:errorhandler>
+  <fmt:parseNumber var="parsedNum" value="aaa" />
+</jtest:errorhandler>
+
+parsedNum = <c:out value="${parsedNum}"/>
\ No newline at end of file
diff --git a/apache-jstl/src/test/webapp/ref.jsp b/apache-jstl/src/test/webapp/ref.jsp
new file mode 100644
index 0000000..0debf75
--- /dev/null
+++ b/apache-jstl/src/test/webapp/ref.jsp
@@ -0,0 +1,2 @@
+<%@ page contentType="text/plain; charset=UTF-8" %>
+Reference Page: No useful content here, just used for other tests
\ No newline at end of file
diff --git a/apache-jstl/src/test/webapp/urls.jsp b/apache-jstl/src/test/webapp/urls.jsp
new file mode 100644
index 0000000..bc18e9a
--- /dev/null
+++ b/apache-jstl/src/test/webapp/urls.jsp
@@ -0,0 +1,6 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
+<%@ page contentType="text/plain; charset=UTF-8" %>
+Title: JSTL c:url Tests
+[c:url value] = <c:url value="/ref.jsp" />
+<c:set var="foo" value="ref.jsp;key=value"/>
+[c:url param] = <c:url value="${foo}"><c:param name="noframe" value="true"/></c:url>
diff --git a/dists/jetty-deb/pom.xml b/dists/jetty-deb/pom.xml
deleted file mode 100644
index 9ce00e1..0000000
--- a/dists/jetty-deb/pom.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>org.eclipse.jetty.dist</groupId>
-    <artifactId>dist-parent</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
-  </parent>
-  <artifactId>jetty-deb</artifactId>
-  <name>Jetty :: Unix Distributions :: Debian</name>
-  <packaging>deb</packaging>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.mortbay.jetty.toolchain</groupId>
-        <artifactId>unix-maven-plugin</artifactId>
-        <version>1.0-alpha-6.1</version>
-        <extensions>true</extensions>
-        <configuration>
-          <contact>Jetty Project</contact>
-          <contactEmail>jetty-dev@eclipse.org</contactEmail>
-          <name>Core Jetty ${project.version} Distribution</name>
-          <description>Jetty provides an Web server and javax.servlet
-            container, plus support for Web Sockets, OSGi, JMX, JNDI,
-            JASPI, AJP and many other integrations. These components are
-            open source and available for commercial use and
-            distribution.</description>
-          <deb>
-            <useFakeroot>false</useFakeroot>
-            <priority>optional</priority>
-            <section>java</section>
-          </deb>
-           <packages>
-            <package>
-              <id>jetty-server</id>
-              <assembly>
-                <extractArtifact>
-                  <artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
-                  <to>/usr/share/jetty9</to>
-                  <pattern>/jetty-distribution-${project.version}(.*)</pattern>
-                  <replacement>$1</replacement>
-                  <excludes>
-                    <exclude>jetty-distribution-*/javadoc</exclude>
-                    <exclude>jetty-distribution-*/javadoc/**</exclude>
-                    <exclude>jetty-distribution-*/logs/**</exclude>
-                    <exclude>jetty-distribution-*/bin/**</exclude>
-                    <exclude>jetty-distribution-*/etc/**</exclude>
-                    <exclude>jetty-distribution-*/webapps/**</exclude>                  
-                    <exclude>jetty-distribution-*/*.html</exclude>
-                    <exclude>jetty-distribution-*/*.txt</exclude>             
-                  </excludes>
-                 </extractArtifact>
-                 <extractArtifact>
-                  <artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
-                  <to>/usr/share/doc/jetty9</to>
-                  <pattern>/jetty-distribution-${project.version}(.*)</pattern>
-                  <replacement>$1</replacement>
-                  <excludes>
-                    <include>jetty-distribution-*/*.html</include>
-                    <include>jetty-distribution-*/*.txt</include> 
-                    <exclude>jetty-distribution-*/**</exclude>           
-                  </excludes>
-                 </extractArtifact>
-                 <extractArtifact>
-                  <artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
-                  <to>/etc/jetty9</to>
-                  <pattern>/jetty-distribution-${project.version}(.*)</pattern>
-                  <replacement>$1</replacement>
-                  <excludes>
-                    <include>jetty-distribution-*/etc/**</include>
-                    <!-- exclude>jetty-distribution-*/**</exclude-->           
-                  </excludes>
-                 </extractArtifact>
-              </assembly>
-            </package>
-            <package>
-              <id>jetty-test-webapp</id>
-              <classifier>test-webapp</classifier>
-              <assembly>
-                <extractArtifact>
-                  <artifact>org.eclipse.jetty:jetty-distribution:zip</artifact>
-                  <to>/var/lib/jetty9/webapps</to>
-                  <pattern>/jetty-distribution-${project.version}(.*)</pattern>
-                  <replacement>$1</replacement>
-                  <includes>
-                    <include>jetty-distribution-*/webapps/**</include>
-                  </includes>
-                </extractArtifact>
-              </assembly>
-            </package>
-          </packages>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  <dependencies>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-    </dependency>
-  </dependencies>
-</project>
diff --git a/dists/jetty-deb/src/main/unix/scripts/postinst b/dists/jetty-deb/src/main/unix/scripts/postinst
deleted file mode 100644
index f6d7813..0000000
--- a/dists/jetty-deb/src/main/unix/scripts/postinst
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-LOG_DIR=/var/lib/jetty9/logs
-WEBAPP_DIR=/var/lib/jetty9/webapps
-
-# copy the jetty start script into place
-cp /usr/share/jetty9/bin/jetty.sh /etc/init.d/jetty
-
-# make it generally executable
-chmod 755 /etc/init.d/jetty
-
-# ensure we have a logging directory
-if [ ! -d "$LOG_DIR" ]; then
-  mkdir $LOG_DIR
-fi
-
-# ensure we have a webapps directory
-if [ ! -d "$WEBAPP_DIR" ]; then
-  mkdir $WEBAPP_DIR
-fi
diff --git a/dists/jetty-deb/src/main/unix/scripts/postrm b/dists/jetty-deb/src/main/unix/scripts/postrm
deleted file mode 100644
index 1f7f3e3..0000000
--- a/dists/jetty-deb/src/main/unix/scripts/postrm
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-
-#rm -f /etc/init.d/jetty
-
- case "$1" in
-  purge)
- [...]
-    # find first and last SYSTEM_UID numbers
-    for LINE in `grep SYSTEM_UID /etc/adduser.conf | grep -v "^#"`; do
-       case $LINE in
-          FIRST_SYSTEM_UID*)
-            FIST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
-            ;;
-          LAST_SYSTEM_UID*)
-            LAST_SYSTEM_UID=`echo $LINE | cut -f2 -d '='`
-            ;;
-          *)
-            ;;
-          esac
-    done
-    # Remove system account if necessary
-    CREATEDUSER="jetty"
-    if [ -n "$FIST_SYSTEM_UID" ] && [ -n "$LAST_SYSTEM_UID" ]; then
-     if USERID=`getent passwd $CREATEDUSER | cut -f 3 -d ':'`; then
-       if [ -n "$USERID" ]; then
-         if [ "$FIST_SYSTEM_UID" -le "$USERID" ] && \
-            [ "$USERID" -le "$LAST_SYSTEM_UID" ]; then
-               echo -n "Removing $CREATEDUSER system user.."
-               deluser --quiet $CREATEDUSER || true
-               echo "..done"
-         fi
-       fi
-     fi
-   fi
-   # Remove system group if necessary
-   CREATEDGROUP="jetty"
-   FIRST_USER_GID=`grep ^USERS_GID /etc/adduser.conf | cut -f2 -d '='`
-   if [ -n "$FIST_USER_GID" ] then
-     if GROUPGID=`getent group $CREATEDGROUP | cut -f 3 -d ':'`; then
-       if [ -n "$GROUPGID" ]; then
-         if [ "$FIST_USER_GID" -gt "$GROUPGID" ]; then
-           echo -n "Removing $CREATEDGROUP group.."
-           delgroup --only-if-empty $CREATEDGROUP || true
-           echo "..done"
-         fi
-       fi
-     fi
-   fi
\ No newline at end of file
diff --git a/dists/jetty-deb/src/main/unix/scripts/preinst b/dists/jetty-deb/src/main/unix/scripts/preinst
deleted file mode 100644
index 423b675..0000000
--- a/dists/jetty-deb/src/main/unix/scripts/preinst
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-
- case "$1" in
-   install|upgrade)
- 
-   # If the package has default file it could be sourced, so that
-   # the local admin can overwrite the defaults
- 
-   [ -f "/etc/default/jetty9" ] && . /etc/default/jetty9
- 
-   # Sane defaults:
- 
-   [ -z "$SERVER_HOME" ] && SERVER_HOME=/usr/share/jetty9
-   [ -z "$SERVER_USER" ] && SERVER_USER=jetty
-   [ -z "$SERVER_NAME" ] && SERVER_NAME="Jetty-9 Http and Servlet Engine"
-   [ -z "$SERVER_GROUP" ] && SERVER_GROUP=jetty
- 
-   # Groups that the user will be added to, if undefined, then none.
-   ADDGROUP=""
- 
-   # create user to avoid running server as root
-   # 1. create group if not existing
-   if ! getent group | grep -q "^$SERVER_GROUP:" ; then
-      echo -n "Adding group $SERVER_GROUP.."
-      addgroup --quiet --system $SERVER_GROUP 2>/dev/null ||true
-      echo "..done"
-   fi
-   # 2. create homedir if not existing
-   test -d $SERVER_HOME || mkdir $SERVER_HOME
-   # 3. create user if not existing
-   if ! getent passwd | grep -q "^$SERVER_USER:"; then
-     echo -n "Adding system user $SERVER_USER.."
-     adduser --quiet \
-             --system \
-             --ingroup $SERVER_GROUP \
-             --no-create-home \
-             --disabled-password \
-             $SERVER_USER 2>/dev/null || true
-     echo "..done"
-   fi
-   # 4. adjust passwd entry
-   usermod -c "$SERVER_NAME" \
-           -d $SERVER_HOME   \
-           -g $SERVER_GROUP  \
-              $SERVER_USER
-   # 5. adjust file and directory permissions
-   if ! dpkg-statoverride --list $SERVER_HOME >/dev/null
-   then
-       chown -R $SERVER_USER:$SERVER_GROUP $SERVER_HOME
-       chmod u=rwx,g=rxs,o= $SERVER_HOME
-   fi
-   # 6. Add the user to the ADDGROUP group
-   if test -n $ADDGROUP
-   then
-       if ! groups $SERVER_USER | cut -d: -f2 | \
-          grep -qw $ADDGROUP; then
-            adduser $SERVER_USER $ADDGROUP
-       fi
-   fi
-   ;;
-   configure)
\ No newline at end of file
diff --git a/dists/pom.xml b/dists/pom.xml
deleted file mode 100644
index c6ad38dc..0000000
--- a/dists/pom.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<parent>
-		<artifactId>jetty-project</artifactId>
-		<groupId>org.eclipse.jetty</groupId>
-		<version>9.0.0-SNAPSHOT</version>
-	</parent>
-	<modelVersion>4.0.0</modelVersion>
-	<groupId>org.eclipse.jetty.dist</groupId>
-	<artifactId>dist-parent</artifactId>
-	<packaging>pom</packaging>
-	<name>Jetty :: Distribution :: Parent</name>
-	<profiles>
-	  <profile>
-	    <id>linux-packaging</id>
-	    <!-- activation>
-	      <os>
-	        <name>Linux</name>
-	      </os>
-	    </activation-->
-	    <modules>
-	      <module>jetty-deb</module>
-	      <!--module>jetty-rpm</module-->
-	    </modules>
-	   </profile>
-	</profiles>
-</project>
diff --git a/examples/async-rest/async-rest-jar/pom.xml b/examples/async-rest/async-rest-jar/pom.xml
index 1d29910..ad1a25c 100644
--- a/examples/async-rest/async-rest-jar/pom.xml
+++ b/examples/async-rest/async-rest-jar/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>example-async-rest</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+       <version>9.3.7-SNAPSHOT</version>
   </parent>  
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.eclipse.jetty.example-async-rest</groupId>
@@ -10,6 +10,9 @@
   <packaging>jar</packaging>
   <name>Example Async Rest :: Jar</name>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.examples.asyc.rest</bundle-symbolic-name>
+  </properties>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
diff --git a/examples/async-rest/async-rest-webapp/pom.xml b/examples/async-rest/async-rest-webapp/pom.xml
index 4fb2e43..5e0769e 100644
--- a/examples/async-rest/async-rest-webapp/pom.xml
+++ b/examples/async-rest/async-rest-webapp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>example-async-rest</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>  
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.eclipse.jetty.example-async-rest</groupId>
diff --git a/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 9376677..c15dc38 100644
--- a/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/examples/async-rest/async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!--
 This is the jetty specific web application configuration file.  When starting
diff --git a/examples/async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java b/examples/async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java
index 24cb263..0fb1943 100644
--- a/examples/async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java
+++ b/examples/async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java
@@ -28,7 +28,7 @@
     {
         String jetty_home = System.getProperty("jetty.home",".");
 
-        Server server = new Server(Integer.getInteger("jetty.port",8080).intValue());
+        Server server = new Server(Integer.getInteger("jetty.http.port",8080).intValue());
                 
         WebAppContext webapp = new WebAppContext();
         webapp.setContextPath("/");
diff --git a/examples/async-rest/pom.xml b/examples/async-rest/pom.xml
index 46aaac6..26b1411 100644
--- a/examples/async-rest/pom.xml
+++ b/examples/async-rest/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.examples</groupId>
     <artifactId>examples-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>  
   <modelVersion>4.0.0</modelVersion>
diff --git a/examples/embedded/pom.xml b/examples/embedded/pom.xml
index c41d535..1cf8069 100644
--- a/examples/embedded/pom.xml
+++ b/examples/embedded/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.examples</groupId>
     <artifactId>examples-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -11,6 +11,9 @@
   <name>Example :: Jetty Embedded</name>
   <description>Jetty Embedded Examples</description>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.embedded</bundle-symbolic-name>
+  </properties>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
@@ -53,8 +56,18 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.alpn</groupId>
+      <artifactId>alpn-api</artifactId>
+      <version>${alpn.api.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-alpn-server</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -105,5 +118,12 @@
       <artifactId>jetty-test-helper</artifactId>
       <!-- scope>test</scope-->
     </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-http</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/examples/embedded/src/main/java/HelloWorld.java b/examples/embedded/src/main/java/HelloWorld.java
deleted file mode 100644
index 15bf5e0..0000000
--- a/examples/embedded/src/main/java/HelloWorld.java
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
-public class HelloWorld extends AbstractHandler
-{
-    @Override
-    public void handle( String target,
-                        Request baseRequest,
-                        HttpServletRequest request,
-                        HttpServletResponse response ) throws IOException,
-                                                      ServletException
-    {
-        // Declare response encoding and types
-        response.setContentType("text/html; charset=utf-8");
-
-        // Declare response status code
-        response.setStatus(HttpServletResponse.SC_OK);
-
-        // Write back response
-        response.getWriter().println("<h1>Hello World</h1>");
-
-        // Inform jetty that this request has now been handled
-        baseRequest.setHandled(true);
-    }
-
-    public static void main( String[] args ) throws Exception
-    {
-        Server server = new Server(8080);
-        server.setHandler(new HelloWorld());
-
-        server.start();
-        server.join();
-    }
-}
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java
index 8bdc440..e996dc4 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/AsyncEchoServlet.java
@@ -34,6 +34,8 @@
 
 public class AsyncEchoServlet extends HttpServlet
 {
+    private static final long serialVersionUID = 1L;
+
     @Override
     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
     {
@@ -62,18 +64,23 @@
         @Override
         public void onDataAvailable() throws IOException
         {
-            onWritePossible();
+            handleAsyncIO();
         }
 
         @Override
         public void onAllDataRead() throws IOException
         {
-            onWritePossible();
+            handleAsyncIO();
         }
 
         @Override
         public void onWritePossible() throws IOException
         {
+            handleAsyncIO();
+        }
+        
+        private void handleAsyncIO() throws IOException
+        {
             // This method is called:
             //   1) after first registering a WriteListener (ready for first write)
             //   2) after first registering a ReadListener iff write is ready
@@ -81,8 +88,17 @@
             //   4) from an input callback 
            
             // We should try to read, only if we are able to write!
-            while (output.isReady() && input.isReady())
+            while (true)
             {
+                if (!output.isReady())
+                    // Don't even try to read anything until it is possible to write something,
+                    // when onWritePossible will be called
+                    break;
+
+                if (!input.isReady())
+                    // Nothing available to read, so wait for another call to onDataAvailable
+                    break;
+                
                 int read = input.read(buffer);
                 if (read<0)
                 {
@@ -100,7 +116,7 @@
         @Override
         public void onError(Throwable failure)
         {
-            failure.printStackTrace();
+            new Throwable("onError",failure).printStackTrace();
             asyncContext.complete();
         }
     }
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java
index db2fb09..a127b05 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java
@@ -39,6 +39,8 @@
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.DefaultHandler;
 import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.server.handler.ResourceHandler;
+import org.eclipse.jetty.servlet.DefaultServlet;
 import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.resource.Resource;
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java
index 84f54ce..2da99b2 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java
@@ -23,6 +23,7 @@
 import org.eclipse.jetty.server.handler.DefaultHandler;
 import org.eclipse.jetty.server.handler.HandlerList;
 import org.eclipse.jetty.server.handler.ResourceHandler;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
 
 /** 
  * Simple Jetty FileServer.
@@ -47,9 +48,11 @@
         resource_handler.setResourceBase(".");
 
         // Add the ResourceHandler to the server.
+        GzipHandler gzip = new GzipHandler();
+        server.setHandler(gzip);
         HandlerList handlers = new HandlerList();
         handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
-        server.setHandler(handlers);
+        gzip.setHandler(handlers);
 
         // Start things up! By using the server.join() the server thread will join with the current thread.
         // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java
new file mode 100644
index 0000000..09b2d67
--- /dev/null
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/HelloWorld.java
@@ -0,0 +1,61 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.embedded;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+public class HelloWorld extends AbstractHandler
+{
+    @Override
+    public void handle( String target,
+                        Request baseRequest,
+                        HttpServletRequest request,
+                        HttpServletResponse response ) throws IOException,
+                                                      ServletException
+    {
+        // Declare response encoding and types
+        response.setContentType("text/html; charset=utf-8");
+
+        // Declare response status code
+        response.setStatus(HttpServletResponse.SC_OK);
+
+        // Write back response
+        response.getWriter().println("<h1>Hello World</h1>");
+
+        // Inform jetty that this request has now been handled
+        baseRequest.setHandled(true);
+    }
+
+    public static void main( String[] args ) throws Exception
+    {
+        Server server = new Server(8080);
+        server.setHandler(new HelloWorld());
+
+        server.start();
+        server.join();
+    }
+}
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java
new file mode 100644
index 0000000..28f8547
--- /dev/null
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/Http2Server.java
@@ -0,0 +1,189 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.embedded;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Date;
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.alpn.ALPN;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.jmx.MBeanContainer;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlets.PushCacheFilter;
+import org.eclipse.jetty.servlets.PushSessionCacheFilter;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class Http2Server
+{
+    public static void main(String... args) throws Exception
+    {
+        Server server = new Server();
+
+        MBeanContainer mbContainer = new MBeanContainer(
+                ManagementFactory.getPlatformMBeanServer());
+        server.addBean(mbContainer);
+
+        ServletContextHandler context = new ServletContextHandler(server, "/",ServletContextHandler.SESSIONS);
+        context.setResourceBase("src/main/resources/docroot");
+        context.addFilter(PushCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
+        // context.addFilter(PushSessionCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
+        context.addFilter(PushedTilesFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
+        context.addServlet(new ServletHolder(servlet), "/test/*");
+        context.addServlet(DefaultServlet.class, "/").setInitParameter("maxCacheSize","81920");
+        server.setHandler(context);
+
+        // HTTP Configuration
+        HttpConfiguration http_config = new HttpConfiguration();
+        http_config.setSecureScheme("https");
+        http_config.setSecurePort(8443);
+        http_config.setSendXPoweredBy(true);
+        http_config.setSendServerVersion(true);
+
+        // HTTP Connector
+        ServerConnector http = new ServerConnector(server,new HttpConnectionFactory(http_config), new HTTP2CServerConnectionFactory(http_config));
+        http.setPort(8080);
+        server.addConnector(http);
+
+        // SSL Context Factory for HTTPS and HTTP/2
+        String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution");
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath(jetty_distro + "/demo-base/etc/keystore");
+        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
+        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
+        sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
+
+        // HTTPS Configuration
+        HttpConfiguration https_config = new HttpConfiguration(http_config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
+
+        // HTTP/2 Connection Factory
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
+
+        NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(http.getDefaultProtocol());
+
+        // SSL Connection Factory
+        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol());
+
+        // HTTP/2 Connector
+        ServerConnector http2Connector =
+            new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config));
+        http2Connector.setPort(8443);
+        server.addConnector(http2Connector);
+
+        ALPN.debug=false;
+
+        server.start();
+        //server.dumpStdErr();
+        server.join();
+    }
+
+    public static class PushedTilesFilter implements Filter
+    {
+        @Override
+        public void init(FilterConfig filterConfig) throws ServletException
+        {
+        }
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+        {
+            Request baseRequest = Request.getBaseRequest(request);
+
+            if (baseRequest.isPush() && baseRequest.getRequestURI().contains("tiles") )
+            {
+                String uri = baseRequest.getRequestURI().replace("tiles","pushed").substring(baseRequest.getContextPath().length());
+                request.getRequestDispatcher(uri).forward(request,response);
+                return;
+            }
+
+            chain.doFilter(request,response);
+        }
+
+        @Override
+        public void destroy()
+        {
+        }
+    };
+
+    static Servlet servlet = new HttpServlet()
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            String code=request.getParameter("code");
+            if (code!=null)
+                response.setStatus(Integer.parseInt(code));
+
+            HttpSession session = request.getSession(true);
+            if (session.isNew())
+                response.addCookie(new Cookie("bigcookie",
+                "This is a test cookies that was created on "+new Date()+" and is used by the jetty http/2 test servlet."));
+            response.setHeader("Custom","Value");
+            response.setContentType("text/plain");
+            String content = "Hello from Jetty using "+request.getProtocol() +"\n";
+            content+="uri="+request.getRequestURI()+"\n";
+            content+="session="+session.getId()+(session.isNew()?"(New)\n":"\n");
+            content+="date="+new Date()+"\n";
+            
+            for (Cookie c : request.getCookies())
+                content+="cookie "+c.getName()+"="+c.getValue()+"\n";
+            
+            response.setContentLength(content.length());
+            response.getOutputStream().print(content);
+        }
+    };
+}
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
index a4c6315..f96cb5f 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java
@@ -24,9 +24,12 @@
 
 import org.eclipse.jetty.deploy.DeploymentManager;
 import org.eclipse.jetty.deploy.PropertiesConfigurationManager;
+import org.eclipse.jetty.deploy.bindings.DebugListenerBinding;
 import org.eclipse.jetty.deploy.providers.WebAppProvider;
+import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.security.HashLoginService;
+import org.eclipse.jetty.server.DebugListener;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -128,10 +131,10 @@
         // === jetty-https.xml ===
         // SSL Context Factory
         SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore");
+        sslContextFactory.setKeyStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore");
         sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
         sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
-        sslContextFactory.setTrustStorePath(jetty_home + "/etc/keystore");
+        sslContextFactory.setTrustStorePath(jetty_home + "/../../../jetty-server/src/test/config/etc/keystore");
         sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
         sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA",
                 "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA",
@@ -146,7 +149,7 @@
 
         // SSL Connector
         ServerConnector sslConnector = new ServerConnector(server,
-            new SslConnectionFactory(sslContextFactory,"http/1.1"),
+            new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
             new HttpConnectionFactory(https_config));
         sslConnector.setPort(8443);
         server.addConnector(sslConnector);
@@ -154,6 +157,9 @@
 
         // === jetty-deploy.xml ===
         DeploymentManager deployer = new DeploymentManager();
+        DebugListener debug = new DebugListener(System.out,true,true,true);
+        server.addBean(debug);        
+        deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
         deployer.setContexts(contexts);
         deployer.setContextAttribute(
                 "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
@@ -210,9 +216,8 @@
         HashLoginService login = new HashLoginService();
         login.setName("Test Realm");
         login.setConfig(jetty_base + "/etc/realm.properties");
-        login.setRefreshInterval(0);
+        login.setHotReload(false);
         server.addBean(login);
-
         
         // Start the server
         server.start();
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
index 16d7756..0694ea6 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 
+import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -42,7 +43,7 @@
         // to get access to a keystore that we use in many unit tests and should
         // probably be a direct path to your own keystore.
 
-        String jettyDistKeystore = "../../jetty-distribution/target/distribution/etc/keystore";
+        String jettyDistKeystore = "../../jetty-distribution/target/distribution/demo-base/etc/keystore";
         String keystorePath = System.getProperty(
                 "example.keystore", jettyDistKeystore);
         File keystoreFile = new File(keystorePath);
@@ -77,7 +78,7 @@
         http.setPort(8080);
         http.setIdleTimeout(30000);
 
-        // SSL Context Factory for HTTPS and SPDY
+        // SSL Context Factory for HTTPS
         // SSL requires a certificate so we configure a factory for ssl contents
         // with information pointing to what keystore the ssl connection needs
         // to know about. Much more configuration is available the ssl context,
@@ -96,14 +97,17 @@
         // resolve the https connection before handing control over to the Jetty
         // Server.
         HttpConfiguration https_config = new HttpConfiguration(http_config);
-        https_config.addCustomizer(new SecureRequestCustomizer());
+        SecureRequestCustomizer src = new SecureRequestCustomizer();
+        src.setStsMaxAge(2000);
+        src.setStsIncludeSubDomains(true);
+        https_config.addCustomizer(src);
 
         // HTTPS connector
         // We create a second ServerConnector, passing in the http configuration
         // we just made along with the previously created ssl context factory.
         // Next we set the port and a longer idle timeout.
         ServerConnector https = new ServerConnector(server,
-                new SslConnectionFactory(sslContextFactory, "http/1.1"),
+            new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
                 new HttpConnectionFactory(https_config));
         https.setPort(8443);
         https.setIdleTimeout(500000);
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java
index 1fe814e..7e9e28a 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyHandlers.java
@@ -36,6 +36,7 @@
 import org.eclipse.jetty.server.handler.HandlerList;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
 import org.eclipse.jetty.util.ajax.JSON;
 
 /**
@@ -127,7 +128,7 @@
 
         // link them all together
         wrapper.setHandler(hello);
-        list.setHandlers(new Handler[] { param, wrapper, dft });
+        list.setHandlers(new Handler[] { param, new GzipHandler(), dft });
         handlers.setHandlers(new Handler[] { list, requestLog });
 
         // Handler tree looks like the following
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
index fac6e52..f20c621 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneWebApp.java
@@ -24,6 +24,7 @@
 import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.security.HashLoginService;
 import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
 import org.eclipse.jetty.webapp.WebAppContext;
 
 public class OneWebApp
@@ -51,26 +52,14 @@
         WebAppContext webapp = new WebAppContext();
         webapp.setContextPath("/");
         File warFile = new File(
-                "../../jetty-distribution/target/distribution/demo-base/webapps/test.war");
+                "../../jetty-distribution/target/distribution/test/webapps/test/");
         webapp.setWar(warFile.getAbsolutePath());
+        webapp.addAliasCheck(new AllowSymLinkAliasChecker());
 
         // A WebAppContext is a ContextHandler as well so it needs to be set to
         // the server so it is aware of where to send the appropriate requests.
         server.setHandler(webapp);
 
-        // Configure a LoginService
-        // Since this example is for our test webapp, we need to setup a
-        // LoginService so this shows how to create a very simple hashmap based
-        // one. The name of the LoginService needs to correspond to what is
-        // configured in the webapp's web.xml and since it has a lifecycle of
-        // its own we register it as a bean with the Jetty server object so it
-        // can be started and stopped according to the lifecycle of the server
-        // itself.
-        HashLoginService loginService = new HashLoginService();
-        loginService.setName("Test Realm");
-        loginService.setConfig("src/test/resources/realm.properties");
-        server.addBean(loginService);
-
         // Start things up! 
         server.start();
 
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java
deleted file mode 100644
index cb8f727..0000000
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.embedded;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-/**
- * A Jetty server with HTTP and SPDY connectors.
- */
-public class SpdyConnector
-{
-    public static void main(String[] args) throws Exception
-    {
-        // Path to as-built jetty-distribution directory
-        String jettyHomeBuild = "../../jetty-distribution/target/distribution";
-        
-        // Find jetty home directories
-        String homePath = System.getProperty("jetty.home", jettyHomeBuild);
-        File homeDir = new File(homePath);
-        if (!homeDir.exists())
-        {
-            throw new FileNotFoundException(homeDir.getAbsolutePath());
-        }
-        String jetty_home = homeDir.getAbsolutePath();
-        System.setProperty("jetty.home", jetty_home);
-
-        // The Server
-        Server server = new Server();
-
-        // HTTP Configuration
-        HttpConfiguration http_config = new HttpConfiguration();
-        http_config.setSecureScheme("https");
-        http_config.setSecurePort(8443);
-
-        // HTTP connector
-        ServerConnector http = new ServerConnector(server,
-                new HttpConnectionFactory(http_config));        
-        http.setPort(8080);
-        server.addConnector(http);
- 
-        // SSL Context Factory for HTTPS and SPDY
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore");
-        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
-        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
-
-        // HTTPS Configuration
-        HttpConfiguration https_config = new HttpConfiguration(http_config);
-        https_config.addCustomizer(new SecureRequestCustomizer());
-        
-        // SPDY versions
-        HTTPSPDYServerConnectionFactory spdy2 = 
-                new HTTPSPDYServerConnectionFactory(2, https_config);
-
-        HTTPSPDYServerConnectionFactory spdy3 = 
-                new HTTPSPDYServerConnectionFactory(3, https_config, 
-                        new ReferrerPushStrategy());
-
-        // NPN Factory
-        SPDYServerConnectionFactory.checkProtocolNegotiationAvailable();
-        NPNServerConnectionFactory npn = new NPNServerConnectionFactory(
-                spdy3.getProtocol(), 
-                spdy2.getProtocol(),
-                http.getDefaultProtocol());
-        npn.setDefaultProtocol(http.getDefaultProtocol());
-
-        // SSL Factory
-        SslConnectionFactory ssl = new SslConnectionFactory(
-                sslContextFactory, npn.getProtocol());
-
-        // SPDY Connector
-        ServerConnector spdyConnector = new ServerConnector(server, ssl, 
-                npn, spdy3, spdy2, 
-                new HttpConnectionFactory(https_config));
-        spdyConnector.setPort(8443);
-        server.addConnector(spdyConnector);
-        
-        // Set a handler
-        server.setHandler(new HelloHandler());
-
-        // Start the server
-        server.start();
-        server.join();
-    }
-}
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java
deleted file mode 100644
index 5e86359..0000000
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java
+++ /dev/null
@@ -1,210 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.embedded;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.lang.management.ManagementFactory;
-
-import org.eclipse.jetty.deploy.DeploymentManager;
-import org.eclipse.jetty.deploy.providers.WebAppProvider;
-import org.eclipse.jetty.jmx.MBeanContainer;
-import org.eclipse.jetty.security.HashLoginService;
-import org.eclipse.jetty.server.AsyncNCSARequestLog;
-import org.eclipse.jetty.server.ForwardedRequestCustomizer;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.NCSARequestLog;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.server.handler.DefaultHandler;
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.server.handler.RequestLogHandler;
-import org.eclipse.jetty.server.handler.StatisticsHandler;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.PushStrategy;
-import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-
-public class SpdyServer
-{
-    public static void main( String[] args ) throws Exception
-    {
-        // Path to as-built jetty-distribution directory
-        String jettyHomeBuild = "../../jetty-distribution/target/distribution";
-
-        // Find jetty home directories
-        String homePath = System.getProperty("jetty.home", jettyHomeBuild);
-        File homeDir = new File(homePath);
-        if (!homeDir.exists())
-        {
-            throw new FileNotFoundException(homeDir.getAbsolutePath());
-        }
-        String jetty_home = homeDir.getAbsolutePath();
-        System.setProperty("jetty.home", jetty_home);
-
-        // Setup Threadpool
-        QueuedThreadPool threadPool = new QueuedThreadPool(512);
-
-        // Setup Jetty Server instance
-        Server server = new Server(threadPool);
-        server.manage(threadPool);
-        server.setDumpAfterStart(false);
-        server.setDumpBeforeStop(false);
-
-        // Setup JMX
-        MBeanContainer mbContainer = new MBeanContainer(
-                ManagementFactory.getPlatformMBeanServer());
-        server.addBean(mbContainer);
-
-        // Common HTTP configuration
-        HttpConfiguration config = new HttpConfiguration();
-        config.setSecurePort(8443);
-        config.addCustomizer(new ForwardedRequestCustomizer());
-        config.addCustomizer(new SecureRequestCustomizer());
-        config.setSendServerVersion(true);
-
-        // Http Connector Setup
-
-        // A plain HTTP connector listening on port 8080. Note that it's also
-        // possible to have port 8080 configured as a non SSL SPDY connector.
-        // But the specification and most browsers do not allow to use SPDY
-        // without SSL encryption. However some browsers allow it to be
-        // configured.
-        HttpConnectionFactory http = new HttpConnectionFactory(config);
-        ServerConnector httpConnector = new ServerConnector(server, http);
-        httpConnector.setPort(8080);
-        httpConnector.setIdleTimeout(10000);
-        server.addConnector(httpConnector);
-
-        // SSL configurations
-
-        // We need a SSLContextFactory for the SSL encryption. That
-        // SSLContextFactory will be used by the SPDY
-        // connector.
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath(jetty_home + "/etc/keystore");
-        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
-        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
-        sslContextFactory.setTrustStorePath(jetty_home + "/etc/keystore");
-        sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
-        sslContextFactory.setExcludeCipherSuites(
-                "SSL_RSA_WITH_DES_CBC_SHA",
-                "SSL_DHE_RSA_WITH_DES_CBC_SHA", 
-                "SSL_DHE_DSS_WITH_DES_CBC_SHA",
-                "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
-                "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
-
-        // Spdy Connector
-
-        // Make sure that the required NPN implementations are available.
-        SPDYServerConnectionFactory.checkProtocolNegotiationAvailable();
-
-        // A ReferrerPushStrategy is being initialized.
-        // See:
-        // http://www.eclipse.org/jetty/documentation/current/spdy-configuring-push.html
-        // for more details.
-        PushStrategy push = new ReferrerPushStrategy();
-        HTTPSPDYServerConnectionFactory spdy2 = 
-                new HTTPSPDYServerConnectionFactory(2, config, push);
-        spdy2.setInputBufferSize(8192);
-        spdy2.setInitialWindowSize(32768);
-
-        // We need a connection factory per protocol that our server is supposed
-        // to support on the NPN port. We then
-        // create a ServerConnector and pass in the supported factories. NPN
-        // will then be used to negotiate the
-        // protocol with the client.
-        HTTPSPDYServerConnectionFactory spdy3 = 
-                new HTTPSPDYServerConnectionFactory(3, config, push);
-        spdy3.setInputBufferSize(8192);
-
-        NPNServerConnectionFactory npn = new NPNServerConnectionFactory(
-                spdy3.getProtocol(), spdy2.getProtocol(), http.getProtocol());
-        npn.setDefaultProtocol(http.getProtocol());
-        npn.setInputBufferSize(1024);
-
-        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,
-                npn.getProtocol());
-
-        // Setup the npn connector on port 8443
-        ServerConnector spdyConnector = new ServerConnector(server, ssl, 
-                npn, spdy3, spdy2, http);
-        spdyConnector.setPort(8443);
-
-        server.addConnector(spdyConnector);
-
-        // The following section adds some handlers, deployers and webapp
-        // providers. See
-        // http://www.eclipse.org/jetty/documentation/current/advanced-embedding.html
-        // for details.
-
-        // Setup handlers
-        HandlerCollection handlers = new HandlerCollection();
-        ContextHandlerCollection contexts = new ContextHandlerCollection();
-        RequestLogHandler requestLogHandler = new RequestLogHandler();
-
-        handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(),
-                requestLogHandler });
-
-        StatisticsHandler stats = new StatisticsHandler();
-        stats.setHandler(handlers);
-
-        server.setHandler(stats);
-
-        // Setup deployers
-        DeploymentManager deployer = new DeploymentManager();
-        deployer.setContexts(contexts);
-        server.addBean(deployer);
-
-        WebAppProvider webapp_provider = new WebAppProvider();
-        webapp_provider.setMonitoredDirName(jetty_home + "/webapps");
-        webapp_provider.setParentLoaderPriority(false);
-        webapp_provider.setExtractWars(true);
-        webapp_provider.setScanInterval(2);
-        webapp_provider.setDefaultsDescriptor(jetty_home
-                + "/etc/webdefault.xml");
-        deployer.addAppProvider(webapp_provider);
-
-        HashLoginService login = new HashLoginService();
-        login.setName("Test Realm");
-        login.setConfig(jetty_home + "/etc/realm.properties");
-        server.addBean(login);
-
-        NCSARequestLog requestLog = new AsyncNCSARequestLog();
-        requestLog.setFilename(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
-        requestLog.setExtended(false);
-        requestLogHandler.setRequestLog(requestLog);
-
-        server.setStopAtShutdown(true);
-
-        server.start();
-        server.dumpStdErr();
-        server.join();
-    }
-}
diff --git a/examples/embedded/src/main/resources/docroot/push.html b/examples/embedded/src/main/resources/docroot/push.html
new file mode 100644
index 0000000..f6807e7
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/push.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+<style>
+img {
+  width: 80px;
+  height: 80px;
+  border: 0;
+  display: block;
+}
+
+td {
+  width: 80px;
+  height: 80px;
+}
+
+tr {
+  height: 80px;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+table, th, td {
+   border: 0 solid black;
+   margin: 0;
+   padding: 0;
+}
+</style>
+
+<body>
+<div id="pushtiles">
+<table>
+<tbody>
+<tr>
+<td><img src="tiles/tile00.jpg" alt="" /></td>
+<td><img src="tiles/tile01.jpg" alt="" /></td>
+<td><img src="tiles/tile02.jpg" alt="" /></td>
+<td><img src="tiles/tile03.jpg" alt="" /></td>
+<td><img src="tiles/tile04.jpg" alt="" /></td>
+<td><img src="tiles/tile05.jpg" alt="" /></td>
+<td><img src="tiles/tile06.jpg" alt="" /></td>
+<td><img src="tiles/tile07.jpg" alt="" /></td>
+<td><img src="tiles/tile08.jpg" alt="" /></td>
+<td><img src="tiles/tile09.jpg" alt="" /></td>
+</tr>
+<tr>
+<td><img src="tiles/tile10.jpg" alt="" /></td>
+<td><img src="tiles/tile11.jpg" alt="" /></td>
+<td><img src="tiles/tile12.jpg" alt="" /></td>
+<td><img src="tiles/tile13.jpg" alt="" /></td>
+<td><img src="tiles/tile14.jpg" alt="" /></td>
+<td><img src="tiles/tile15.jpg" alt="" /></td>
+<td><img src="tiles/tile16.jpg" alt="" /></td>
+<td><img src="tiles/tile17.jpg" alt="" /></td>
+<td><img src="tiles/tile18.jpg" alt="" /></td>
+<td><img src="tiles/tile19.jpg" alt="" /></td>
+</tr>
+<tr>
+<td><img src="tiles/tile20.jpg" alt="" /></td>
+<td><img src="tiles/tile21.jpg" alt="" /></td>
+<td><img src="tiles/tile22.jpg" alt="" /></td>
+<td><img src="tiles/tile23.jpg" alt="" /></td>
+<td><img src="tiles/tile24.jpg" alt="" /></td>
+<td><img src="tiles/tile25.jpg" alt="" /></td>
+<td><img src="tiles/tile26.jpg" alt="" /></td>
+<td><img src="tiles/tile27.jpg" alt="" /></td>
+<td><img src="tiles/tile28.jpg" alt="" /></td>
+<td><img src="tiles/tile29.jpg" alt="" /></td>
+</tr>
+<tr>
+<td><img src="tiles/tile30.jpg" alt="" /></td>
+<td><img src="tiles/tile31.jpg" alt="" /></td>
+<td><img src="tiles/tile32.jpg" alt="" /></td>
+<td><img src="tiles/tile33.jpg" alt="" /></td>
+<td><img src="tiles/tile34.jpg" alt="" /></td>
+<td><img src="tiles/tile35.jpg" alt="" /></td>
+<td><img src="tiles/tile36.jpg" alt="" /></td>
+<td><img src="tiles/tile37.jpg" alt="" /></td>
+<td><img src="tiles/tile38.jpg" alt="" /></td>
+<td><img src="tiles/tile39.jpg" alt="" /></td>
+</tr>
+<tr>
+<td><img src="tiles/tile40.jpg" alt="" /></td>
+<td><img src="tiles/tile41.jpg" alt="" /></td>
+<td><img src="tiles/tile42.jpg" alt="" /></td>
+<td><img src="tiles/tile43.jpg" alt="" /></td>
+<td><img src="tiles/tile44.jpg" alt="" /></td>
+<td><img src="tiles/tile45.jpg" alt="" /></td>
+<td><img src="tiles/tile46.jpg" alt="" /></td>
+<td><img src="tiles/tile47.jpg" alt="" /></td>
+<td><img src="tiles/tile48.jpg" alt="" /></td>
+<td><img src="tiles/tile49.jpg" alt="" /></td>
+</tr>
+</tbody>
+</table>
+</div>
+</body>
+</html>
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile00.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile00.jpg
new file mode 100644
index 0000000..dc30307
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile00.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile01.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile01.jpg
new file mode 100644
index 0000000..66c2e25
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile01.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile02.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile02.jpg
new file mode 100644
index 0000000..f281dfd
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile02.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile03.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile03.jpg
new file mode 100644
index 0000000..4787e69
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile03.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile04.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile04.jpg
new file mode 100644
index 0000000..64e6d10
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile04.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile05.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile05.jpg
new file mode 100644
index 0000000..1530c76
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile05.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile06.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile06.jpg
new file mode 100644
index 0000000..cd59c5f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile06.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile07.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile07.jpg
new file mode 100644
index 0000000..7f85287
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile07.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile08.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile08.jpg
new file mode 100644
index 0000000..31ebcb0
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile08.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile09.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile09.jpg
new file mode 100644
index 0000000..b9cfb1a
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile09.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile10.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile10.jpg
new file mode 100644
index 0000000..11c6fae
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile10.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile11.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile11.jpg
new file mode 100644
index 0000000..fee6760
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile11.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile12.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile12.jpg
new file mode 100644
index 0000000..a503246
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile12.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile13.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile13.jpg
new file mode 100644
index 0000000..4227207
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile13.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile14.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile14.jpg
new file mode 100644
index 0000000..6071c0f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile14.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile15.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile15.jpg
new file mode 100644
index 0000000..64a0bf9
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile15.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile16.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile16.jpg
new file mode 100644
index 0000000..f599516
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile16.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile17.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile17.jpg
new file mode 100644
index 0000000..b4183b3
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile17.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile18.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile18.jpg
new file mode 100644
index 0000000..5a568e2
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile18.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile19.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile19.jpg
new file mode 100644
index 0000000..126c3c6
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile19.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile20.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile20.jpg
new file mode 100644
index 0000000..5423ac1
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile20.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile21.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile21.jpg
new file mode 100644
index 0000000..0b6edb0
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile21.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile22.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile22.jpg
new file mode 100644
index 0000000..f788a48
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile22.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile23.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile23.jpg
new file mode 100644
index 0000000..1fbc64d
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile23.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile24.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile24.jpg
new file mode 100644
index 0000000..f565b8f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile24.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile25.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile25.jpg
new file mode 100644
index 0000000..18a4d06
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile25.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile26.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile26.jpg
new file mode 100644
index 0000000..dde86ec
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile26.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile27.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile27.jpg
new file mode 100644
index 0000000..eaf0ce8
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile27.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile28.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile28.jpg
new file mode 100644
index 0000000..7e59630
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile28.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile29.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile29.jpg
new file mode 100644
index 0000000..1eb25b7
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile29.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile30.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile30.jpg
new file mode 100644
index 0000000..ea68292
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile30.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile31.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile31.jpg
new file mode 100644
index 0000000..31455ca
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile31.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile32.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile32.jpg
new file mode 100644
index 0000000..f6a2a29
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile32.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile33.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile33.jpg
new file mode 100644
index 0000000..8362cf4
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile33.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile34.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile34.jpg
new file mode 100644
index 0000000..2b856a0
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile34.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile35.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile35.jpg
new file mode 100644
index 0000000..4e59e21
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile35.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile36.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile36.jpg
new file mode 100644
index 0000000..7df53fd
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile36.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile37.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile37.jpg
new file mode 100644
index 0000000..3184411
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile37.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile38.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile38.jpg
new file mode 100644
index 0000000..52b44b8
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile38.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile39.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile39.jpg
new file mode 100644
index 0000000..2f7a636
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile39.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile40.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile40.jpg
new file mode 100644
index 0000000..61cfdfa
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile40.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile41.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile41.jpg
new file mode 100644
index 0000000..d25a4e4
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile41.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile42.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile42.jpg
new file mode 100644
index 0000000..029e0f6
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile42.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile43.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile43.jpg
new file mode 100644
index 0000000..5ea4f55
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile43.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile44.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile44.jpg
new file mode 100644
index 0000000..ba18b30
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile44.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile45.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile45.jpg
new file mode 100644
index 0000000..b856d66
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile45.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile46.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile46.jpg
new file mode 100644
index 0000000..f474cc2
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile46.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile47.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile47.jpg
new file mode 100644
index 0000000..6b2f58e
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile47.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile48.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile48.jpg
new file mode 100644
index 0000000..e5d1426
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile48.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/pushed/tile49.jpg b/examples/embedded/src/main/resources/docroot/pushed/tile49.jpg
new file mode 100644
index 0000000..6a33cf3
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/pushed/tile49.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/readme.txt b/examples/embedded/src/main/resources/docroot/readme.txt
new file mode 100644
index 0000000..e0df187
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/readme.txt
@@ -0,0 +1 @@
+This is a test resouce for the Http2Server example
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile00.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile00.jpg
new file mode 100644
index 0000000..b2e52fb
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile00.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile01.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile01.jpg
new file mode 100644
index 0000000..4d98637
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile01.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile02.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile02.jpg
new file mode 100644
index 0000000..06b289b
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile02.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile03.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile03.jpg
new file mode 100644
index 0000000..fcb7b19
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile03.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile04.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile04.jpg
new file mode 100644
index 0000000..0cc4933
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile04.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile05.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile05.jpg
new file mode 100644
index 0000000..6a6d66f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile05.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile06.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile06.jpg
new file mode 100644
index 0000000..89ddd64
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile06.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile07.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile07.jpg
new file mode 100644
index 0000000..9679317
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile07.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile08.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile08.jpg
new file mode 100644
index 0000000..aa895c4
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile08.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile09.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile09.jpg
new file mode 100644
index 0000000..9c234ca
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile09.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile10.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile10.jpg
new file mode 100644
index 0000000..8bc306c
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile10.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile11.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile11.jpg
new file mode 100644
index 0000000..85b62b6
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile11.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile12.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile12.jpg
new file mode 100644
index 0000000..448faa2
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile12.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile13.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile13.jpg
new file mode 100644
index 0000000..4f4f901
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile13.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile14.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile14.jpg
new file mode 100644
index 0000000..e03120b
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile14.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile15.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile15.jpg
new file mode 100644
index 0000000..64bc238
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile15.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile16.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile16.jpg
new file mode 100644
index 0000000..5e858b9
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile16.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile17.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile17.jpg
new file mode 100644
index 0000000..2da3aa8
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile17.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile18.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile18.jpg
new file mode 100644
index 0000000..e934ce5
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile18.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile19.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile19.jpg
new file mode 100644
index 0000000..15707bc
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile19.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile20.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile20.jpg
new file mode 100644
index 0000000..4b940f1
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile20.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile21.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile21.jpg
new file mode 100644
index 0000000..b340585
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile21.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile22.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile22.jpg
new file mode 100644
index 0000000..39b0824
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile22.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile23.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile23.jpg
new file mode 100644
index 0000000..42adae1
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile23.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile24.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile24.jpg
new file mode 100644
index 0000000..a8281dd
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile24.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile25.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile25.jpg
new file mode 100644
index 0000000..43692f0
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile25.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile26.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile26.jpg
new file mode 100644
index 0000000..f8de0f7
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile26.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile27.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile27.jpg
new file mode 100644
index 0000000..f6c210a
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile27.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile28.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile28.jpg
new file mode 100644
index 0000000..39f2622
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile28.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile29.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile29.jpg
new file mode 100644
index 0000000..952ce0b
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile29.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile30.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile30.jpg
new file mode 100644
index 0000000..e699a53
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile30.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile31.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile31.jpg
new file mode 100644
index 0000000..d6256fe
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile31.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile32.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile32.jpg
new file mode 100644
index 0000000..fde5e8b
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile32.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile33.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile33.jpg
new file mode 100644
index 0000000..2ba66aa
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile33.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile34.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile34.jpg
new file mode 100644
index 0000000..37e24f0
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile34.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile35.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile35.jpg
new file mode 100644
index 0000000..b147697
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile35.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile36.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile36.jpg
new file mode 100644
index 0000000..6501650
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile36.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile37.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile37.jpg
new file mode 100644
index 0000000..e2d40ee
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile37.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile38.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile38.jpg
new file mode 100644
index 0000000..1363781
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile38.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile39.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile39.jpg
new file mode 100644
index 0000000..790cfd2
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile39.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile40.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile40.jpg
new file mode 100644
index 0000000..3027238
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile40.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile41.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile41.jpg
new file mode 100644
index 0000000..d085e38
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile41.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile42.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile42.jpg
new file mode 100644
index 0000000..b7ec60f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile42.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile43.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile43.jpg
new file mode 100644
index 0000000..6230abd
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile43.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile44.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile44.jpg
new file mode 100644
index 0000000..46ad6a1
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile44.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile45.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile45.jpg
new file mode 100644
index 0000000..89d2d32
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile45.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile46.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile46.jpg
new file mode 100644
index 0000000..9f3451f
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile46.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile47.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile47.jpg
new file mode 100644
index 0000000..b702178
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile47.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile48.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile48.jpg
new file mode 100644
index 0000000..9defd9a
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile48.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/docroot/tiles/tile49.jpg b/examples/embedded/src/main/resources/docroot/tiles/tile49.jpg
new file mode 100644
index 0000000..26f2a44
--- /dev/null
+++ b/examples/embedded/src/main/resources/docroot/tiles/tile49.jpg
Binary files differ
diff --git a/examples/embedded/src/main/resources/exampleserver.xml b/examples/embedded/src/main/resources/exampleserver.xml
index a0fc811..deae1dd 100644
--- a/examples/embedded/src/main/resources/exampleserver.xml
+++ b/examples/embedded/src/main/resources/exampleserver.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="ExampleServer" class="org.eclipse.jetty.server.Server">
 
diff --git a/examples/embedded/src/main/resources/fileserver.xml b/examples/embedded/src/main/resources/fileserver.xml
index 0b4daa3..126f098 100644
--- a/examples/embedded/src/main/resources/fileserver.xml
+++ b/examples/embedded/src/main/resources/fileserver.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="FileServer" class="org.eclipse.jetty.server.Server">
 
diff --git a/examples/embedded/src/main/resources/java-util-logging.properties b/examples/embedded/src/main/resources/java-util-logging.properties
new file mode 100644
index 0000000..4aaa236
--- /dev/null
+++ b/examples/embedded/src/main/resources/java-util-logging.properties
@@ -0,0 +1,9 @@
+
+# Logging
+handlers = java.util.logging.ConsoleHandler
+.level = INFO
+
+java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n
+
+# Console Logging
+java.util.logging.ConsoleHandler.level = ALL
\ No newline at end of file
diff --git a/examples/embedded/src/main/resources/jetty-logging.properties b/examples/embedded/src/main/resources/jetty-logging.properties
index d353093..7bffba8 100644
--- a/examples/embedded/src/main/resources/jetty-logging.properties
+++ b/examples/embedded/src/main/resources/jetty-logging.properties
@@ -1,12 +1,10 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-org.eclipse.jetty.LEVEL=INFO
-org.eclipse.jetty.STACKS=true
-org.eclipse.jetty.SOURCE=false
+#org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog
+#org.eclipse.jetty.util.log.javautil.PROPERTIES=java-util-logging.properties
+#org.eclipse.jetty.util.log.SOURCE=true
+#org.eclipse.jetty.LEVEL=INFO
+#org.eclipse.jetty.STACKS=true
 #org.eclipse.jetty.STACKS=false
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
-#org.eclipse.jetty.server.LEVEL=DEBUG
 #org.eclipse.jetty.io.LEVEL=DEBUG
 #org.eclipse.jetty.io.ssl.LEVEL=DEBUG
-#org.eclipse.jetty.spdy.server.LEVEL=DEBUG
 #org.eclipse.jetty.server.LEVEL=DEBUG
 #org.eclipse.jetty.servlets.LEVEL=DEBUG
diff --git a/examples/embedded/src/main/resources/jetty-otherserver.xml b/examples/embedded/src/main/resources/jetty-otherserver.xml
index 4c8a5cd..21272bb 100644
--- a/examples/embedded/src/main/resources/jetty-otherserver.xml
+++ b/examples/embedded/src/main/resources/jetty-otherserver.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="OtherServer" class="org.eclipse.jetty.server.Server">
     <Set name="handler">
diff --git a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java
index 447bfe0..6bb8b5e 100644
--- a/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java
+++ b/examples/embedded/src/test/java/org/eclipse/jetty/embedded/TestXml.java
@@ -25,12 +25,7 @@
     public static void main(String[] args) throws Exception
     {
         System.setProperty("jetty.home","../jetty-distribution/target/distribution");
-        XmlConfiguration.main(new String[]
-            {
-            "../jetty-jmx/src/main/config/etc/jetty-jmx.xml",
-            "../jetty-server/src/main/config/etc/jetty.xml",
-            "../jetty-spdy/spdy-jetty-http-webapp/src/main/config/etc/jetty-spdy.xml"
-            }
-        );
+        XmlConfiguration.main("../jetty-jmx/src/main/config/etc/jetty-jmx.xml",
+                "../jetty-server/src/main/config/etc/jetty.xml");
     }
 }
diff --git a/examples/pom.xml b/examples/pom.xml
index feaef2f..641240c 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.eclipse.jetty.examples</groupId>
diff --git a/jetty-alpn/jetty-alpn-client/pom.xml b/jetty-alpn/jetty-alpn-client/pom.xml
index 1a9651e..e0466a9 100644
--- a/jetty-alpn/jetty-alpn-client/pom.xml
+++ b/jetty-alpn/jetty-alpn-client/pom.xml
@@ -2,13 +2,11 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-alpn-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-alpn-client</artifactId>
-  <name>Jetty :: ALPN Client</name>
-  <description>Jetty ALPN client services</description>
-  <url>http://www.eclipse.org/jetty</url>
+  <name>Jetty :: ALPN :: Client</name>
   <properties>
     <bundle-symbolic-name>${project.groupId}.alpn.client</bundle-symbolic-name>
   </properties>
@@ -31,15 +29,6 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
       <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
       with a snapshot. -->
       <plugin>
diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java
index 39e8073..b4c55b5 100644
--- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java
+++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnection.java
@@ -18,10 +18,10 @@
 
 package org.eclipse.jetty.alpn.client;
 
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.alpn.ALPN;
@@ -35,12 +35,12 @@
 {
     private static final Logger LOG = Log.getLogger(ALPNClientConnection.class);
 
-    private final String protocol;
+    private final List<String> protocols;
 
-    public ALPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, String protocol)
+    public ALPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, List<String> protocols)
     {
         super(endPoint, executor, sslEngine, connectionFactory, context);
-        this.protocol = protocol;
+        this.protocols = protocols;
         ALPN.put(sslEngine, this);
     }
 
@@ -54,20 +54,20 @@
     @Override
     public List<String> protocols()
     {
-        return Arrays.asList(protocol);
+        return protocols;
     }
 
     @Override
     public void selected(String protocol)
     {
-        if (this.protocol.equals(protocol))
+        if (protocols.contains(protocol))
         {
             ALPN.remove(getSSLEngine());
             completed();
         }
         else
         {
-            LOG.info("Could not negotiate protocol: server {} - client {}", protocol, this.protocol);
+            LOG.info("Could not negotiate protocol: server [{}] - client {}", protocol, protocols);
             close();
         }
     }
diff --git a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java
index 5c74dce..da45aa0 100644
--- a/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java
+++ b/jetty-alpn/jetty-alpn-client/src/main/java/org/eclipse/jetty/alpn/client/ALPNClientConnectionFactory.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.alpn.client;
 
 import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
 
@@ -33,19 +34,21 @@
 public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory
 {
     private final Executor executor;
-    private final String protocol;
+    private final List<String> protocols;
 
-    public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol)
+    public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, List<String> protocols)
     {
         super(connectionFactory);
         this.executor = executor;
-        this.protocol = protocol;
+        this.protocols = protocols;
+        if (protocols.isEmpty())
+            throw new IllegalArgumentException("ALPN protocol list cannot be empty");
     }
 
     @Override
     public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
     {
         return new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(),
-                (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol);
+                (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocols);
     }
 }
diff --git a/jetty-alpn/jetty-alpn-server/pom.xml b/jetty-alpn/jetty-alpn-server/pom.xml
index 1949aa9..8aaae0f 100644
--- a/jetty-alpn/jetty-alpn-server/pom.xml
+++ b/jetty-alpn/jetty-alpn-server/pom.xml
@@ -2,62 +2,16 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-alpn-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-alpn-server</artifactId>
-  <name>Jetty :: ALPN Server</name>
-  <description>Jetty ALPN server services</description>
-  <url>http://www.eclipse.org/jetty</url>
+  <name>Jetty :: ALPN :: Server</name>
   <properties>
     <bundle-symbolic-name>${project.groupId}.alpn.server</bundle-symbolic-name>
   </properties>
   <build>
     <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-               <Import-Package>org.eclipse.jetty.alpn,*</Import-Package>
-               <_nouses>true</_nouses>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
       <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
       with a snapshot. -->
       <plugin>
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml
new file mode 100644
index 0000000..a8b0e35
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.server.SslConnectionFactory">
+        <Arg name="next">alpn</Arg>
+        <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
+      </New>
+    </Arg>
+  </Call>
+  
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New id="alpn" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
+        <Arg type="String">
+          <Property name="jetty.alpn.protocols" deprecated="alpn.protocols" default="" />
+        </Arg>
+        <Set name="defaultProtocol">
+          <Property name="jetty.alpn.defaultProtocol" deprecated="alpn.defaultProtocol" />
+        </Set>
+      </New>
+    </Arg>
+  </Call>
+
+  <!-- ALPN debugging on System.err -->
+  <Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean"><Property name="jetty.alpn.debug" default="false" /></Set>
+
+</Configure>
+
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml b/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml
deleted file mode 100644
index 5d2ac7a..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/etc/protonego-alpn.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="protonego" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
-    <Arg name="protocols">
-        <Array type="String">
-            <Item>spdy/3</Item>
-            <Item>spdy/2</Item>
-            <Item>http/1.1</Item>
-        </Array>
-    </Arg>
-
-    <Set name="defaultProtocol">http/1.1</Set>
-
-    <!-- Enables NPN debugging on System.err -->
-    <!--<Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean">true</Set>-->
-
-</Configure>
-
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_05.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_11.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_20.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod
new file mode 100644
index 0000000..6d6d75e
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_25.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.2.v20141202|lib/alpn/alpn-boot-8.1.2.v20141202.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.2.v20141202.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod
new file mode 100644
index 0000000..e52bd23
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_31.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_40.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_40.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_45.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_45.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_51.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_51.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_60.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_65.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_66.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod
similarity index 100%
rename from jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_66.mod
rename to jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod
new file mode 100644
index 0000000..7928e64
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn.mod
@@ -0,0 +1,53 @@
+# ALPN is provided via a -Xbootclasspath that modifies the secure connections
+# in java to support the ALPN layer needed for HTTP/2.
+#
+# This modification has a tight dependency on specific recent updates of
+# Java 1.7 and Java 1.8 (Java versions prior to 1.7u40 are not supported).
+#
+# The alpn module will use an appropriate alpn-boot jar for your
+# specific version of Java.
+#
+# IMPORTANT: Versions of Java that exist after this module was created are
+#            not guaranteed to work with existing alpn-boot jars, and might
+#            need a new alpn-boot to be created / tested / deployed by the
+#            Jetty project in order to provide support for these future
+#            Java versions.
+#
+# All versions of alpn-boot can be found at
+# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
+
+[name]
+alpn
+
+[depend]
+ssl
+alpn-impl/alpn-${java.version}
+
+[lib]
+lib/jetty-alpn-client-${jetty.version}.jar
+lib/jetty-alpn-server-${jetty.version}.jar
+
+[xml]
+etc/jetty-alpn.xml
+
+[files]
+lib/
+lib/alpn/
+
+[ini-template]
+## Overrides the order protocols are chosen by the server.
+## The default order is that specified by the order of the
+## modules declared in start.ini.
+# jetty.alpn.protocols=h2-16,http/1.1
+
+## Specifies what protocol to use when negotiation fails.
+# jetty.alpn.defaultProtocol=http/1.1
+
+## ALPN debug logging on System.err
+# jetty.alpn.debug=false
+
+[license]
+ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
+ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
+http://github.com/jetty-project/jetty-alpn
+http://openjdk.java.net/legal/gplv2+ce.html
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_40.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_40.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_45.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_45.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_51.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_51.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_55.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_55.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_67.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_71.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_71.mod
deleted file mode 100644
index e9b4e2a..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_71.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.2.v20141202/alpn-boot-7.1.2.v20141202.jar|lib/alpn/alpn-boot-7.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.2.v20141202.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_72.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_72.mod
deleted file mode 100644
index e9b4e2a..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_72.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.2.v20141202/alpn-boot-7.1.2.v20141202.jar|lib/alpn/alpn-boot-7.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.2.v20141202.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_75.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_75.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_75.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_76.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_76.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_76.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_79.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_79.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_79.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_80.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_80.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_80.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_05.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_05.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_20.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_20.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_20.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_25.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_25.mod
deleted file mode 100644
index 8d13261..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_25.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.2.v20141202/alpn-boot-8.1.2.v20141202.jar|lib/alpn/alpn-boot-8.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.2.v20141202.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_31.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_31.mod
deleted file mode 100644
index 4114979..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_31.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod
deleted file mode 100644
index d3e4118..0000000
--- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn.mod
+++ /dev/null
@@ -1,42 +0,0 @@
-# ALPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2)
-#
-# This modification has a tight dependency on specific recent updates of
-# Java 1.7 and Java 1.8
-# (Java versions prior to 1.7u40 are not supported)
-#
-# The alpn protonego module will use an appropriate alpn-boot jar for your
-# specific version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing alpn-boot jars, and might
-#            need a new alpn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of alpn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/alpn-${java.version}
-
-[lib]
-lib/jetty-alpn-client-${jetty.version}.jar
-lib/jetty-alpn-server-${jetty.version}.jar
-
-[xml]
-etc/protonego-alpn.xml
-
-[files]
-lib/
-lib/alpn/
-
-[license]
-ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
-ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
-http://github.com/jetty-project/jetty-alpn
-http://openjdk.java.net/legal/gplv2+ce.html
-
diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
index b4d99f1..e6c15eb 100644
--- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
+++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnection.java
@@ -20,10 +20,12 @@
 
 import java.util.Collections;
 import java.util.List;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.alpn.ALPN;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.ConnectionFactory;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.NegotiatingServerConnection;
 import org.eclipse.jetty.util.log.Log;
@@ -48,7 +50,10 @@
     @Override
     public String select(List<String> clientProtocols)
     {
+        SSLEngine sslEngine = getSSLEngine();
         List<String> serverProtocols = getProtocols();
+        String tlsProtocol = sslEngine.getHandshakeSession().getProtocol();
+        String tlsCipher = sslEngine.getHandshakeSession().getCipherSuite();
         String negotiated = null;
 
         // RFC 7301 states that the server picks the protocol
@@ -57,19 +62,35 @@
         {
             if (clientProtocols.contains(serverProtocol))
             {
+                ConnectionFactory factory = getConnector().getConnectionFactory(serverProtocol);
+                if (factory instanceof CipherDiscriminator && !((CipherDiscriminator)factory).isAcceptable(serverProtocol, tlsProtocol, tlsCipher))
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} protocol {} not acceptable to {} for {}/{}", this, serverProtocol, factory, tlsProtocol, tlsCipher);
+                    continue;
+                }
+
                 negotiated = serverProtocol;
                 break;
             }
         }
-
         if (negotiated == null)
         {
-            negotiated = getDefaultProtocol();
+            if (clientProtocols.isEmpty())
+            {
+                negotiated = getDefaultProtocol();
+            }
+            else
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} could not negotiate protocol: C{} | S{}", this, clientProtocols, serverProtocols);
+                throw new IllegalStateException();
+            }
         }
         if (LOG.isDebugEnabled())
             LOG.debug("{} protocol selected {}", this, negotiated);
         setProtocol(negotiated);
-        ALPN.remove(getSSLEngine());
+        ALPN.remove(sslEngine);
         return negotiated;
     }
 
diff --git a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java
index 56680e4..3608b45 100644
--- a/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java
+++ b/jetty-alpn/jetty-alpn-server/src/main/java/org/eclipse/jetty/alpn/server/ALPNServerConnectionFactory.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.alpn.server;
 
 import java.util.List;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.alpn.ALPN;
@@ -34,6 +35,11 @@
 {
     private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class);
 
+    public ALPNServerConnectionFactory(String protocols)
+    {
+        this(protocols.trim().split(",", 0));
+    }
+
     public ALPNServerConnectionFactory(@Name("protocols") String... protocols)
     {
         super("alpn", protocols);
diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml
index 5027292..888e31b 100644
--- a/jetty-alpn/pom.xml
+++ b/jetty-alpn/pom.xml
@@ -2,14 +2,12 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-alpn-parent</artifactId>
   <packaging>pom</packaging>
   <name>Jetty :: ALPN :: Parent</name>
-  <description>Jetty ALPN services parent</description>
-  <url>http://www.eclipse.org/jetty</url>
   <modules>
     <module>jetty-alpn-server</module>
     <module>jetty-alpn-client</module>
diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml
index 4658dda..842aa11 100644
--- a/jetty-annotations/pom.xml
+++ b/jetty-annotations/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-annotations</artifactId>
@@ -15,52 +15,14 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
         <extensions>true</extensions>
-        <executions>
-          <execution>
-            <id>generate-manifest</id>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.objectweb.asm.*;version=5,*</Import-Package>
                 <Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
               </instructions>
             </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
diff --git a/jetty-annotations/src/main/config/etc/jetty-annotations.xml b/jetty-annotations/src/main/config/etc/jetty-annotations.xml
index 637b511..3eb3f6b 100644
--- a/jetty-annotations/src/main/config/etc/jetty-annotations.xml
+++ b/jetty-annotations/src/main/config/etc/jetty-annotations.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
   <!-- =========================================================== -->
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
index 90836b4..7e1e3b8 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java
@@ -23,6 +23,7 @@
 import java.net.URI;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -59,8 +60,6 @@
 
 /**
  * Configuration for Annotations
- *
- *
  */
 public class AnnotationConfiguration extends AbstractConfiguration
 {
@@ -89,7 +88,7 @@
     protected CounterStatistic _webInfLibStats;
     protected CounterStatistic _webInfClassesStats;
     protected Pattern _sciExcludePattern;
-  
+    protected ServiceLoader<ServletContainerInitializer> _loadedInitializers = null;
     /**
      * TimeStatistic
      *
@@ -293,8 +292,7 @@
         }
         
         /**
-         * True if "*" is one of the values.
-         * @return
+         * @return true if "*" is one of the values.
          */
         public boolean hasWildcard()
         {
@@ -302,8 +300,7 @@
         }
         
         /**
-         * Get the index of the "*" element, if it is specified. -1 otherwise.
-         * @return
+         * @return the index of the "*" element, if it is specified. -1 otherwise.
          */
         public int getWildcardIndex()
         {
@@ -313,8 +310,7 @@
         }
         
         /**
-         * True if the ordering contains a single value of "*"
-         * @return
+         * @return true if the ordering contains a single value of "*"
          */
         public boolean isDefaultOrder ()
         {
@@ -323,8 +319,8 @@
         
         /**
          * Get the order index of the given classname
-         * @param name
-         * @return
+         * @param name the classname to look up
+         * @return the index of the class name (or -1 if not found)
          */
         public int getIndexOf (String name)
         {
@@ -336,7 +332,7 @@
         
         /**
          * Get the number of elements of the ordering
-         * @return
+         * @return the size of the index
          */
         public int getSize()
         {
@@ -417,6 +413,9 @@
             context.removeBean(starter);
             context.removeAttribute(CONTAINER_INITIALIZER_STARTER);
         }
+        
+        if (_loadedInitializers != null)
+            _loadedInitializers.reload();
     }
     
     /** 
@@ -425,7 +424,7 @@
     @Override
     public void configure(WebAppContext context) throws Exception
     {
-       context.addDecorator(new AnnotationDecorator(context));
+       context.getObjectFactory().addDecorator(new AnnotationDecorator(context));
 
        //Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
       
@@ -499,8 +498,8 @@
     /**
      * Perform scanning of classes for annotations
      * 
-     * @param context
-     * @throws Exception
+     * @param context the context for the scan
+     * @throws Exception if unable to scan
      */
     protected void scanForAnnotations (WebAppContext context)
     throws Exception
@@ -592,8 +591,9 @@
     
     /**
      * Check if we should use multiple threads to scan for annotations or not
-     * @param context
-     * @return
+     * @param context the context of the multi threaded setting
+     * @return true if multi threading is enabled on the context, server, or via a System property.
+     * @see #MULTI_THREADED
      */
     protected boolean isUseMultiThreading(WebAppContext context)
     {
@@ -618,8 +618,9 @@
     /**
      * Work out how long we should wait for the async scanning to occur.
      * 
-     * @param context
-     * @return
+     * @param context the context of the max scan wait setting
+     * @return the max scan wait setting on the context, or server, or via a System property.
+     * @see #MAX_SCAN_WAIT
      */
     protected int getMaxScanWait (WebAppContext context)
     {
@@ -639,24 +640,15 @@
         return Integer.getInteger(MAX_SCAN_WAIT, DEFAULT_MAX_SCAN_WAIT).intValue();
     }
     
-    
-    
     /** 
      * @see org.eclipse.jetty.webapp.AbstractConfiguration#cloneConfigure(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.WebAppContext)
      */
     @Override
     public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
     {
-        context.addDecorator(new AnnotationDecorator(context));
+        context.getObjectFactory().addDecorator(new AnnotationDecorator(context));
     }
 
-
-    
-    /**
-     * @param context
-     * @param scis
-     * @throws Exception
-     */
     public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List<ServletContainerInitializer> scis)
     throws Exception
     {
@@ -676,6 +668,9 @@
                 Class<?>[] classes = annotation.value();
                 if (classes != null)
                 {
+
+                    if (LOG.isDebugEnabled()){LOG.debug("HandlesTypes {} on initializer {}",Arrays.asList(classes),service.getClass());}
+                    
                     initializer = new ContainerInitializer(service, classes);
 
                     //If we haven't already done so, we need to register a handler that will
@@ -708,7 +703,7 @@
             else
             {
                 initializer = new ContainerInitializer(service, null);
-                if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
+                if (LOG.isDebugEnabled()) LOG.debug("No HandlesTypes annotation on initializer "+service.getClass());
             }
             
             initializers.add(initializer);
@@ -724,7 +719,6 @@
         context.addBean(starter, true);
     }
 
-    
     public Resource getJarFor (ServletContainerInitializer service) 
     throws MalformedURLException, IOException
     {
@@ -747,13 +741,15 @@
         return Resource.newResource(loadingJarName);
     }
     
-
     /**
      * Check to see if the ServletContainerIntializer loaded via the ServiceLoader came
      * from a jar that is excluded by the fragment ordering. See ServletSpec 3.0 p.85.
-     * @param context
-     * @param sci
+     * 
+     * @param context the context for the jars
+     * @param sci the servlet container initializer
+     * @param sciResource  the resource for the servlet container initializer
      * @return true if excluded
+     * @throws Exception if unable to determine exclusion
      */
     public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer sci, Resource sciResource)
     throws Exception
@@ -800,9 +796,9 @@
     /**
      * Test if the ServletContainerIntializer is excluded by the 
      * o.e.j.containerInitializerExclusionPattern
-     * @param context
-     * @param sci
-     * @return
+     * 
+     * @param sci the ServletContainerIntializer
+     * @return true if the ServletContainerIntializer is excluded
      */
     public boolean matchesExclusionPattern(ServletContainerInitializer sci)
     {
@@ -819,9 +815,9 @@
     /**
      * Test if the ServletContainerInitializer is from the container classpath
      * 
-     * @param context
-     * @param sci
-     * @return
+     * @param context the context for the webapp classpath
+     * @param sci the ServletContainerIntializer
+     * @return true if ServletContainerIntializer is from container classpath
      */
     public boolean isFromContainerClassPath (WebAppContext context, ServletContainerInitializer sci)
     {
@@ -831,26 +827,27 @@
     }
 
     /**
-     * @param context
-     * @return list of non-excluded {@link ServletContainerInitializer}s
-     * @throws Exception
+     * Get SCIs that are not excluded from consideration
+     * @param context the web app context 
+     * @return the list of non-excluded servlet container initializers
+     * @throws Exception if unable to get list 
      */
     public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
     throws Exception
     {
         ArrayList<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
-
+      
         //We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect
         long start = 0;
 
         ClassLoader old = Thread.currentThread().getContextClassLoader();
-        ServiceLoader<ServletContainerInitializer> loadedInitializers = null;
+       
         try
         {        
             if (LOG.isDebugEnabled())
                 start = System.nanoTime();
             Thread.currentThread().setContextClassLoader(context.getClassLoader());
-            loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class);
+            _loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class);
         }
         finally
         {
@@ -859,21 +856,22 @@
         
         if (LOG.isDebugEnabled())
             LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime()-start), TimeUnit.NANOSECONDS)));
-        
+     
         
         Map<ServletContainerInitializer,Resource> sciResourceMap = new HashMap<ServletContainerInitializer,Resource>();
         ServletContainerInitializerOrdering initializerOrdering = getInitializerOrdering(context);
 
         //Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded
         //because containerInitializerOrdering omits it
-        for (ServletContainerInitializer sci:loadedInitializers)
-        {       
+        for (ServletContainerInitializer sci:_loadedInitializers)
+        { 
+            
             if (matchesExclusionPattern(sci)) 
             {
                 if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci);
                 continue;
             }
-            
+
             Resource sciResource = getJarFor(sci);
             if (isFromExcludedJar(context, sci, sciResource)) 
             { 
@@ -933,7 +931,7 @@
                 {
                     for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
                     {
-                        if (webInfJar.equals(entry.getValue()))
+                      if (webInfJar.equals(entry.getValue()))
                             nonExcludedInitializers.add(entry.getKey());
                     }
                 }
@@ -944,8 +942,9 @@
         {
             int i=0;
             for (ServletContainerInitializer sci:nonExcludedInitializers)
-                LOG.debug("ServletContainerInitializer: {} {}",(++i), sci.getClass().getName());
-        }
+                LOG.debug("ServletContainerInitializer: {} {} from {}",(++i), sci.getClass().getName(), sciResourceMap.get(sci));
+        }    
+        
         return nonExcludedInitializers;
     }
 
@@ -953,7 +952,8 @@
     /**
      * Jetty-specific extension that allows an ordering to be applied across ALL ServletContainerInitializers.
      * 
-     * @return
+     * @param context the context for the initializer ordering configuration 
+     * @return the ordering of the ServletContainerIntializer's
      */
     public ServletContainerInitializerOrdering getInitializerOrdering (WebAppContext context)
     {
@@ -971,9 +971,9 @@
     /**
      * Scan jars on container path.
      * 
-     * @param context
-     * @param parser
-     * @throws Exception
+     * @param context the context for the scan
+     * @param parser the parser to scan with
+     * @throws Exception if unable to scan
      */
     public void parseContainerPath (final WebAppContext context, final AnnotationParser parser) throws Exception
     {
@@ -1004,9 +1004,9 @@
     /**
      * Scan jars in WEB-INF/lib
      * 
-     * @param context
-     * @param parser
-     * @throws Exception
+     * @param context the context for the scan
+     * @param parser the annotation parser to use
+     * @throws Exception if unable to scan and/or parse
      */
     public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser) throws Exception
     {   
@@ -1067,9 +1067,9 @@
     /**
      * Scan classes in WEB-INF/classes
      * 
-     * @param context
-     * @param parser
-     * @throws Exception
+     * @param context the context for the scan
+     * @param parser the annotation parser to use
+     * @throws Exception if unable to scan and/or parse
      */
     public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
     throws Exception
@@ -1100,10 +1100,10 @@
     /**
      * Get the web-fragment.xml from a jar
      * 
-     * @param jar
-     * @param frags
-     * @return the fragment if found, or null of not found
-     * @throws Exception
+     * @param jar the jar to look in for a fragment
+     * @param frags the fragments previously found
+     * @return true if the fragment if found, or null of not found
+     * @throws Exception if unable to determine the the fragment contains
      */
     public FragmentDescriptor getFragmentFromJar (Resource jar,  List<FragmentDescriptor> frags)
     throws Exception
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java
index 896eac0..60cd298 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java
@@ -18,21 +18,16 @@
 
 package org.eclipse.jetty.annotations;
 
-import org.eclipse.jetty.servlet.ServletContextHandler.Decorator;
+import org.eclipse.jetty.util.Decorator;
 import org.eclipse.jetty.webapp.WebAppContext;
 
 /**
  * AnnotationDecorator
- *
- *
  */
 public class AnnotationDecorator implements Decorator
 {
     protected AnnotationIntrospector _introspector = new AnnotationIntrospector();
 
-    /**
-     * @param context
-     */
     public AnnotationDecorator(WebAppContext context)
     {
        registerHandlers(context);
@@ -53,13 +48,13 @@
     /**
      * Look for annotations that can be discovered with introspection:
      * <ul>
-     * <li> Resource
-     * <li> Resources
-     * <li> PostConstruct
-     * <li> PreDestroy
-     * <li> ServletSecurity?
+     * <li> Resource </li>
+     * <li> Resources </li>
+     * <li> PostConstruct </li>
+     * <li> PreDestroy </li>
+     * <li> ServletSecurity? </li>
      * </ul>
-     * @param o
+     * @param o the object ot introspect
      */
     protected void introspect (Object o)
     {
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java
index 69b5930..14bec7e 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java
@@ -48,18 +48,18 @@
 
 /**
  * AnnotationParser
- *
+ * <p>
  * Use asm to scan classes for annotations. A SAX-style parsing is done.
  * Handlers are registered which will be called back when various types of
  * entity are encountered, eg a class, a method, a field. 
- * 
+ * <p> 
  * Handlers are not called back in any particular order and are assumed
  * to be order-independent.
- * 
+ * <p>
  * As a registered Handler will be called back for each annotation discovered
  * on a class, a method, a field, the Handler should test to see if the annotation
  * is one that it is interested in.
- * 
+ * <p>
  * For the servlet spec, we are only interested in annotations on classes, methods and fields,
  * so the callbacks for handling finding a class, a method a field are themselves
  * not fully implemented.
@@ -76,8 +76,8 @@
     /**
      * Convert internal name to simple name
      * 
-     * @param name
-     * @return
+     * @param name the internal name
+     * @return the simple name
      */
     public static String normalize (String name)
     {
@@ -96,8 +96,8 @@
     /**
      * Convert internal names to simple names.
      * 
-     * @param list
-     * @return
+     * @param list the list of internal names
+     * @return the list of simple names
      */
     public static String[] normalize (String[] list)
     {
@@ -291,7 +291,6 @@
         }
     }
     
-    
     /**
      * Handler
      *
@@ -307,13 +306,10 @@
         public void handle (FieldInfo info, String annotationName);
     }
     
-    
-    
     /**
      * AbstractHandler
      *
      * Convenience base class to provide no-ops for all Handler methods.
-     * 
      */
     public static abstract class AbstractHandler implements Handler
     {
@@ -533,7 +529,8 @@
 
     /**
      * True if the class has already been processed, false otherwise
-     * @param className
+     * @param className the classname
+     * @return true if class was parsed, false if not
      */
     public boolean isParsed (String className)
     {
@@ -545,9 +542,10 @@
     /**
      * Parse a given class
      * 
-     * @param className
-     * @param resolver
-     * @throws Exception
+     * @param handlers the set of handlers to find class
+     * @param className the class name to parse
+     * @param resolver the class name resolver to use 
+     * @throws Exception if unable to parse
      */
     public void parse (Set<? extends Handler> handlers, String className, ClassNameResolver resolver)
     throws Exception
@@ -564,7 +562,10 @@
                 if (resource!= null)
                 {
                     Resource r = Resource.newResource(resource);
-                    scanClass(handlers, null, r.getInputStream());
+                    try (InputStream is = r.getInputStream())
+                    {
+                        scanClass(handlers, null, is);
+                    }
                 }
             }
         }
@@ -575,10 +576,11 @@
     /**
      * Parse the given class, optionally walking its inheritance hierarchy
      * 
-     * @param clazz
-     * @param resolver
-     * @param visitSuperClasses
-     * @throws Exception
+     * @param handlers the handlers to look for class in 
+     * @param clazz the class to look for
+     * @param resolver the resolver to look up class with
+     * @param visitSuperClasses if true, also visit super classes for parse 
+     * @throws Exception if unable to parse class
      */
     public void parse (Set<? extends Handler> handlers, Class<?> clazz, ClassNameResolver resolver, boolean visitSuperClasses)
     throws Exception
@@ -595,7 +597,10 @@
                     if (resource!= null)
                     {
                         Resource r = Resource.newResource(resource);
-                        scanClass(handlers, null, r.getInputStream());
+                        try (InputStream is =  r.getInputStream())
+                        {
+                            scanClass(handlers, null, is);
+                        }
                     }
                 }
             }
@@ -612,9 +617,10 @@
     /**
      * Parse the given classes
      * 
-     * @param classNames
-     * @param resolver
-     * @throws Exception
+     * @param handlers the set of handlers to look for class in 
+     * @param classNames the class name
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (Set<? extends Handler> handlers, String[] classNames, ClassNameResolver resolver)
     throws Exception
@@ -629,9 +635,10 @@
     /**
      * Parse the given classes
      * 
-     * @param classNames
-     * @param resolver
-     * @throws Exception
+     * @param handlers the set of handlers to look for class in 
+     * @param classNames the class names
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (Set<? extends Handler> handlers, List<String> classNames, ClassNameResolver resolver)
     throws Exception
@@ -649,7 +656,10 @@
                     if (resource!= null)
                     {
                         Resource r = Resource.newResource(resource);
-                        scanClass(handlers, null, r.getInputStream());
+                        try (InputStream is = r.getInputStream())
+                        {
+                            scanClass(handlers, null, is);
+                        }
                     }
                 }
             }
@@ -665,14 +675,15 @@
     /**
      * Parse all classes in a directory
      * 
-     * @param dir
-     * @param resolver
-     * @throws Exception
+     * @param handlers the set of handlers to look for classes in 
+     * @param dir the resource directory to look for classes
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     protected void parseDir (Set<? extends Handler> handlers, Resource dir, ClassNameResolver resolver)
     throws Exception
     {
-        //skip dirs whose name start with . (ie hidden)
+        // skip dirs whose name start with . (ie hidden)
         if (!dir.isDirectory() || !dir.exists() || dir.getName().startsWith("."))
             return;
 
@@ -699,7 +710,10 @@
                         {
                             Resource r = Resource.newResource(res.getURL());
                             if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
-                            scanClass(handlers, dir, r.getInputStream());
+                            try (InputStream is=r.getInputStream())
+                            {
+                                scanClass(handlers, dir, is);
+                            }
                         }
                     }                  
                     catch (Exception ex)
@@ -723,11 +737,12 @@
      * Parse classes in the supplied classloader. 
      * Only class files in jar files will be scanned.
      * 
-     * @param loader
-     * @param visitParents
-     * @param nullInclusive
-     * @param resolver
-     * @throws Exception
+     * @param handlers the handlers to look for classes in 
+     * @param loader the classloader for the classes
+     * @param visitParents if true, visit parent classloaders too
+     * @param nullInclusive if true, an empty pattern means all names match, if false, none match
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
     throws Exception
@@ -765,9 +780,10 @@
     /**
      * Parse classes in the supplied uris.
      * 
-     * @param uris
-     * @param resolver
-     * @throws Exception
+     * @param handlers the handlers to look for classes in  
+     * @param uris the uris for the jars
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (final Set<? extends Handler> handlers, final URI[] uris, final ClassNameResolver resolver)
     throws Exception
@@ -793,9 +809,11 @@
 
     /**
      * Parse a particular uri
-     * @param uri
-     * @param resolver
-     * @throws Exception
+     * 
+     * @param handlers the handlers to look for classes in 
+     * @param uri the uri for the jar 
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (final Set<? extends Handler> handlers, URI uri, final ClassNameResolver resolver)
     throws Exception
@@ -809,9 +827,11 @@
     
     /**
      * Parse a resource
-     * @param r
-     * @param resolver
-     * @throws Exception
+     * 
+     * @param handlers the handlers to look for classes in  
+     * @param r the resource to parse
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     public void parse (final Set<? extends Handler> handlers, Resource r, final ClassNameResolver resolver)
     throws Exception
@@ -834,8 +854,11 @@
 
         if (fullname.endsWith(".class"))
         {
-            scanClass(handlers, null, r.getInputStream());
-            return;
+            try (InputStream is=r.getInputStream())
+            {
+                scanClass(handlers, null, is);
+                return;
+            }
         }
         
         if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", r);
@@ -847,9 +870,10 @@
     /**
      * Parse a resource that is a jar file.
      * 
-     * @param jarResource
-     * @param resolver
-     * @throws Exception
+     * @param handlers the handlers to look for classes in  
+     * @param jarResource the jar resource to parse
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     protected void parseJar (Set<? extends Handler> handlers, Resource jarResource,  final ClassNameResolver resolver)
     throws Exception
@@ -925,10 +949,12 @@
 
     /**
      * Parse a single entry in a jar file
-     * @param jar
-     * @param entry
-     * @param resolver
-     * @throws Exception
+     * 
+     * @param handlers the handlers to look for classes in  
+     * @param jar the jar resource to parse
+     * @param entry the entry in the jar resource to parse
+     * @param resolver the class name resolver
+     * @throws Exception if unable to parse
      */
     protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver)
     throws Exception
@@ -949,11 +975,14 @@
 
             if ((resolver == null)
                     ||
-                (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
+               (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
             {
                 Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
                 if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};
-                scanClass(handlers, jar, clazz.getInputStream());
+                try (InputStream is = clazz.getInputStream())
+                {
+                    scanClass(handlers, jar, is);
+                }
             }
         }
     }
@@ -963,9 +992,10 @@
     /**
      * Use ASM on a class
      * 
+     * @param handlers the handlers to look for classes in  
      * @param containingResource the dir or jar that the class is contained within, can be null if not known
-     * @param is
-     * @throws IOException
+     * @param is the input stream to parse
+     * @throws IOException if unable to parse
      */
     protected void scanClass (Set<? extends Handler> handlers, Resource containingResource, InputStream is)
     throws IOException
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java
index 08326f2..84905cb 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java
@@ -25,7 +25,7 @@
     /**
      * Based on the execution context, should the class represented
      * by "name" be excluded from consideration?
-     * @param name
+     * @param name the name to test
      * @return true if classname is excluded
      */
     public boolean isExcluded (String name);
@@ -35,7 +35,7 @@
      * Based on the execution context, if a duplicate class 
      * represented by "name" is detected, should the existing
      * one be overridden or not?
-     * @param name
+     * @param name the name to test
      * @return true if name should be overridden
      */
     public boolean shouldOverride (String name);
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java
index 957721e..3e3756e 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java
@@ -28,15 +28,11 @@
 
 /**
  * ContainerInitializerAnnotationHandler
- *
+ * <p>
  *  Discovers classes that contain the specified annotation, either at class or
- *  method level. The specified annotation is derived from an @HandlesTypes on
+ *  method level. The specified annotation is derived from an <code>&#064;HandlesTypes</code> on
  *  a ServletContainerInitializer class.
  */
-/**
- * @author janb
- *
- */
 public class ContainerInitializerAnnotationHandler extends AbstractHandler
 {
     final ContainerInitializer _initializer;
@@ -51,7 +47,7 @@
     /**
      * Handle finding a class that is annotated with the annotation we were constructed with.
      * 
-     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(ClassInfo, String)
+     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.ClassInfo, String)
      */
     public void handle(ClassInfo info, String annotationName)
     {
@@ -64,7 +60,7 @@
     /**
      * Handle finding a field that is annotated with the annotation we were constructed with.
      * 
-     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(FieldInfo, String)
+     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.FieldInfo, String)
      */
     public void handle(FieldInfo info, String annotationName)
     {        
@@ -76,7 +72,7 @@
     /**
      * Handle finding a method that is annotated with the annotation we were constructed with. 
      * 
-     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(MethodInfo, String)
+     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(org.eclipse.jetty.annotations.AnnotationParser.MethodInfo, String)
      */
     public void handle(MethodInfo info, String annotationName)
     {
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java
index 10cb41f..ec080a0 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/DeclareRolesAnnotationHandler.java
@@ -27,17 +27,12 @@
 
 /**
  * DeclaresRolesAnnotationHandler
- *
- *
  */
 public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotationHandler
 {
 
     protected WebAppContext _context;
 
-    /**
-     * @param context
-     */
     public DeclareRolesAnnotationHandler(WebAppContext context)
     {
         super(false);
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java
index cbd315e..69f3f81 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java
@@ -206,9 +206,12 @@
 
     /**
      * Process a Resource annotation on a Method.
-     *
+     * <p>
      * This will generate a JNDI entry, and an Injection to be
      * processed when an instance of the class is created.
+     * 
+     * @param clazz the class to process 
+     * @param method the method to process
      */
     public void handleMethod(Class<?> clazz, Method method)
     {
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
index 54602d7..458e513 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializersStarter.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.annotations;
 
 import java.util.List;
+
 import org.eclipse.jetty.plus.annotation.ContainerInitializer;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -38,9 +39,6 @@
     private static final Logger LOG = Log.getLogger(ServletContainerInitializersStarter.class);
     WebAppContext _context;
     
-    /**
-     * @param context
-     */
     public ServletContainerInitializersStarter(WebAppContext context)
     {
         _context = context;
@@ -71,6 +69,4 @@
             }
         }
     }
-    
-    
 }
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
index 940dea8..5f3fb68 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java
@@ -40,15 +40,15 @@
 /**
  * ServletSecurityAnnotationHandler
  *
- * Inspect a class to see if it has an @ServletSecurity annotation on it,
- * setting up the <security-constraint>s.
+ * Inspect a class to see if it has an <code>&#064;ServletSecurity</code> annotation on it,
+ * setting up the <code>&lt;security-constraint&gt;s</code>.
  *
  * A servlet can be defined in:
  * <ul>
- * <li>web.xml
- * <li>web-fragment.xml
- * <li>@WebServlet annotation discovered
- * <li>ServletContext.createServlet
+ * <li>web.xml</li>
+ * <li>web-fragment.xml</li>
+ * <li>@WebServlet annotation discovered</li>
+ * <li>ServletContext.createServlet</li>
  * </ul>
  *
  * The ServletSecurity annotation for a servlet should only be processed
@@ -119,12 +119,14 @@
 
 
     /**
-     * Make a jetty Constraint object, which represents the <auth-constraint> and
-     * <user-data-constraint> elements, based on the security annotation.
-     * @param servlet
-     * @param rolesAllowed
-     * @param permitOrDeny
-     * @param transport
+     * Make a jetty Constraint object, which represents the <code>&lt;auth-constraint&gt;</code> and
+     * <code>&lt;user-data-constraint&gt;</code> elements, based on the security annotation.
+     * 
+     * @param servlet the servlet
+     * @param rolesAllowed the roles allowed
+     * @param permitOrDeny the role / permission semantic
+     * @param transport the transport guarantee
+     * @return the constraint
      */
     protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
     {
@@ -135,7 +137,8 @@
 
     /**
      * Get the ServletMappings for the servlet's class.
-     * @param className
+     * @param className the class name
+     * @return the servlet mappings for the class
      */
     protected List<ServletMapping> getServletMappings(String className)
     {
@@ -154,9 +157,12 @@
 
 
     /**
-     * Check if there are already <security-constraint> elements defined that match the url-patterns for
+     * Check if there are already <code>&lt;security-constraint&gt;</code> elements defined that match the url-patterns for
      * the servlet.
-     * @param servletMappings
+     * 
+     * @param servletMappings the servlet mappings
+     * @param constraintMappings the constraint mappings
+     * @return true if constraint exists
      */
     protected boolean constraintsExist (List<ServletMapping> servletMappings, List<ConstraintMapping> constraintMappings)
     {
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java
index 3b9ae1e..a277316 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java
@@ -25,7 +25,7 @@
 import org.objectweb.asm.Type;
 
 /**
- * Util
+ * Annotation Processing Utilities
  */
 public class Util
 { 
@@ -40,7 +40,7 @@
     /**
      * Check if the presented method belongs to a class that is one
      * of the classes with which a servlet container should be concerned.
-     * @param c
+     * @param c the class
      * @return true if class is a type of one of the following: 
      *          ({@link javax.servlet.Servlet}, 
      *           {@link javax.servlet.Filter}, 
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java
index 9dbef8e..cdef8f8 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java
@@ -39,17 +39,11 @@
 
 /**
  * WebFilterAnnotation
- *
- *
  */
 public class WebFilterAnnotation extends DiscoveredAnnotation
 {
     private static final Logger LOG = Log.getLogger(WebFilterAnnotation.class);
 
-    /**
-     * @param context
-     * @param className
-     */
     public WebFilterAnnotation(WebAppContext context, String className)
     {
         super(context, className);
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java
index 8a59896..e7f372c 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java
@@ -40,17 +40,11 @@
 
 /**
  * WebListenerAnnotation
- *
- *
  */
 public class WebListenerAnnotation extends DiscoveredAnnotation
 {
     private static final Logger LOG = Log.getLogger(WebListenerAnnotation.class);
 
-    /**
-     * @param context
-     * @param className
-     */
     public WebListenerAnnotation(WebAppContext context, String className)
     {
         super(context, className);
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java
index 5dad665..9e9b7af 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java
@@ -34,10 +34,6 @@
        super(context);
     }
     
-  
-    /** 
-     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(ClassInfo, String)
-     */
     public void handle(ClassInfo info, String annotationName)
     {
         if (annotationName == null || !"javax.servlet.annotation.WebListener".equals(annotationName))
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
index cf01f5a..06caea4 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.annotations;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -54,13 +53,13 @@
     {
         super(context, className);
     }
-    
-    
+
+
     public WebServletAnnotation (WebAppContext context, String className, Resource resource)
     {
         super(context, className, resource);
     }
-    
+
     /**
      * @see DiscoveredAnnotation#apply()
      */
@@ -126,7 +125,7 @@
             }
         }
 
-        //handle creation/completion of a servlet 
+        //handle creation/completion of a servlet
         if (holder == null)
         {
             //No servlet of this name has already been defined, either by a descriptor
@@ -152,8 +151,8 @@
             }
 
             _context.getServletHandler().addServlet(holder);
-            
-            
+
+
             mapping = new ServletMapping();
             mapping.setServletName(holder.getName());
             mapping.setPathSpecs( LazyList.toStringArray(urlPatternList));
@@ -179,16 +178,16 @@
                     metaData.setOrigin(servletName+".servlet.init-param."+ip.name(),ip,clazz);
                 }
             }
-            
+
 
             //check the url-patterns
             //ServletSpec 3.0 p81 If a servlet already has url mappings from a
-            //webxml or fragment descriptor the annotation is ignored. 
-            //However, we want to be able to replace mappings that were given in webdefault.xml         
+            //webxml or fragment descriptor the annotation is ignored.
+            //However, we want to be able to replace mappings that were given in webdefault.xml
             List<ServletMapping> existingMappings = getServletMappingsForServlet(servletName);
-            
-            //if any mappings for this servlet already set by a descriptor that is not webdefault.xml forget 
-            //about processing these url mappings        
+
+            //if any mappings for this servlet already set by a descriptor that is not webdefault.xml forget
+            //about processing these url mappings
             if (existingMappings.isEmpty() || !containsNonDefaultMappings(existingMappings))
             {
                 mapping = new ServletMapping();
@@ -197,7 +196,7 @@
             }
         }
 
-        
+
         //We also want to be able to replace mappings that were defined in webdefault.xml
         //that were for a different servlet eg a mapping in webdefault.xml for / to the jetty
         //default servlet should be able to be replaced by an annotation for / to a different
@@ -209,7 +208,7 @@
             //take a copy of the existing servlet mappings that we can iterate over and remove from. This is
             //because the ServletHandler interface does not support removal of individual mappings.
             List<ServletMapping> allMappings = ArrayUtil.asMutableList(_context.getServletHandler().getServletMappings());
-            
+
             //for each of the urls in the annotation, check if a mapping to same/different servlet exists
             //  if mapping exists and is from a default descriptor, it can be replaced. NOTE: we do not
             //  guard against duplicate path mapping here: that is the job of the ServletHandler
@@ -221,11 +220,11 @@
                     String[] updatedPaths = ArrayUtil.removeFromArray(existingMapping.getPathSpecs(), p);
                     //if we removed the last path from a servletmapping, delete the servletmapping
                     if (updatedPaths == null || updatedPaths.length == 0)
-                    { 
+                    {
                         boolean success = allMappings.remove(existingMapping);
                         if (LOG.isDebugEnabled()) LOG.debug("Removed empty mapping {} from defaults descriptor success:{}",existingMapping, success);
                     }
-                    else 
+                    else
                     {
                         existingMapping.setPathSpecs(updatedPaths);
                         if (LOG.isDebugEnabled()) LOG.debug("Removed path {} from mapping {} from defaults descriptor ", p,existingMapping);
@@ -239,8 +238,8 @@
     }
 
 
-    
-    
+
+
     /**
      * @param name
      * @return
@@ -261,8 +260,8 @@
         }
         return mappings;
     }
-    
-    
+
+
     /**
      * @param mappings
      * @return
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java
index b6636a6..dca86fa 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java
@@ -29,7 +29,6 @@
  * WebServletAnnotationHandler
  *
  * Process a WebServlet annotation on a class.
- *
  */
 public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationHandler
 {
@@ -43,8 +42,6 @@
 
     /**
      * Handle discovering a WebServlet annotation.
-     *
-     * @see org.eclipse.jetty.annotations.AnnotationParser.Handler#handle(ClassInfo, String)
      */
     @Override
     public void handle(ClassInfo info, String annotationName)
diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java
index 3daaa6f..e26f856 100644
--- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java
+++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java
@@ -18,9 +18,6 @@
 
 package org.eclipse.jetty.annotations;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -34,6 +31,13 @@
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 /**
  * TestServletAnnotations
  */
@@ -56,7 +60,7 @@
             _list.add(a);
         }
     }
-    
+
     @Test
     public void testServletAnnotation() throws Exception
     {
@@ -66,9 +70,9 @@
 
         WebAppContext wac = new WebAppContext();
         List<DiscoveredAnnotation> results = new ArrayList<DiscoveredAnnotation>();
-        
+
         TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results);
-       
+
         parser.parse(Collections.singleton(handler), classes, new ClassNameResolver ()
         {
             public boolean isExcluded(String name)
@@ -82,7 +86,7 @@
             }
         });
 
-  
+
         assertEquals(1, results.size());
         assertTrue(results.get(0) instanceof WebServletAnnotation);
 
@@ -91,14 +95,14 @@
         ServletHolder[] holders = wac.getServletHandler().getServlets();
         assertNotNull(holders);
         assertEquals(1, holders.length);
-        
+
         // Verify servlet annotations
         ServletHolder cholder = holders[0];
         assertThat("Servlet Name", cholder.getName(), is("CServlet"));
         assertThat("InitParameter[x]", cholder.getInitParameter("x"), is("y"));
         assertThat("Init Order", cholder.getInitOrder(), is(2));
         assertThat("Async Supported", cholder.isAsyncSupported(), is(false));
-        
+
         // Verify mappings
         ServletMapping[] mappings = wac.getServletHandler().getServletMappings();
         assertNotNull(mappings);
@@ -107,33 +111,33 @@
         assertNotNull(paths);
         assertEquals(2, paths.length);
     }
-    
-    
+
+
     @Test
     public void testWebServletAnnotationOverrideDefault () throws Exception
     {
         //if the existing servlet mapping TO A DIFFERENT SERVLET IS from a default descriptor we
         //DO allow the annotation to replace the mapping.
-        
+
         WebAppContext wac = new WebAppContext();
         ServletHolder defaultServlet = new ServletHolder();
         defaultServlet.setClassName("org.eclipse.jetty.servlet.DefaultServlet");
-        defaultServlet.setName("default");      
+        defaultServlet.setName("default");
         wac.getServletHandler().addServlet(defaultServlet);
-        
+
         ServletMapping m = new ServletMapping();
         m.setPathSpec("/");
         m.setServletName("default");
         m.setDefault(true);  //this mapping will be from a default descriptor
         wac.getServletHandler().addServletMapping(m);
-        
+
         WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null);
         annotation.apply();
-        
+
         //test that as the original servlet mapping had only 1 pathspec, then the whole
         //servlet mapping should be deleted as that pathspec will be remapped to the DServlet
         ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings();
-        assertNotNull(resultMappings);    
+        assertNotNull(resultMappings);
         assertEquals(1, resultMappings.length);
         assertEquals(2, resultMappings[0].getPathSpecs().length);
         resultMappings[0].getServletName().equals("DServlet");
@@ -142,38 +146,38 @@
             assertTrue (s.equals("/") || s.equals("/bah/*"));
         }
     }
-    
-    
-    
+
+
+
     @Test
     public void testWebServletAnnotationReplaceDefault () throws Exception
     {
         //if the existing servlet mapping TO A DIFFERENT SERVLET IS from a default descriptor we
-        //DO allow the annotation to replace the mapping.    
+        //DO allow the annotation to replace the mapping.
         WebAppContext wac = new WebAppContext();
         ServletHolder defaultServlet = new ServletHolder();
         defaultServlet.setClassName("org.eclipse.jetty.servlet.DefaultServlet");
-        defaultServlet.setName("default");      
+        defaultServlet.setName("default");
         wac.getServletHandler().addServlet(defaultServlet);
-        
+
         ServletMapping m = new ServletMapping();
         m.setPathSpec("/");
         m.setServletName("default");
         m.setDefault(true);  //this mapping will be from a default descriptor
         wac.getServletHandler().addServletMapping(m);
-        
+
         ServletMapping m2 = new ServletMapping();
         m2.setPathSpec("/other");
         m2.setServletName("default");
         m2.setDefault(true);  //this mapping will be from a default descriptor
         wac.getServletHandler().addServletMapping(m2);
-        
+
         WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null);
         annotation.apply();
-        
+
         //test that only the mapping for "/" was removed from the mappings to the default servlet
         ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings();
-        assertNotNull(resultMappings);    
+        assertNotNull(resultMappings);
         assertEquals(2, resultMappings.length);
         for (ServletMapping r:resultMappings)
         {
@@ -194,10 +198,10 @@
            else
                fail("Unexpected servlet mapping");
         }
-        
+
     }
-    
-    
+
+
     @Test
     public void testWebServletAnnotationNotOverride () throws Exception
     {
@@ -232,7 +236,7 @@
                 fail("Unexpected servlet name");
         }
     }
-    
+
     @Test
     public void testWebServletAnnotationIgnore () throws Exception
     {
@@ -243,33 +247,33 @@
         servlet.setClassName("org.eclipse.jetty.servlet.OtherDServlet");
         servlet.setName("DServlet");
         wac.getServletHandler().addServlet(servlet);
-        
+
         ServletMapping m = new ServletMapping();
         m.setPathSpec("/default");
         m.setDefault(true);
         m.setServletName("DServlet");
         wac.getServletHandler().addServletMapping(m);
-        
+
         ServletMapping m2 = new ServletMapping();
         m2.setPathSpec("/other");
         m2.setServletName("DServlet");
         wac.getServletHandler().addServletMapping(m2);
-        
+
         WebServletAnnotation annotation = new WebServletAnnotation(wac, "org.eclipse.jetty.annotations.ServletD", null);
         annotation.apply();
 
         ServletMapping[] resultMappings = wac.getServletHandler().getServletMappings();
         assertEquals(2, resultMappings.length);
-        
+
         for (ServletMapping r:resultMappings)
         {
             assertEquals(1, r.getPathSpecs().length);
             if (!r.getPathSpecs()[0].equals("/default") && !r.getPathSpecs()[0].equals("/other"))
                 fail("Unexpected path in mapping");
         }
-        
+
     }
-    
+
     @Test
     public void testWebServletAnnotationNoMappings () throws Exception
     {
@@ -293,8 +297,8 @@
                 fail("Unexpected path mapping");
         }
     }
-    
-    
+
+
 
     @Test
     public void testDeclareRoles ()
diff --git a/jetty-ant/pom.xml b/jetty-ant/pom.xml
index b8bf8db..e9160bf 100644
--- a/jetty-ant/pom.xml
+++ b/jetty-ant/pom.xml
@@ -2,13 +2,16 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-ant</artifactId>
   <packaging>jar</packaging>
   <name>Jetty :: Ant Plugin</name>
  
+  <properties>
+    <bundle-symbolic-name>org.eclipse.jetty.ant</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -22,8 +25,8 @@
             </goals>
             <configuration>
               <includeGroupIds>org.eclipse.jetty</includeGroupIds>
-              <excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.drafts</excludeGroupIds>
-              <excludeArtifactIds>jetty-all,jetty-start,jetty-monitor,jetty-jsp</excludeArtifactIds>
+              <excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.websocket,org.eclipse.jetty.drafts</excludeGroupIds>
+              <excludeArtifactIds>jetty-all,jetty-start,jetty-monitor</excludeArtifactIds>
               <includeTypes>jar</includeTypes>
               <outputDirectory>${project.build.directory}/test-lib</outputDirectory>
             </configuration>
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java
index a8752b3..7512581 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/AntWebAppContext.java
@@ -16,7 +16,6 @@
 //  ========================================================================
 //
 
-
 package org.eclipse.jetty.ant;
 
 import java.io.File;
@@ -67,13 +66,8 @@
 import org.eclipse.jetty.webapp.WebXmlConfiguration;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
-
-
 /**
- * AntWebAppContext
- * 
  * Extension of WebAppContext to allow configuration via Ant environment.
- *
  */
 public class AntWebAppContext extends WebAppContext
 {
@@ -432,6 +426,7 @@
      * Default constructor. Takes project as an argument
      *
      * @param project the project.
+     * @throws Exception if unable to create webapp context
      */
     public AntWebAppContext(Project project) throws Exception
     {
@@ -445,6 +440,7 @@
 
     /**
      * Adds a new Ant's attributes tag object if it have not been created yet.
+     * @param atts the attributes
      */
     public void addAttributes(Attributes atts)
     {
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java
index 626ea4d..cc2cb49 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/JettyRunTask.java
@@ -41,10 +41,8 @@
  */
 public class JettyRunTask extends Task
 {
-
     private int scanIntervalSeconds; 
     
-    
     /** Temporary files directory. */
     private File tempDirectory;
 
@@ -79,9 +77,6 @@
 
     private boolean daemon;
     
-  
-
-
     public JettyRunTask()
     {
         TaskLog.setTask(this);
@@ -89,17 +84,16 @@
 
     /**
      * Creates a new <code>WebApp</code> Ant object.
-     *
+     * @param webapp the webapp context 
      */
     public void addWebApp(AntWebAppContext webapp)
     {
        webapps.add(webapp);
     }
-    
-    
 
     /**
      * Adds a new Ant's connector tag object if it have not been created yet.
+     * @param connectors the connectors 
      */
     public void addConnectors(Connectors connectors)
     {
@@ -108,10 +102,6 @@
         this.connectors = connectors;
     }
 
-
-    /**
-     * @param services
-     */
     public void addLoginServices(LoginServices services)
     {        
         if (this.loginServices != null )
@@ -126,9 +116,6 @@
         this.systemProperties = systemProperties;
     }
     
-    /**
-     * @param handlers
-     */
     public void addContextHandlers (ContextHandlers handlers)
     {
         if (this.contextHandlers != null)
@@ -141,9 +128,6 @@
         return tempDirectory;
     }
 
-    /**
-     * @param tempDirectory
-     */
     public void setTempDirectory(File tempDirectory)
     {
         this.tempDirectory = tempDirectory;
@@ -154,17 +138,11 @@
         return jettyXml;
     }
 
-    /**
-     * @param jettyXml
-     */
     public void setJettyXml(File jettyXml)
     {
         this.jettyXml = jettyXml;
     }
 
-    /**
-     * @param className
-     */
     public void setRequestLog(String className)
     {
         try
@@ -209,7 +187,7 @@
      * Executes this Ant task. The build flow is being stopped until Jetty
      * server stops.
      *
-     * @throws BuildException
+     * @throws BuildException if unable to build
      */
     public void execute() throws BuildException
     {
@@ -297,17 +275,12 @@
         return scanIntervalSeconds;
     }
 
-    /**
-     * @param secs
-     */
     public void setScanIntervalSeconds(int secs)
     {
         scanIntervalSeconds = secs;
         TaskLog.log("scanIntervalSecs="+secs);
     }
     
-
-    
     /**
      * Sets the system properties.
      */
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java
index 9c425e1..6b25db1 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/Connectors.java
@@ -23,11 +23,7 @@
 import java.util.List;
 
 /**
- * 
- * Connectors
- * 
- * Specifies a jetty configuration <connectors/> element for Ant build file.
- *
+ * Specifies a jetty configuration <code>&lt;connectors/&gt;</code> element for Ant build file.
  */
 public class Connectors
 {
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java
index bfbf49d..0c25058 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/ContextHandlers.java
@@ -25,8 +25,7 @@
 import org.eclipse.jetty.server.handler.ContextHandler;
 
 /**
- * Specifies <contextHandlers/> element in web app configuration.
- * 
+ * Specifies <code>&lt;contextHandlers/&gt;</code> element in web app configuration.
  */
 public class ContextHandlers
 {
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java
index 5576780..73749f9 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/FileMatchingConfiguration.java
@@ -27,10 +27,9 @@
 import org.apache.tools.ant.DirectoryScanner;
 
 /**
- * Describes set of files matched by <fileset/> elements in ant configuration
+ * Describes set of files matched by <code>&lt;fileset/&gt;</code> elements in ant configuration
  * file. It is used to group application classes, libraries, and scannedTargets
  * elements.
- * 
  */
 public class FileMatchingConfiguration
 {
@@ -44,7 +43,7 @@
 
     /**
      * @param directoryScanner new directory scanner retrieved from the
-     *            <fileset/> element.
+     *            <code>&lt;fileset/&gt;</code> element.
      */
     public void addDirectoryScanner(DirectoryScanner directoryScanner)
     {
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java
index f83a1d7..867f99b 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/LoginServices.java
@@ -25,14 +25,10 @@
 import org.eclipse.jetty.security.LoginService;
 
 /**
- * LoginServices
- * 
- * Specifies a jetty configuration <loginServices/> element for Ant build file.
- *
+ * Specifies a jetty configuration &lt;loginServices/&gt; element for Ant build file.
  */
 public class LoginServices
 {
-
     private List<LoginService> loginServices = new ArrayList<LoginService>();
 
     public void add(LoginService service)
diff --git a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java
index 72bed64..3e2b38b 100644
--- a/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java
+++ b/jetty-ant/src/main/java/org/eclipse/jetty/ant/types/SystemProperties.java
@@ -27,9 +27,8 @@
 
 /**
  * SystemProperties
- * 
- * Ant <systemProperties/> tag definition.
- * 
+ * <p> 
+ * Ant &lt;systemProperties/&gt; tag definition.
  */
 public class SystemProperties
 {
@@ -48,8 +47,8 @@
 
     /**
      * Set a System.property with this value if it is not already set.
-     * 
-     * @returns true if property has been set
+     * @param property the property to test 
+     * @return true if property has been set
      */
     public static boolean setIfNotSetAlready(Property property)
     {
diff --git a/jetty-cdi/cdi-core/pom.xml b/jetty-cdi/cdi-core/pom.xml
new file mode 100644
index 0000000..4ba4e5f
--- /dev/null
+++ b/jetty-cdi/cdi-core/pom.xml
@@ -0,0 +1,71 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cdi-core</artifactId>
+  <name>Jetty :: CDI :: Core</name>
+  <description>
+    Core CDI routines for Jetty (Also useful for CDI/SE applications that dont need a server)
+  </description>
+  <url>http://www.eclipse.org/jetty</url>
+  <packaging>jar</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>javax.enterprise</groupId>
+       <artifactId>cdi-api</artifactId>
+       <version>1.2</version>
+       <exclusions>
+         <exclusion>
+           <groupId>javax.el</groupId>
+           <artifactId>javax.el-api</artifactId>
+         </exclusion>
+       </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.weld</groupId>
+      <artifactId>weld-core</artifactId>
+      <version>${weld.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.weld.se</groupId>
+      <artifactId>weld-se-core</artifactId>
+      <version>${weld.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>tests-jar</id>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java
new file mode 100644
index 0000000..63889c7
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/AnyLiteral.java
@@ -0,0 +1,28 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.util.AnnotationLiteral;
+
+@SuppressWarnings("serial")
+public class AnyLiteral extends AnnotationLiteral<Any>
+{
+    public static final AnyLiteral INSTANCE = new AnyLiteral();
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java
new file mode 100644
index 0000000..0eb9868
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/JettyLogFactory.java
@@ -0,0 +1,37 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * CDI Producer of Jetty Logging instances.
+ */
+public class JettyLogFactory
+{
+    @Produces
+    public Logger createLogger(InjectionPoint injectionPoint)
+    {
+        return Log.getLogger(injectionPoint.getMember().getDeclaringClass());
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java
new file mode 100644
index 0000000..103fa91
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/NamedLiteral.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Named;
+
+@SuppressWarnings("serial")
+public class NamedLiteral extends AnnotationLiteral<Named> implements Named
+{
+    private final String value;
+
+    public String value()
+    {
+        return value;
+    }
+
+    public NamedLiteral(String name)
+    {
+        if (name == null)
+        {
+            this.value = "";
+        }
+        else
+        {
+            this.value = name;
+        }
+    }
+}
\ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java
new file mode 100644
index 0000000..e12e364
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/ScopedInstance.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+
+public class ScopedInstance<T>
+{
+    public Bean<T> bean;
+    public CreationalContext<T> creationalContext;
+    public T instance;
+
+    public void destroy()
+    {
+        bean.destroy(instance,creationalContext);
+    }
+    
+    @Override
+    public String toString()
+    {
+        StringBuilder s = new StringBuilder();
+        s.append("ScopedInstance[");
+        s.append(bean);
+        s.append(',').append(creationalContext);
+        s.append(']');
+        return s.toString();
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java
new file mode 100644
index 0000000..de59f93
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/java/org/eclipse/jetty/cdi/core/SimpleBeanStore.java
@@ -0,0 +1,94 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.context.spi.Contextual;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class SimpleBeanStore
+{
+    private static final Logger LOG = Log.getLogger(SimpleBeanStore.class);
+
+    public Map<Contextual<?>, List<ScopedInstance<?>>> beans = new HashMap<>();
+
+    public void addBean(ScopedInstance<?> instance)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("addBean({})",instance);
+        }
+        List<ScopedInstance<?>> instances = getBeans(instance.bean);
+        if (instances == null)
+        {
+            instances = new ArrayList<>();
+            beans.put(instance.bean,instances);
+        }
+        instances.add(instance);
+    }
+
+    public void clear()
+    {
+        beans.clear();
+    }
+
+    public void destroy()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("destroy() - {} beans",beans.size());
+        }
+        for (List<ScopedInstance<?>> instances : beans.values())
+        {
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("destroying - {} instance(s)",instances.size());
+            }
+            for (ScopedInstance<?> instance : instances)
+            {
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("destroying instance {}",instance);
+                }
+                instance.destroy();
+            }
+        }
+    }
+
+    public List<ScopedInstance<?>> getBeans(Contextual<?> contextual)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("getBeans({})",contextual);
+        }
+        return beans.get(contextual);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%X[size=%d]",this.getClass().getSimpleName(),hashCode(),beans.size());
+    }
+}
\ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..f158a71
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
+        http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="all">
+</beans>
\ No newline at end of file
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java
new file mode 100644
index 0000000..e93ceaf
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/AbstractWeldTest.java
@@ -0,0 +1,78 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core;
+
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public abstract class AbstractWeldTest
+{
+    public static class TestBean<T>
+    {
+        public Bean<T> bean;
+        public CreationalContext<T> cCtx;
+        public T instance;
+
+        public void destroy()
+        {
+            bean.destroy(instance,cCtx);
+        }
+    }
+
+    @BeforeClass
+    public static void initWeld()
+    {
+        weld = new Weld();
+        container = weld.initialize();
+    }
+
+    @AfterClass
+    public static void shutdownWeld()
+    {
+        weld.shutdown();
+    }
+
+    private static WeldContainer container;
+    private static Weld weld;
+
+    @SuppressWarnings("unchecked")
+    public <T> TestBean<T> newInstance(Class<T> clazz) throws Exception
+    {
+        TestBean<T> testBean = new TestBean<>();
+        Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.size() > 0)
+        {
+            testBean.bean = (Bean<T>)beans.iterator().next();
+            testBean.cCtx = container.getBeanManager().createCreationalContext(testBean.bean);
+            testBean.instance = (T)container.getBeanManager().getReference(testBean.bean,clazz,testBean.cCtx);
+            return testBean;
+        }
+        else
+        {
+            throw new Exception(String.format("Can't find class %s",clazz));
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java
new file mode 100644
index 0000000..6114cf1
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LeanConsoleHandler.java
@@ -0,0 +1,112 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core.logging;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.regex.Pattern;
+
+public class LeanConsoleHandler extends Handler
+{
+    public static Handler createWithLevel(Level level)
+    {
+        LeanConsoleHandler handler = new LeanConsoleHandler();
+        handler.setLevel(level);
+        return handler;
+    }
+
+    @Override
+    public void close() throws SecurityException
+    {
+        /* nothing to do here */
+    }
+
+    @Override
+    public void flush()
+    {
+        /* nothing to do here */
+    }
+
+    public synchronized String formatMessage(LogRecord record)
+    {
+        String msg = getMessage(record);
+
+        try
+        {
+            Object params[] = record.getParameters();
+            if ((params == null) || (params.length == 0))
+            {
+                return msg;
+            }
+
+            if (Pattern.compile("\\{\\d+\\}").matcher(msg).find())
+            {
+                return MessageFormat.format(msg,params);
+            }
+
+            return msg;
+        }
+        catch (Exception ex)
+        {
+            return msg;
+        }
+    }
+
+    private String getMessage(LogRecord record)
+    {
+        ResourceBundle bundle = record.getResourceBundle();
+        if (bundle != null)
+        {
+            try
+            {
+                return bundle.getString(record.getMessage());
+            }
+            catch (java.util.MissingResourceException ex)
+            {
+            }
+        }
+
+        return record.getMessage();
+    }
+
+    @Override
+    public void publish(LogRecord record)
+    {
+        StringBuilder buf = new StringBuilder();
+        buf.append("[").append(record.getLevel().getName()).append("] ");
+        String logname = record.getLoggerName();
+        int idx = logname.lastIndexOf('.');
+        if (idx > 0)
+        {
+            logname = logname.substring(idx + 1);
+        }
+        buf.append(logname);
+        buf.append(": ");
+        buf.append(formatMessage(record));
+
+        System.out.println(buf.toString());
+        if (record.getThrown() != null)
+        {
+            record.getThrown().printStackTrace(System.out);
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java
new file mode 100644
index 0000000..4671f99
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/LogFactory.java
@@ -0,0 +1,33 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core.logging;
+
+import java.util.logging.Logger;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+public class LogFactory
+{
+    @Produces
+    public Logger createLogger(InjectionPoint injectionPoint)
+    {
+        return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java
new file mode 100644
index 0000000..44324ce
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/java/org/eclipse/jetty/cdi/core/logging/Logging.java
@@ -0,0 +1,46 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.core.logging;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.LogManager;
+
+public class Logging
+{
+    public static void config()
+    {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        URL url = cl.getResource("logging.properties");
+        if (url != null)
+        {
+            try (InputStream in = url.openStream())
+            {
+                LogManager.getLogManager().readConfiguration(in);
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace(System.err);
+            }
+        }
+
+        System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.Jdk14Logger");
+    }
+}
diff --git a/jetty-cdi/cdi-core/src/test/resources/logging.properties b/jetty-cdi/cdi-core/src/test/resources/logging.properties
new file mode 100644
index 0000000..c0ff63e
--- /dev/null
+++ b/jetty-cdi/cdi-core/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.cdi.core.logging.LeanConsoleHandler
+.level=INFO
diff --git a/jetty-cdi/cdi-full-servlet/pom.xml b/jetty-cdi/cdi-full-servlet/pom.xml
new file mode 100644
index 0000000..0c4ef63
--- /dev/null
+++ b/jetty-cdi/cdi-full-servlet/pom.xml
@@ -0,0 +1,53 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cdi-full-servlet</artifactId>
+  <name>Jetty :: CDI :: Dependencies</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <packaging>pom</packaging>
+  <properties>
+    <weld.version>2.2.9.Final</weld.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-servlet</artifactId>
+      <version>${project.version}</version>
+<!--
+      <exclusions>
+        <exclusion>
+          <groupId>javax.el</groupId>
+          <artifactId>javax.el-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.el</groupId>
+          <artifactId>jboss-el-api_3.0_spec</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.annotation</groupId>
+          <artifactId>jboss-annotations-api_1.2_spec</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.interceptor</groupId>
+          <artifactId>jboss-interceptors-api_1.2_spec</artifactId>
+        </exclusion>
+      </exclusions>
+-->
+    </dependency>
+    <dependency>
+       <groupId>javax.annotation</groupId>
+       <artifactId>javax.annotation-api</artifactId>
+       <version>1.2</version>
+    </dependency>
+    <dependency>
+       <groupId>org.mortbay.jasper</groupId>
+       <artifactId>apache-jsp</artifactId>
+       <version>${jsp.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/jetty-cdi/cdi-servlet/pom.xml b/jetty-cdi/cdi-servlet/pom.xml
new file mode 100644
index 0000000..da05a98
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/pom.xml
@@ -0,0 +1,90 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cdi-servlet</artifactId>
+  <name>Jetty :: CDI :: Servlet</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <packaging>jar</packaging>
+  <properties>
+    <weld.version>2.2.9.Final</weld.version>
+    <bundle-symbolic-name>${project.groupId}.servlet</bundle-symbolic-name>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptorRefs>
+                <descriptorRef>config</descriptorRef>
+              </descriptorRefs>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-plus</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-deploy</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.weld.servlet</groupId>
+      <artifactId>weld-servlet-core</artifactId>
+      <version>${weld.version}</version>
+      <exclusions>
+        <exclusion>
+          <groupId>javax.el</groupId>
+          <artifactId>javax.el-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.el</groupId>
+          <artifactId>jboss-el-api_3.0_spec</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.annotation</groupId>
+          <artifactId>jboss-annotations-api_1.2_spec</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.jboss.spec.javax.interceptor</groupId>
+          <artifactId>jboss-interceptors-api_1.2_spec</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <!-- below here lie testing dragons -->
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>apache-jsp</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml b/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml
new file mode 100644
index 0000000..79ebdae
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/config/etc/jetty-cdi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- =============================================================== -->
+<!-- Mixin the Weld / CDI classes to the class loader                -->
+<!-- =============================================================== -->
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+  <Ref refid="DeploymentManager">
+    <Call name="addLifeCycleBinding">
+      <Arg>
+        <New
+          class="org.eclipse.jetty.cdi.servlet.WeldDeploymentBinding">
+        </New>
+      </Arg>
+    </Call>
+  </Ref>
+</Configure>
+
diff --git a/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod b/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod
new file mode 100644
index 0000000..ebffb55
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/config/modules/cdi.mod
@@ -0,0 +1,38 @@
+#
+# [EXPERIMENTAL] CDI / Weld Jetty module
+#
+
+[depend]
+deploy
+annotations
+plus
+# JSP (and EL) are requirements for CDI and Weld
+jsp
+
+[files]
+lib/cdi/
+maven://javax.enterprise/cdi-api/1.2|lib/cdi/javax.enterprise.cdi-api-1.2.jar
+maven://javax.interceptor/javax.interceptor-api/1.2|lib/cdi/javax.interceptor-api-1.2.jar
+maven://javax.inject/javax.inject/1|lib/cdi/javax.inject-1.0.jar
+maven://org.jboss.weld.servlet/weld-servlet-core/2.2.9.Final|lib/cdi/weld-servlet-core-2.2.9.Final.jar
+maven://org.jboss.weld.environment/weld-environment-common/2.2.9.Final|lib/cdi/weld-environment-common-2.2.9.Final.jar
+maven://org.jboss.weld/weld-core-impl/2.2.9.Final|lib/cdi/weld-core-impl-2.2.9.Final.jar
+maven://org.jboss.classfilewriter/jboss-classfilewriter/1.0.5.Final|lib/cdi/jboss-classfilewriter-1.0.5.Final.jar
+maven://com.google.guava/guava/13.0.1|lib/cdi/com.google.guava.guava-13.0.1.jar
+maven://org.jboss.weld/weld-spi/2.2.SP3|lib/cdi/weld-spi-2.2.SP3.jar
+maven://org.jboss.weld/weld-api/2.2.SP3|lib/cdi/weld-api-2.2.SP3.jar
+maven://org.jboss.logging/jboss-logging/3.1.3.GA|lib/cdi/jboss-logging-3.1.3.GA.jar
+
+
+[lib]
+lib/cdi/*.jar
+lib/cdi-core-${jetty.version}.jar
+lib/cdi-servlet-${jetty.version}.jar
+
+[xml]
+etc/jetty-cdi.xml
+
+[license]
+Weld is an open source project hosted on Github and released under the Apache 2.0 license.
+http://weld.cdi-spec.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java
new file mode 100644
index 0000000..5e8b374
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/EmbeddedCdiHandler.java
@@ -0,0 +1,131 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.jboss.weld.environment.servlet.EnhancedListener;
+
+/**
+ * Handy {@link ServletContextHandler} implementation that hooks up
+ * all of the various CDI related components and listeners from Weld.
+ */
+public class EmbeddedCdiHandler extends ServletContextHandler
+{
+    private static final Logger LOG = Log.getLogger(EmbeddedCdiHandler.class);
+    
+    private static final String[] REQUIRED_BEANS_XML_PATHS = new String[] { 
+        "/WEB-INF/beans.xml", 
+        "/META-INF/beans.xml", 
+        "/WEB-INF/classes/META-INF/beans.xml" 
+    };
+
+    public EmbeddedCdiHandler()
+    {
+        super();
+    }
+
+    public EmbeddedCdiHandler(int options)
+    {
+        super(options);
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        // Required of CDI
+        Resource baseResource = getBaseResource();
+        if (baseResource == null)
+        {
+            throw new NullPointerException("baseResource must be set (to so it can find the beans.xml)");
+        }
+        
+        boolean foundBeansXml = false;
+
+        // Verify that beans.xml is present, otherwise weld will fail silently.
+        for(String beansXmlPath: REQUIRED_BEANS_XML_PATHS) {
+            Resource res = baseResource.addPath(beansXmlPath);
+            if (res == null)
+            {
+                // not found, skip it
+                continue;
+            }
+            
+            if (res.exists())
+            {
+                foundBeansXml = true;
+            }
+
+            if (res.isDirectory())
+            {
+                throw new IOException("Directory conflicts with expected file: " + res.getURI().toASCIIString());
+            }
+        }
+        
+        if (!foundBeansXml)
+        {
+            StringBuilder err = new StringBuilder();
+            err.append("Unable to find required beans.xml from the baseResource: ");
+            err.append(baseResource.getURI().toASCIIString()).append(System.lineSeparator());
+            err.append("Searched for: ");
+            for (String beansXmlPath : REQUIRED_BEANS_XML_PATHS)
+            {
+                err.append(System.lineSeparator());
+                err.append("  ").append(beansXmlPath);
+            }
+            LOG.warn("ERROR: {}",err.toString());
+            throw new IOException(err.toString());
+        }
+
+        // Initialize Weld
+        JettyWeldInitializer.initContext(this);
+
+        // Wire up Weld (what's usually done via the ServletContainerInitializer)
+        ServletContext ctx = getServletContext();
+        
+        // Fake the call to ServletContainerInitializer
+        ClassLoader orig = Thread.currentThread().getContextClassLoader();
+        try
+        {
+            Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
+            
+            EnhancedListener weldListener = new EnhancedListener();
+            Set<Class<?>> classes = Collections.emptySet();
+            weldListener.onStartup(classes,ctx);
+            
+            // add the rest of the Weld Listeners
+            ctx.addListener(weldListener);
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(orig);
+        }
+
+        // Let normal ServletContextHandler startup continue its merry way
+        super.doStart();
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java
new file mode 100644
index 0000000..e7c6a00
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/JettyWeldInitializer.java
@@ -0,0 +1,77 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+
+import org.eclipse.jetty.plus.jndi.Resource;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * Utility class suitable for initializing CDI/Weld on Embedded Jetty
+ */
+public class JettyWeldInitializer
+{
+    /**
+     * Initialize WebAppContext to support CDI/Weld.
+     * <p>
+     * Initializes Context, then sets up WebAppContext system and server classes to allow Weld to operate from Server
+     * level.
+     * <p>
+     * Includes {@link #initContext(ContextHandler)} behavior as well.
+     * @param webapp the webapp
+     * @throws NamingException if unable to bind BeanManager context
+     */
+    public static void initWebApp(WebAppContext webapp) throws NamingException
+    {
+        initContext(webapp);
+
+        // webapp cannot change / replace weld classes
+        webapp.addSystemClass("org.jboss.weld.");
+        webapp.addSystemClass("org.jboss.classfilewriter.");
+        webapp.addSystemClass("org.jboss.logging.");
+        webapp.addSystemClass("com.google.common.");
+        webapp.addSystemClass("org.eclipse.jetty.cdi.websocket.annotation.");
+        
+
+        // don't hide weld classes from webapps (allow webapp to use ones from system classloader)
+        webapp.prependServerClass("-org.eclipse.jetty.cdi.websocket.annotation.");
+        webapp.prependServerClass("-org.eclipse.jetty.cdi.core.");
+        webapp.prependServerClass("-org.eclipse.jetty.cdi.servlet.");
+        webapp.addServerClass("-org.jboss.weld.");
+        webapp.addServerClass("-org.jboss.classfilewriter.");
+        webapp.addServerClass("-org.jboss.logging.");
+        webapp.addServerClass("-com.google.common.");
+    
+    }
+
+    public static void initContext(ContextHandler handler) throws NamingException
+    {
+        // Add context specific weld container reference.
+        // See https://issues.jboss.org/browse/WELD-1710
+        // and https://github.com/weld/core/blob/2.2.5.Final/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java#L244-L253
+        handler.setInitParameter("org.jboss.weld.environment.container.class","org.jboss.weld.environment.jetty.JettyContainer");
+
+        // Setup Weld BeanManager reference
+        Reference ref = new Reference("javax.enterprise.inject.spi.BeanManager","org.jboss.weld.resources.ManagerObjectFactory",null);
+        new Resource(handler,"BeanManager",ref);
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java
new file mode 100644
index 0000000..a2ddabf
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/main/java/org/eclipse/jetty/cdi/servlet/WeldDeploymentBinding.java
@@ -0,0 +1,57 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.AppLifeCycle;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * Perform some basic weld configuration of WebAppContext
+ */
+public class WeldDeploymentBinding implements AppLifeCycle.Binding
+{
+    public String[] getBindingTargets()
+    {
+        return new String[] { "deploying" };
+    }
+
+    public void processBinding(Node node, App app) throws Exception
+    {
+        ContextHandler handler = app.getContextHandler();
+        if (handler == null)
+        {
+            throw new NullPointerException("No Handler created for App: " + app);
+        }
+
+        if (handler instanceof WebAppContext)
+        {
+            // Do webapp specific init
+            WebAppContext webapp = (WebAppContext)handler;
+            JettyWeldInitializer.initWebApp(webapp);
+        }
+        else
+        {
+            // Do general init
+            JettyWeldInitializer.initContext(handler);
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java
new file mode 100644
index 0000000..3baeac6
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/Dumper.java
@@ -0,0 +1,27 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public interface Dumper
+{
+    public void dump(PrintWriter out) throws IOException;
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java
new file mode 100644
index 0000000..d2d64cd
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/IsoTimeFormatter.java
@@ -0,0 +1,39 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.inject.Named;
+
+@Named("iso")
+public class IsoTimeFormatter implements TimeFormatter
+{
+    @Override
+    public String format(Calendar cal)
+    {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",Locale.US);
+        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+        return dateFormat.format(cal.getTime());
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java
new file mode 100644
index 0000000..207992c
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/LocaleTimeFormatter.java
@@ -0,0 +1,38 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import javax.enterprise.inject.Default;
+import javax.inject.Named;
+
+@Named("locale")
+@Default
+public class LocaleTimeFormatter implements TimeFormatter
+{
+    public static final TimeFormatter INSTANCE = new LocaleTimeFormatter();
+
+    @Override
+    public String format(Calendar cal)
+    {
+        return new SimpleDateFormat().format(cal.getTime());
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java
new file mode 100644
index 0000000..82d2454
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestInfoServlet.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.cdi.core.NamedLiteral;
+
+@SuppressWarnings("serial")
+@WebServlet("/req-info")
+public class RequestInfoServlet extends HttpServlet
+{
+    @Inject
+    @Any
+    private Instance<Dumper> dumpers;
+    
+    @Inject
+    @Named("params")
+    private Dumper defaultDumper;
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+    {
+        resp.setContentType("text/plain");
+        PrintWriter out = resp.getWriter();
+        
+        Dumper dumper = defaultDumper;
+        
+        String dumperId = req.getParameter("dumperId");
+        
+        if (dumperId != null)
+        {
+            Instance<Dumper> inst = dumpers.select(new NamedLiteral(dumperId));
+            if (!inst.isAmbiguous() && !inst.isUnsatisfied())
+            {
+                dumper = inst.get();
+            }
+        }
+        
+        dumper.dump(out);
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java
new file mode 100644
index 0000000..19c76d2
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/RequestParamsDumper.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.http.HttpServletRequest;
+
+@Named("params")
+@RequestScoped
+public class RequestParamsDumper implements Dumper
+{
+    @Inject
+    private HttpServletRequest request;
+
+    @Override
+    public void dump(PrintWriter out) throws IOException
+    {
+        out.printf("request is %s%n",request == null ? "NULL" : "PRESENT");
+
+        if (request != null)
+        {
+            Map<String, String[]> params = request.getParameterMap();
+            List<String> paramNames = new ArrayList<>();
+            paramNames.addAll(params.keySet());
+            Collections.sort(paramNames);
+
+            out.printf("parameters.size = [%d]%n",params.size());
+
+            for (String name : paramNames)
+            {
+                out.printf(" param[%s] = [",name);
+                boolean delim = false;
+                for (String val : params.get(name))
+                {
+                    if (delim)
+                    {
+                        out.print(", ");
+                    }
+                    out.print(val);
+                    delim = true;
+                }
+                out.println("]");
+            }
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java
new file mode 100644
index 0000000..a5f1b64
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeFormatter.java
@@ -0,0 +1,26 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.util.Calendar;
+
+public interface TimeFormatter
+{
+    public String format(Calendar cal);
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java
new file mode 100644
index 0000000..50e4806
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/TimeServlet.java
@@ -0,0 +1,59 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import java.io.IOException;
+import java.util.Calendar;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.cdi.core.NamedLiteral;
+
+@SuppressWarnings("serial")
+@WebServlet(urlPatterns = "/time")
+public class TimeServlet extends HttpServlet
+{
+    @Inject
+    @Any
+    Instance<TimeFormatter> formatters;
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+    {
+        resp.setContentType("text/plain");
+
+        String timeType = req.getParameter("type");
+        TimeFormatter time = LocaleTimeFormatter.INSTANCE;
+
+        Instance<TimeFormatter> inst = formatters.select(new NamedLiteral(timeType));
+        if (!inst.isAmbiguous() && !inst.isUnsatisfied())
+        {
+            time = inst.get();
+        }
+
+        resp.getWriter().println(time.format(Calendar.getInstance()));
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java
new file mode 100644
index 0000000..32ff575
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/java/org/eclipse/jetty/cdi/servlet/WeldInitializationTest.java
@@ -0,0 +1,115 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.servlet;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.net.URI;
+
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WeldInitializationTest
+{
+    private static final Logger LOG = Log.getLogger(WeldInitializationTest.class);
+    private static Server server;
+    private static URI serverHttpURI;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        JettyLogHandler.config();
+
+        server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+
+        File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+        context.setBaseResource(Resource.newResource(baseDir));
+        context.setContextPath("/");
+        server.setHandler(context);
+
+        // Add some servlets
+        context.addServlet(TimeServlet.class,"/time");
+        context.addServlet(RequestInfoServlet.class,"/req-info");
+
+        server.start();
+
+        String host = connector.getHost();
+        if (host == null)
+        {
+            host = "localhost";
+        }
+        int port = connector.getLocalPort();
+        serverHttpURI = new URI(String.format("http://%s:%d/",host,port));
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        try
+        {
+            server.stop();
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+    }
+
+    @Test
+    public void testRequestParamServletDefault() throws Exception
+    {
+        SimpleRequest req = new SimpleRequest(serverHttpURI);
+        String resp = req.getString("req-info");
+
+        System.out.println(resp);
+
+        assertThat("Response",resp,containsString("request is PRESENT"));
+        assertThat("Response",resp,containsString("parameters.size = [0]"));
+    }
+
+    @Test
+    public void testRequestParamServletAbc() throws Exception
+    {
+        SimpleRequest req = new SimpleRequest(serverHttpURI);
+        String resp = req.getString("req-info?abc=123");
+
+        System.out.println(resp);
+
+        assertThat("Response",resp,containsString("request is PRESENT"));
+        assertThat("Response",resp,containsString("parameters.size = [1]"));
+        assertThat("Response",resp,containsString(" param[abc] = [123]"));
+    }
+}
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000..f158a71
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
+        http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="all">
+</beans>
\ No newline at end of file
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..f69b351
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/jetty-logging.properties
@@ -0,0 +1,11 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.jboss.LEVEL=DEBUG
+org.eclipse.jetty.LEVEL=INFO
+
+org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+org.eclipse.jetty.cdi.LEVEL=DEBUG
+
+# org.eclipse.jetty.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
+
diff --git a/jetty-cdi/cdi-servlet/src/test/resources/logging.properties b/jetty-cdi/cdi-servlet/src/test/resources/logging.properties
new file mode 100644
index 0000000..cfec8c7
--- /dev/null
+++ b/jetty-cdi/cdi-servlet/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.util.log.JettyLogHandler
+.level=FINE
diff --git a/jetty-cdi/cdi-websocket/pom.xml b/jetty-cdi/cdi-websocket/pom.xml
new file mode 100644
index 0000000..409f21c
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/pom.xml
@@ -0,0 +1,71 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cdi-websocket</artifactId>
+  <name>Jetty :: CDI :: WebSocket</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <packaging>jar</packaging>
+  <properties>
+    <weld.version>2.2.9.Final</weld.version>
+    <bundle-symbolic-name>${project.groupId}.websocket</bundle-symbolic-name>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <!-- below here lie testing dragons -->
+    <dependency>
+       <groupId>org.eclipse.jetty</groupId>
+       <artifactId>apache-jsp</artifactId>
+       <version>${project.version}</version>
+       <scope>test</scope>
+     </dependency>
+    <dependency>
+      <groupId>org.jboss.weld</groupId>
+      <artifactId>weld-core</artifactId>
+      <version>${weld.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.weld.se</groupId>
+      <artifactId>weld-se-core</artifactId>
+      <version>${weld.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-core</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>javax-websocket-server-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java
new file mode 100644
index 0000000..1c15e06
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/AbstractContainerListener.java
@@ -0,0 +1,73 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import org.eclipse.jetty.util.component.Container;
+import org.eclipse.jetty.util.component.LifeCycle;
+
+/**
+ * Abstract implementation of listener that needs both Container events and LifeCycle events
+ */
+public abstract class AbstractContainerListener implements LifeCycle.Listener, Container.InheritedListener
+{
+    @Override
+    public void beanAdded(Container parent, Object child)
+    {
+        if (child instanceof LifeCycle)
+        {
+            ((LifeCycle)child).addLifeCycleListener(this);
+        }
+    }
+
+    @Override
+    public void beanRemoved(Container parent, Object child)
+    {
+        if (child instanceof LifeCycle)
+        {
+            ((LifeCycle)child).removeLifeCycleListener(this);
+        }
+    }
+
+    @Override
+    public void lifeCycleFailure(LifeCycle event, Throwable cause)
+    {
+    }
+
+    @Override
+    public void lifeCycleStarted(LifeCycle event)
+    {
+    }
+
+    @Override
+    public void lifeCycleStarting(LifeCycle event)
+    {
+    }
+
+    @Override
+    public void lifeCycleStopped(LifeCycle event)
+    {
+
+    }
+
+    @Override
+    public void lifeCycleStopping(LifeCycle event)
+    {
+    }
+
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java
new file mode 100644
index 0000000..6aaa2ba
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JavaWebSocketSessionProducer.java
@@ -0,0 +1,56 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.websocket.Session;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Producer of {@link javax.websocket.Session} instances
+ */
+public class JavaWebSocketSessionProducer
+{
+    private static final Logger LOG = Log.getLogger(JavaWebSocketSessionProducer.class);
+
+    @Produces
+    public Session getSession(InjectionPoint injectionPoint)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("getSession({})",injectionPoint);
+        }
+        org.eclipse.jetty.websocket.api.Session sess = WebSocketScopeContext.current().getSession();
+        if (sess == null)
+        {
+            throw new IllegalStateException("No Session Available");
+        }
+
+        if (sess instanceof javax.websocket.Session)
+        {
+            return (Session)sess;
+        }
+
+        throw new IllegalStateException("Incompatible Session, expected <" + javax.websocket.Session.class.getName() + ">, but got <"
+                + sess.getClass().getName() + "> instead");
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java
new file mode 100644
index 0000000..6ff9ba4
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/JettyWebSocketSessionProducer.java
@@ -0,0 +1,55 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+
+/**
+ * Producer of {@link org.eclipse.jetty.websocket.api.Session} instances
+ */
+public class JettyWebSocketSessionProducer
+{
+    private static final Logger LOG = Log.getLogger(JettyWebSocketSessionProducer.class);
+
+    @Produces
+    public Session getSession(InjectionPoint injectionPoint)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("getSession({})",injectionPoint);
+        }
+        WebSocketScopeContext ctx = WebSocketScopeContext.current();
+        if (ctx == null)
+        {
+            throw new IllegalStateException("Not in a " + WebSocketScope.class.getName());
+        }
+        org.eclipse.jetty.websocket.api.Session sess = ctx.getSession();
+        if (sess == null)
+        {
+            throw new IllegalStateException("No Session Available");
+        }
+        return sess;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java
new file mode 100644
index 0000000..fd15251
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiInitializer.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import java.util.Set;
+
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.thread.ThreadClassLoaderScope;
+
+public class WebSocketCdiInitializer implements ServletContainerInitializer
+{
+    public static void configureContext(ServletContextHandler context) throws ServletException
+    {
+        try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(context.getClassLoader()))
+        {
+            addListeners(context);
+        }
+    }
+
+    @Override
+    public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
+    {
+        ContextHandler handler = ContextHandler.getContextHandler(context);
+
+        if (handler == null)
+        {
+            throw new ServletException("Not running on Jetty, WebSocket+CDI support unavailable");
+        }
+
+        if (!(handler instanceof ServletContextHandler))
+        {
+            throw new ServletException("Not running in Jetty ServletContextHandler, WebSocket+CDI support unavailable");
+        }
+
+        ServletContextHandler jettyContext = (ServletContextHandler)handler;
+        try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(context.getClassLoader()))
+        {
+            addListeners(jettyContext);
+        }
+    }
+    
+    private static void addListeners(ContainerLifeCycle container)
+    {
+        WebSocketCdiListener listener = new WebSocketCdiListener();
+        container.addLifeCycleListener(listener);
+        container.addEventListener(listener);
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java
new file mode 100644
index 0000000..769be54
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketCdiListener.java
@@ -0,0 +1,137 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope;
+
+public class WebSocketCdiListener extends AbstractContainerListener
+{
+    static final Logger LOG = Log.getLogger(WebSocketCdiListener.class);
+
+    @SuppressWarnings(
+    { "rawtypes", "unchecked" })
+    public static <T> ScopedInstance<T> newInstance(Class<T> clazz)
+    {
+        BeanManager bm = CDI.current().getBeanManager();
+
+        ScopedInstance sbean = new ScopedInstance();
+        Set<Bean<?>> beans = bm.getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.size() > 0)
+        {
+            sbean.bean = beans.iterator().next();
+            sbean.creationalContext = bm.createCreationalContext(sbean.bean);
+            sbean.instance = bm.getReference(sbean.bean,clazz,sbean.creationalContext);
+            return sbean;
+        }
+        else
+        {
+            throw new RuntimeException(String.format("Can't find class %s",clazz));
+        }
+    }
+
+    public static class ContainerListener extends AbstractContainerListener
+    {
+        private static final Logger LOG = Log.getLogger(WebSocketCdiListener.ContainerListener.class);
+        private final WebSocketContainerScope container;
+        private final ScopedInstance<WebSocketScopeContext> wsScope;
+
+        public ContainerListener(WebSocketContainerScope container)
+        {
+            this.container = container;
+            this.wsScope = newInstance(WebSocketScopeContext.class);
+            this.wsScope.instance.create();
+        }
+
+        @Override
+        public void lifeCycleStarted(LifeCycle event)
+        {
+            if (event == container)
+            {
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("starting websocket container [{}]",event);
+                }
+                wsScope.instance.begin();
+                return;
+            }
+            
+            if (event instanceof WebSocketSessionScope)
+            {
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("starting websocket session [{}]",event);
+                }
+                wsScope.instance.setSession((Session)event);
+                return;
+            }
+        }
+
+        @Override
+        public void lifeCycleStopped(LifeCycle event)
+        {
+            if (event == container)
+            {
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("stopped websocket container [{}]",event);
+                }
+                this.wsScope.instance.end();
+                this.wsScope.instance.destroy();
+                this.wsScope.destroy();
+            }
+        }
+    }
+    
+    @Override
+    public void lifeCycleStarting(LifeCycle event)
+    {
+        if (event instanceof WebSocketContainerScope)
+        {
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("started websocket container [{}]",event);
+            }
+            ContainerListener listener = new ContainerListener((WebSocketContainerScope)event);
+            if (event instanceof ContainerLifeCycle)
+            {
+                ContainerLifeCycle container = (ContainerLifeCycle)event;
+                container.addLifeCycleListener(listener);
+                container.addEventListener(listener);
+            }
+            else
+            {
+                throw new RuntimeException("Unable to setup CDI against non-container: " + event.getClass().getName());
+            }
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java
new file mode 100644
index 0000000..67f22af
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeContext.java
@@ -0,0 +1,230 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.Set;
+
+import javax.enterprise.context.spi.Context;
+import javax.enterprise.context.spi.Contextual;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.SimpleBeanStore;
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+
+/**
+ * WebSocket Scope Context.
+ * <p>
+ * A CDI Context definition for how CDI will use objects defined to belong to the WebSocketScope
+ */
+public class WebSocketScopeContext implements Context
+{
+    private static final Logger LOG = Log.getLogger(WebSocketScopeContext.class);
+
+    private static ThreadLocal<WebSocketScopeContext> current = new ThreadLocal<>();
+
+    public static WebSocketScopeContext current()
+    {
+        return current.get();
+    }
+
+    private SimpleBeanStore beanStore;
+
+    @Inject
+    private BeanManager beanManager;
+
+    private ThreadLocal<org.eclipse.jetty.websocket.api.Session> session = new ThreadLocal<>();
+
+    public void begin()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} begin()",this);
+        }
+        current.set(this);
+    }
+
+    public void create()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} create()",this);
+        }
+        current.set(this);
+        beanStore = new SimpleBeanStore();
+    }
+
+    public void destroy()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} destroy()",this);
+        }
+
+        beanStore.destroy();
+    }
+
+    public void end()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} end()",this);
+        }
+        beanStore.clear();
+    }
+
+    @SuppressWarnings({ "unchecked" })
+    @Override
+    public <T> T get(Contextual<T> contextual)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} get({})",this,contextual);
+        }
+
+        Bean<T> bean = (Bean<T>)contextual;
+
+        if (bean.getBeanClass().isAssignableFrom(Session.class))
+        {
+            return (T)this.session;
+        }
+        
+        if (beanStore == null)
+        {
+            return null;
+        }
+
+        List<ScopedInstance<?>> beans = beanStore.getBeans(contextual);
+
+        if ((beans != null) && (!beans.isEmpty()))
+        {
+            return (T)beans.get(0).instance;
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} get({},{})",this,contextual,creationalContext);
+        }
+
+        Bean<T> bean = (Bean<T>)contextual;
+
+        if (bean.getBeanClass().isAssignableFrom(Session.class))
+        {
+            return (T)this.session;
+        }
+
+        if (beanStore == null)
+        {
+            beanStore = new SimpleBeanStore();
+        }
+
+        List<ScopedInstance<?>> beans = beanStore.getBeans(contextual);
+
+        if ((beans != null) && (!beans.isEmpty()))
+        {
+            for (ScopedInstance<?> instance : beans)
+            {
+                if (instance.bean.equals(bean))
+                {
+                    return (T)instance.instance;
+                }
+            }
+        }
+
+        // no bean found, create it
+        T t = bean.create(creationalContext);
+        ScopedInstance<T> customInstance = new ScopedInstance<>();
+        customInstance.bean = bean;
+        customInstance.creationalContext = creationalContext;
+        customInstance.instance = t;
+        beanStore.addBean(customInstance);
+        return t;
+    }
+
+    @Override
+    public Class<? extends Annotation> getScope()
+    {
+        return WebSocketScope.class;
+    }
+
+    @Override
+    public boolean isActive()
+    {
+        return true;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public <T> T newInstance(Class<T> clazz)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("newInstance({})",clazz);
+        }
+        Set<Bean<?>> beans = beanManager.getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.isEmpty())
+        {
+            return null;
+        }
+
+        Bean bean = beans.iterator().next();
+        CreationalContext cc = beanManager.createCreationalContext(bean);
+        return (T)beanManager.getReference(bean,clazz,cc);
+    }
+
+    public void setSession(org.eclipse.jetty.websocket.api.Session sess)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} setSession({})",this,sess);
+        }
+        current.set(this);
+        this.session.set(sess);
+    }
+
+    public org.eclipse.jetty.websocket.api.Session getSession()
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("{} getSession()",this);
+        }
+        return this.session.get();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%X[%s]",this.getClass().getSimpleName(),hashCode(),beanStore);
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java
new file mode 100644
index 0000000..9793804
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/WebSocketScopeExtension.java
@@ -0,0 +1,74 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import javax.enterprise.context.Destroyed;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.BeforeBeanDiscovery;
+import javax.enterprise.inject.spi.Extension;
+
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Register the various WebSocket specific components for CDI
+ */
+public class WebSocketScopeExtension implements Extension
+{
+    private static final Logger LOG = Log.getLogger(WebSocketScopeExtension.class);
+
+    public void addScope(@Observes final BeforeBeanDiscovery event)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("addScope()");
+        }
+        // Add our scope
+        event.addScope(WebSocketScope.class,true,false);
+    }
+
+    public void registerContext(@Observes final AfterBeanDiscovery event)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("registerContext()");
+        }
+        // Register our context
+        event.addContext(new WebSocketScopeContext());
+    }
+
+    public void logWsScopeInit(@Observes @Initialized(WebSocketScope.class) org.eclipse.jetty.websocket.api.Session sess)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Initialized @WebSocketScope - {}",sess);
+        }
+    }
+
+    public void logWsScopeDestroyed(@Observes @Destroyed(WebSocketScope.class) org.eclipse.jetty.websocket.api.Session sess)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Destroyed @WebSocketScope - {}",sess);
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java
new file mode 100644
index 0000000..a2cd6c4
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/java/org/eclipse/jetty/cdi/websocket/annotation/WebSocketScope.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Scope;
+
+/**
+ * A CDI Context Scope for a WebSocket Session / Endpoint
+ * <p>
+ * <em>CAUTION: This is a highly speculative scope defined by Jetty.  One that will likely be replaced by a formal spec later</em>
+ * <p>
+ * At the time of implementation (of this scope), no standard scope exists for websocket session lifecycle.
+ */
+@Scope
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
+@Inherited
+@Documented
+public @interface WebSocketScope
+{
+
+}
diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..aeeef53
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,4 @@
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+
+</beans>
\ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 0000000..93723bc
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+org.eclipse.jetty.cdi.websocket.WebSocketScopeExtension
\ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
new file mode 100644
index 0000000..f527270
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
@@ -0,0 +1 @@
+org.eclipse.jetty.cdi.websocket.WebSocketCdiInitializer
\ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java
new file mode 100644
index 0000000..0c76d95
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/CheckSocket.java
@@ -0,0 +1,99 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
+
+@WebSocket
+public class CheckSocket extends WebSocketAdapter
+{
+    private static final Logger LOG = Log.getLogger(CheckSocket.class);
+    private CountDownLatch closeLatch = new CountDownLatch(1);
+    private CountDownLatch openLatch = new CountDownLatch(1);
+    private EventQueue<String> textMessages = new EventQueue<>();
+
+    public void awaitClose(int timeout, TimeUnit timeunit) throws InterruptedException
+    {
+        assertTrue("Timeout waiting for close",closeLatch.await(timeout,timeunit));
+    }
+
+    public void awaitOpen(int timeout, TimeUnit timeunit) throws InterruptedException
+    {
+        assertTrue("Timeout waiting for open",openLatch.await(timeout,timeunit));
+    }
+
+    public EventQueue<String> getTextMessages()
+    {
+        return textMessages;
+    }
+
+    @Override
+    public void onWebSocketClose(int statusCode, String reason)
+    {
+        LOG.debug("Close: {}, {}",statusCode,reason);
+        super.onWebSocketClose(statusCode,reason);
+        closeLatch.countDown();
+    }
+
+    @Override
+    public void onWebSocketConnect(Session sess)
+    {
+        LOG.debug("Open: {}",sess);
+        super.onWebSocketConnect(sess);
+        openLatch.countDown();
+    }
+    
+    @Override
+    public void onWebSocketError(Throwable cause)
+    {
+        LOG.warn("WebSocket Error",cause);
+        super.onWebSocketError(cause);
+    }
+
+    @Override
+    public void onWebSocketText(String message)
+    {
+        LOG.debug("TEXT: {}",message);
+        textMessages.add(message);
+    }
+
+    public void sendText(String msg) throws IOException
+    {
+        if (isConnected())
+        {
+            getRemote().sendString(msg);
+        }
+    }
+
+    public void close(int statusCode, String reason)
+    {
+        getSession().close(statusCode,reason);
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java
new file mode 100644
index 0000000..1a888d2
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/BasicAppTest.java
@@ -0,0 +1,130 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.basicapp;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler;
+import org.eclipse.jetty.cdi.websocket.CheckSocket;
+import org.eclipse.jetty.cdi.websocket.cdiapp.InfoSocket;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class BasicAppTest
+{
+    private static final Logger LOG = Log.getLogger(BasicAppTest.class);
+    
+    private static Server server;
+    @SuppressWarnings("unused")
+    private static URI serverHttpURI;
+    private static URI serverWebsocketURI;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        JettyLogHandler.config();
+
+        server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+
+        File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+        context.setBaseResource(Resource.newResource(baseDir));
+        context.setContextPath("/");
+        server.setHandler(context);
+        
+        // Add some websockets
+        ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
+        container.addEndpoint(EchoSocket.class);
+        container.addEndpoint(InfoSocket.class);
+
+        server.start();
+
+        String host = connector.getHost();
+        if (host == null)
+        {
+            host = "localhost";
+        }
+        int port = connector.getLocalPort();
+        serverHttpURI = new URI(String.format("http://%s:%d/",host,port));
+        serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port));
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        try
+        {
+            server.stop();
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+    }
+
+    @Test
+    public void testWebSocketEcho() throws Exception
+    {
+        WebSocketClient client = new WebSocketClient();
+        try
+        {
+            client.start();
+            CheckSocket socket = new CheckSocket();
+            client.connect(socket,serverWebsocketURI.resolve("/echo"));
+
+            socket.awaitOpen(2,TimeUnit.SECONDS);
+            socket.sendText("Hello World");
+            socket.close(StatusCode.NORMAL,"Test complete");
+            socket.awaitClose(2,TimeUnit.SECONDS);
+
+            assertThat("Messages received",socket.getTextMessages().size(),is(1));
+            String response = socket.getTextMessages().poll();
+            System.err.println(response);
+
+            assertThat("Message[0]",response,is("Hello World"));
+        }
+        finally
+        {
+            client.stop();
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java
new file mode 100644
index 0000000..b4a2354
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicapp/EchoSocket.java
@@ -0,0 +1,57 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.basicapp;
+
+import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+@ServerEndpoint("/echo")
+public class EchoSocket
+{
+    private static final Logger LOG = Log.getLogger(EchoSocket.class);
+    @SuppressWarnings("unused")
+    private Session session;
+
+    @OnOpen
+    public void onOpen(Session session)
+    {
+        LOG.debug("onOpen(): {}",session);
+        this.session = session;
+    }
+
+    @OnClose
+    public void onClose(CloseReason close)
+    {
+        LOG.debug("onClose(): {}",close);
+        this.session = null;
+    }
+
+    @OnMessage
+    public String onMessage(String msg)
+    {
+        return msg;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java
new file mode 100644
index 0000000..99f4b00
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Food.java
@@ -0,0 +1,100 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.basicscope;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+public class Food
+{
+    private boolean constructed = false;
+    private boolean destroyed = false;
+    private String name;
+
+    @PreDestroy
+    void destroy()
+    {
+        destroyed = true;       
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        Food other = (Food)obj;
+        if (name == null)
+        {
+            if (other.name != null)
+            {
+                return false;
+            }
+        }
+        else if (!name.equals(other.name))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+        return result;
+    }
+
+    @PostConstruct
+    void init()
+    {
+        constructed = true;
+    }
+
+    public boolean isConstructed()
+    {
+        return constructed;
+    }
+
+    public boolean isDestroyed()
+    {
+        return destroyed;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Meal.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Meal.java
new file mode 100644
index 0000000..29ef659
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/Meal.java
@@ -0,0 +1,40 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.basicscope;
+
+import javax.inject.Inject;
+
+public class Meal
+{
+    @Inject
+    private Food entree;
+
+    @Inject
+    private Food side;
+
+    public Food getEntree()
+    {
+        return entree;
+    }
+
+    public Food getSide()
+    {
+        return side;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java
new file mode 100644
index 0000000..aa68b90
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/basicscope/ScopeBasicsTest.java
@@ -0,0 +1,97 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.basicscope;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.logging.Logging;
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ScopeBasicsTest
+{
+    private static Weld weld;
+    private static WeldContainer container;
+
+    @BeforeClass
+    public static void startWeld()
+    {
+        Logging.config();
+        weld = new Weld();
+        container = weld.initialize();
+    }
+
+    @AfterClass
+    public static void stopWeld()
+    {
+        weld.shutdown();
+    }
+
+    /**
+     * Validation of Scope / Inject logic on non-websocket-scoped classes
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testBasicBehavior() throws Exception
+    {
+        ScopedInstance<Meal> meal1Bean = newInstance(Meal.class);
+        Meal meal1 = meal1Bean.instance;
+        ScopedInstance<Meal> meal2Bean = newInstance(Meal.class);
+        Meal meal2 = meal2Bean.instance;
+
+        assertThat("Meals are not the same",meal1,not(sameInstance(meal2)));
+
+        assertThat("Meal 1 Entree Constructed",meal1.getEntree().isConstructed(),is(true));
+        assertThat("Meal 1 Side Constructed",meal1.getSide().isConstructed(),is(true));
+
+        assertThat("Meal parts not the same",meal1.getEntree(),not(sameInstance(meal1.getSide())));
+        assertThat("Meal entrees are the same",meal1.getEntree(),not(sameInstance(meal2.getEntree())));
+        assertThat("Meal sides are the same",meal1.getSide(),not(sameInstance(meal2.getSide())));
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <T> ScopedInstance<T> newInstance(Class<T> clazz) throws Exception
+    {
+        ScopedInstance sbean = new ScopedInstance();
+        Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.size() > 0)
+        {
+            sbean.bean = beans.iterator().next();
+            sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean);
+            sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext);
+            return sbean;
+        }
+        else
+        {
+            throw new Exception(String.format("Can't find class %s",clazz));
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java
new file mode 100644
index 0000000..0bc3a91
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/CdiAppTest.java
@@ -0,0 +1,185 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.cdiapp;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.jetty.cdi.servlet.EmbeddedCdiHandler;
+import org.eclipse.jetty.cdi.websocket.CheckSocket;
+import org.eclipse.jetty.cdi.websocket.WebSocketCdiInitializer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.log.JettyLogHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class CdiAppTest
+{
+    private static final Logger LOG = Log.getLogger(CdiAppTest.class);
+    private static Server server;
+    private static URI serverWebsocketURI;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        JettyLogHandler.config();
+
+        server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        EmbeddedCdiHandler context = new EmbeddedCdiHandler();
+        WebSocketCdiInitializer.configureContext(context);
+
+        File baseDir = MavenTestingUtils.getTestResourcesDir();
+
+        context.setBaseResource(Resource.newResource(baseDir));
+        context.setContextPath("/");
+        server.setHandler(context);
+        
+        // Add some websockets
+        ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
+        container.addEndpoint(EchoSocket.class);
+        container.addEndpoint(InfoSocket.class);
+
+        server.start();
+
+        String host = connector.getHost();
+        if (host == null)
+        {
+            host = "localhost";
+        }
+        int port = connector.getLocalPort();
+        serverWebsocketURI = new URI(String.format("ws://%s:%d/",host,port));
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        try
+        {
+            server.stop();
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+    }
+
+    @Test
+    public void testWebSocketActivated() throws Exception
+    {
+        WebSocketClient client = new WebSocketClient();
+        try
+        {
+            client.start();
+            CheckSocket socket = new CheckSocket();
+            client.connect(socket,serverWebsocketURI.resolve("/echo"));
+
+            socket.awaitOpen(2,TimeUnit.SECONDS);
+            socket.sendText("Hello");
+            socket.close(StatusCode.NORMAL,"Test complete");
+            socket.awaitClose(2,TimeUnit.SECONDS);
+
+            assertThat("Messages received",socket.getTextMessages().size(),is(1));
+            assertThat("Message[0]",socket.getTextMessages().poll(),is("Hello"));
+        }
+        finally
+        {
+            client.stop();
+        }
+    }
+
+    @Test
+    public void testWebSocket_Info_FieldPresence() throws Exception
+    {
+        WebSocketClient client = new WebSocketClient();
+        try
+        {
+            client.start();
+            CheckSocket socket = new CheckSocket();
+            client.connect(socket,serverWebsocketURI.resolve("/cdi-info"));
+
+            socket.awaitOpen(2,TimeUnit.SECONDS);
+            socket.sendText("info");
+            socket.close(StatusCode.NORMAL,"Test complete");
+            socket.awaitClose(2,TimeUnit.SECONDS);
+
+            assertThat("Messages received",socket.getTextMessages().size(),is(1));
+            String response = socket.getTextMessages().poll();
+            System.err.println(response);
+
+            assertThat("Message[0]",response,
+                    allOf(
+                            containsString("websocketSession is PRESENT"),
+                            containsString("httpSession is PRESENT"),
+                            containsString("servletContext is PRESENT")
+                    ));
+        }
+        finally
+        {
+            client.stop();
+        }
+    }
+    
+    @Test
+    public void testWebSocket_Info_DataFromCdi() throws Exception
+    {
+        WebSocketClient client = new WebSocketClient();
+        try
+        {
+            client.start();
+            CheckSocket socket = new CheckSocket();
+            client.connect(socket,serverWebsocketURI.resolve("/cdi-info"));
+
+            socket.awaitOpen(2,TimeUnit.SECONDS);
+            socket.sendText("data|stuff");
+            socket.close(StatusCode.NORMAL,"Test complete");
+            socket.awaitClose(2,TimeUnit.SECONDS);
+
+            assertThat("Messages received",socket.getTextMessages().size(),is(2));
+            String response = socket.getTextMessages().poll();
+            System.out.println("[0]" + response);
+            assertThat("Message[0]",response,containsString("Hello there stuff"));
+            System.out.println("[1]" + socket.getTextMessages().poll());
+        }
+        finally
+        {
+            client.stop();
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java
new file mode 100644
index 0000000..c605c30
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/DataMaker.java
@@ -0,0 +1,43 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.cdiapp;
+
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.Session;
+
+public class DataMaker
+{
+    private static final Logger LOG = Log.getLogger(DataMaker.class);
+    
+    @Inject
+    @WebSocketScope
+    private Session session;
+
+    public void processMessage(String msg) 
+    {
+        LOG.debug(".processMessage({})",msg);
+        LOG.debug("session = {}",session);
+
+        session.getRemote().sendStringByFuture("Hello there " + msg);
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java
new file mode 100644
index 0000000..6d68f70
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/EchoSocket.java
@@ -0,0 +1,57 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.cdiapp;
+
+import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+@ServerEndpoint("/echo")
+public class EchoSocket
+{
+    private static final Logger LOG = Log.getLogger(EchoSocket.class);
+    @SuppressWarnings("unused")
+    private Session session;
+
+    @OnOpen
+    public void onOpen(Session session)
+    {
+        LOG.debug("onOpen(): {}",session);
+        this.session = session;
+    }
+
+    @OnClose
+    public void onClose(CloseReason close)
+    {
+        LOG.debug("onClose(): {}",close);
+        this.session = null;
+    }
+
+    @OnMessage
+    public String onMessage(String msg)
+    {
+        return msg;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java
new file mode 100644
index 0000000..c108a5e
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/cdiapp/InfoSocket.java
@@ -0,0 +1,94 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.cdiapp;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Level;
+
+import javax.enterprise.context.SessionScoped;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+@ServerEndpoint("/cdi-info")
+public class InfoSocket
+{
+    private static final java.util.logging.Logger LOG = java.util.logging.Logger.getLogger(InfoSocket.class.getName());
+
+    @SessionScoped
+    @Inject
+    private HttpSession httpSession;
+
+    @Inject
+    private ServletContext servletContext;
+    
+    @Inject
+    private DataMaker dataMaker;
+
+    private Session session;
+    
+    @OnOpen
+    public void onOpen(Session session)
+    {
+        LOG.log(Level.INFO,"onOpen(): {0}",session);
+        this.session = session;
+    }
+
+    @OnClose
+    public void onClose(CloseReason close)
+    {
+        LOG.log(Level.INFO,"onClose(): {}",close);
+        this.session = null;
+    }
+
+    @OnMessage
+    public String onMessage(String msg)
+    {
+        StringWriter str = new StringWriter();
+        PrintWriter out = new PrintWriter(str);
+        
+        String args[] = msg.split("\\|");
+
+        switch (args[0])
+        {
+            case "info":
+                out.printf("websocketSession is %s%n",asPresent(session));
+                out.printf("httpSession is %s%n",asPresent(httpSession));
+                out.printf("servletContext is %s%n",asPresent(servletContext));
+                break;
+            case "data":
+                dataMaker.processMessage(args[1]);
+                break;
+        }
+
+        return str.toString();
+    }
+
+    private String asPresent(Object obj)
+    {
+        return obj == null ? "NULL" : "PRESENT";
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java
new file mode 100644
index 0000000..fd43ed1
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSession.java
@@ -0,0 +1,150 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.eclipse.jetty.websocket.api.CloseStatus;
+import org.eclipse.jetty.websocket.api.RemoteEndpoint;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.SuspendToken;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.api.UpgradeResponse;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+
+/**
+ * A bogus websocket Session concept object.
+ * <p>
+ * Used to test the scope @Inject of this kind of Session. This is important to test, as the BogusSession does not have
+ * a default constructor that CDI itself can use to create this object.
+ * <p>
+ * This object would need to be added to the beanstore for this scope for later @Inject to use.
+ */
+public class BogusSession implements Session
+{
+    private final String id;
+
+    public BogusSession(String id)
+    {
+        this.id = id;
+    }
+    
+    @Override
+    public String toString()
+    {
+        return String.format("BogusSession[id=%s]",id);
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    @Override
+    public void close()
+    {
+    }
+
+    @Override
+    public void close(CloseStatus closeStatus)
+    {
+    }
+
+    @Override
+    public void close(int statusCode, String reason)
+    {
+    }
+
+    @Override
+    public void disconnect() throws IOException
+    {
+    }
+
+    @Override
+    public long getIdleTimeout()
+    {
+        return 0;
+    }
+
+    @Override
+    public InetSocketAddress getLocalAddress()
+    {
+        return null;
+    }
+
+    @Override
+    public WebSocketPolicy getPolicy()
+    {
+        return null;
+    }
+
+    @Override
+    public String getProtocolVersion()
+    {
+        return null;
+    }
+
+    @Override
+    public RemoteEndpoint getRemote()
+    {
+        return null;
+    }
+
+    @Override
+    public InetSocketAddress getRemoteAddress()
+    {
+        return null;
+    }
+
+    @Override
+    public UpgradeRequest getUpgradeRequest()
+    {
+        return null;
+    }
+
+    @Override
+    public UpgradeResponse getUpgradeResponse()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isSecure()
+    {
+        return false;
+    }
+
+    @Override
+    public void setIdleTimeout(long ms)
+    {
+    }
+
+    @Override
+    public SuspendToken suspend()
+    {
+        return null;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java
new file mode 100644
index 0000000..ddc172c
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/BogusSocket.java
@@ -0,0 +1,36 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import javax.inject.Inject;
+
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.eclipse.jetty.websocket.api.Session;
+
+public class BogusSocket
+{
+    @Inject
+    @WebSocketScope
+    private Session session;
+    
+    public Session getSession()
+    {
+        return session;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java
new file mode 100644
index 0000000..94836ed
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Food.java
@@ -0,0 +1,119 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+
+@WebSocketScope
+public class Food
+{
+    private boolean constructed = false;
+    private boolean destroyed = false;
+    private String name;
+
+    public Food()
+    {
+        // default constructor (for CDI use)
+    }
+
+    public Food(String name)
+    {
+        this.name = name;
+    }
+
+    @PreDestroy
+    void destroy()
+    {
+        destroyed = true;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        Food other = (Food)obj;
+        if (name == null)
+        {
+            if (other.name != null)
+            {
+                return false;
+            }
+        }
+        else if (!name.equals(other.name))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+        return result;
+    }
+
+    @PostConstruct
+    void init()
+    {
+        constructed = true;
+    }
+
+    public boolean isConstructed()
+    {
+        return constructed;
+    }
+
+    public boolean isDestroyed()
+    {
+        return destroyed;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%X[%s]",Food.class.getSimpleName(),hashCode(),name);
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Meal.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Meal.java
new file mode 100644
index 0000000..5561e3e
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/Meal.java
@@ -0,0 +1,40 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import javax.inject.Inject;
+
+public class Meal
+{
+    @Inject
+    private Food entree;
+
+    @Inject
+    private Food side;
+
+    public Food getEntree()
+    {
+        return entree;
+    }
+
+    public Food getSide()
+    {
+        return side;
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java
new file mode 100644
index 0000000..ee0440c
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeBaselineTest.java
@@ -0,0 +1,131 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+import java.util.Set;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.logging.Logging;
+import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext;
+import org.eclipse.jetty.cdi.websocket.annotation.WebSocketScope;
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WebSocketScopeBaselineTest
+{
+    private static Weld weld;
+    private static WeldContainer container;
+
+    @BeforeClass
+    public static void startWeld()
+    {
+        Logging.config();
+        weld = new Weld();
+        container = weld.initialize();
+    }
+
+    @AfterClass
+    public static void stopWeld()
+    {
+        weld.shutdown();
+    }
+    
+    /**
+     * Test behavior of {@link WebSocketScope} in basic operation.
+     * <p>
+     * Food is declared as part of WebSocketScope, and as such, only 1 instance of it can exist.
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testScopeBehavior() throws Exception
+    {
+        ScopedInstance<WebSocketScopeContext> wsScopeBean = newInstance(WebSocketScopeContext.class);
+        WebSocketScopeContext wsScope = wsScopeBean.instance;
+
+        wsScope.create();
+        Meal meal1;
+        try
+        {
+            wsScope.begin();
+            ScopedInstance<Meal> meal1Bean = newInstance(Meal.class);
+            meal1 = meal1Bean.instance;
+            ScopedInstance<Meal> meal2Bean = newInstance(Meal.class);
+            Meal meal2 = meal2Bean.instance;
+            
+            assertThat("Meals are not the same",meal1,not(sameInstance(meal2)));
+            
+            assertThat("Meal 1 Entree Constructed",meal1.getEntree().isConstructed(),is(true));
+            assertThat("Meal 1 Side Constructed",meal1.getSide().isConstructed(),is(true));
+            
+            /* Since Food is annotated with @WebSocketScope, there can only be one instance of it
+             * in use with the 2 Meal objects.
+             */
+            assertThat("Meal parts not the same",meal1.getEntree(),sameInstance(meal1.getSide()));
+            assertThat("Meal entrees are the same",meal1.getEntree(),sameInstance(meal2.getEntree()));
+            assertThat("Meal sides are the same",meal1.getSide(),sameInstance(meal2.getSide()));
+
+            meal1Bean.destroy();
+            meal2Bean.destroy();
+        }
+        finally
+        {
+            wsScope.end();
+        }
+        
+        Food entree1 = meal1.getEntree();
+        Food side1 = meal1.getSide();
+
+        assertThat("Meal 1 entree destroyed",entree1.isDestroyed(),is(false));
+        assertThat("Meal 1 side destroyed",side1.isDestroyed(),is(false));
+        wsScope.destroy();
+
+        // assertThat("Meal 1 entree destroyed",entree1.isDestroyed(),is(true));
+        // assertThat("Meal 1 side destroyed",side1.isDestroyed(),is(true));
+        wsScopeBean.destroy();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <T> ScopedInstance<T> newInstance(Class<T> clazz) throws Exception
+    {
+        ScopedInstance sbean = new ScopedInstance();
+        Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.size() > 0)
+        {
+            sbean.bean = beans.iterator().next();
+            sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean);
+            sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext);
+            return sbean;
+        }
+        else
+        {
+            throw new Exception(String.format("Can't find class %s",clazz));
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java
new file mode 100644
index 0000000..908db14
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/java/org/eclipse/jetty/cdi/websocket/wsscope/WebSocketScopeSessionTest.java
@@ -0,0 +1,253 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.cdi.websocket.wsscope;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import javax.enterprise.inject.spi.Bean;
+
+import org.eclipse.jetty.cdi.core.AnyLiteral;
+import org.eclipse.jetty.cdi.core.ScopedInstance;
+import org.eclipse.jetty.cdi.core.logging.Logging;
+import org.eclipse.jetty.cdi.websocket.WebSocketScopeContext;
+import org.eclipse.jetty.websocket.api.Session;
+import org.jboss.weld.environment.se.Weld;
+import org.jboss.weld.environment.se.WeldContainer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class WebSocketScopeSessionTest
+{
+    private static Weld weld;
+    private static WeldContainer container;
+
+    @BeforeClass
+    public static void startWeld()
+    {
+        Logging.config();
+        weld = new Weld();
+        container = weld.initialize();
+    }
+
+    @AfterClass
+    public static void stopWeld()
+    {
+        weld.shutdown();
+    }
+    
+    @Test
+    public void testSessionActivation() throws Exception
+    {
+        ScopedInstance<WebSocketScopeContext> wsScopeBean = newInstance(WebSocketScopeContext.class);
+        WebSocketScopeContext wsScope = wsScopeBean.instance;
+
+        wsScope.create();
+        try
+        {
+            // Scope 1
+            wsScope.begin();
+            BogusSession sess = new BogusSession("1");
+            wsScope.setSession(sess);
+            ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+            BogusSocket sock1 = sock1Bean.instance;
+            assertThat("Socket 1 Session",sock1.getSession().toString(),is(sess.toString()));
+
+            sock1Bean.destroy();
+        }
+        finally
+        {
+            wsScope.end();
+        }
+
+        wsScope.destroy();
+        wsScopeBean.destroy();
+    }
+    
+    @Test
+    public void testMultiSession_Sequential() throws Exception
+    {
+        ScopedInstance<WebSocketScopeContext> wsScope1Bean = newInstance(WebSocketScopeContext.class);
+        WebSocketScopeContext wsScope1 = wsScope1Bean.instance;
+        
+        ScopedInstance<WebSocketScopeContext> wsScope2Bean = newInstance(WebSocketScopeContext.class);
+        WebSocketScopeContext wsScope2 = wsScope2Bean.instance;
+
+        wsScope1.create();
+        try
+        {
+            // Scope 1
+            wsScope1.begin();
+            BogusSession sess = new BogusSession("1");
+            wsScope1.setSession(sess);
+            ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+            BogusSocket sock1 = sock1Bean.instance;
+            assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess));
+            sock1Bean.destroy();
+        }
+        finally
+        {
+            wsScope1.end();
+        }
+        
+        wsScope1.destroy();
+        wsScope1Bean.destroy();
+
+        wsScope2.create();
+        try
+        {
+            // Scope 2
+            wsScope2.begin();
+            BogusSession sess = new BogusSession("2");
+            wsScope2.setSession(sess);
+            ScopedInstance<BogusSocket> sock2Bean = newInstance(BogusSocket.class);
+            BogusSocket sock2 = sock2Bean.instance;
+            assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess));
+            sock2Bean.destroy();
+        }
+        finally
+        {
+            wsScope2.end();
+        }
+
+        wsScope2.destroy();
+        wsScope2Bean.destroy();
+    }
+    
+    @Test
+    public void testMultiSession_Overlapping() throws Exception
+    {
+        final CountDownLatch midLatch = new CountDownLatch(2);
+        final CountDownLatch end1Latch = new CountDownLatch(1);
+        
+        Callable<Session> call1 = new Callable<Session>() {
+            @Override
+            public Session call() throws Exception
+            {
+                Session ret = null;
+                ScopedInstance<WebSocketScopeContext> wsScope1Bean = newInstance(WebSocketScopeContext.class);
+                WebSocketScopeContext wsScope1 = wsScope1Bean.instance;
+                
+                wsScope1.create();
+                try
+                {
+                    // Scope 1
+                    wsScope1.begin();
+                    BogusSession sess = new BogusSession("1");
+                    wsScope1.setSession(sess);
+                    
+                    midLatch.countDown();
+                    midLatch.await(1, TimeUnit.SECONDS);
+                    
+                    ScopedInstance<BogusSocket> sock1Bean = newInstance(BogusSocket.class);
+                    BogusSocket sock1 = sock1Bean.instance;
+                    assertThat("Socket 1 Session",sock1.getSession(),sameInstance((Session)sess));
+                    ret = sock1.getSession();
+                    sock1Bean.destroy();
+                }
+                finally
+                {
+                    wsScope1.end();
+                }
+                
+                wsScope1.destroy();
+                wsScope1Bean.destroy();
+                end1Latch.countDown();
+                return ret;
+            }
+        };
+        
+        final CountDownLatch end2Latch = new CountDownLatch(1);
+        
+        Callable<Session> call2 = new Callable<Session>() {
+            @Override
+            public Session call() throws Exception
+            {
+                Session ret = null;
+                ScopedInstance<WebSocketScopeContext> wsScope2Bean = newInstance(WebSocketScopeContext.class);
+                WebSocketScopeContext wsScope2 = wsScope2Bean.instance;
+
+                wsScope2.create();
+                try
+                {
+                    // Scope 2
+                    wsScope2.begin();
+                    BogusSession sess = new BogusSession("2");
+                    wsScope2.setSession(sess);
+                    ScopedInstance<BogusSocket> sock2Bean = newInstance(BogusSocket.class);
+                    
+                    midLatch.countDown();
+                    midLatch.await(1, TimeUnit.SECONDS);
+                    
+                    BogusSocket sock2 = sock2Bean.instance;
+                    ret = sock2.getSession();
+                    assertThat("Socket 2 Session",sock2.getSession(),sameInstance((Session)sess)); 
+                    sock2Bean.destroy();
+                }
+                finally
+                {
+                    wsScope2.end();
+                }
+
+                wsScope2.destroy();
+                wsScope2Bean.destroy();
+                end2Latch.countDown();
+                return ret;
+            }
+        };
+        
+        ExecutorService svc = Executors.newFixedThreadPool(4);
+        Future<Session> fut1 = svc.submit(call1);
+        Future<Session> fut2 = svc.submit(call2);
+        
+        Session sess1 = fut1.get(1,TimeUnit.SECONDS);
+        Session sess2 = fut2.get(1,TimeUnit.SECONDS);
+        
+        assertThat("Sessions are different", sess1, not(sameInstance(sess2)));
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <T> ScopedInstance<T> newInstance(Class<T> clazz)
+    {
+        ScopedInstance sbean = new ScopedInstance();
+        Set<Bean<?>> beans = container.getBeanManager().getBeans(clazz,AnyLiteral.INSTANCE);
+        if (beans.size() > 0)
+        {
+            sbean.bean = beans.iterator().next();
+            sbean.creationalContext = container.getBeanManager().createCreationalContext(sbean.bean);
+            sbean.instance = container.getBeanManager().getReference(sbean.bean,clazz,sbean.creationalContext);
+            return sbean;
+        }
+        else
+        {
+            throw new RuntimeException(String.format("Can't find class %s",clazz));
+        }
+    }
+}
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml
new file mode 100644
index 0000000..f158a71
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
+        http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
+       bean-discovery-mode="all">
+</beans>
\ No newline at end of file
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..eeed11d
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/jetty-logging.properties
@@ -0,0 +1,15 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.jetty.LEVEL=INFO
+org.jboss.LEVEL=INFO
+# org.eclipse.jetty.LEVEL=INFO
+ 
+# org.eclipse.jetty.util.component.LEVEL=DEBUG
+
+# org.eclipse.jetty.websocket.common.LEVEL=DEBUG
+# org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+# org.eclipse.jetty.cdi.LEVEL=DEBUG
+
+# org.eclipse.jetty.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
+
diff --git a/jetty-cdi/cdi-websocket/src/test/resources/logging.properties b/jetty-cdi/cdi-websocket/src/test/resources/logging.properties
new file mode 100644
index 0000000..cfec8c7
--- /dev/null
+++ b/jetty-cdi/cdi-websocket/src/test/resources/logging.properties
@@ -0,0 +1,2 @@
+handlers = org.eclipse.jetty.util.log.JettyLogHandler
+.level=FINE
diff --git a/jetty-cdi/pom.xml b/jetty-cdi/pom.xml
index c1a4716..a59c9a8 100644
--- a/jetty-cdi/pom.xml
+++ b/jetty-cdi/pom.xml
@@ -2,48 +2,26 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
-  <artifactId>jetty-cdi</artifactId>
-  <name>Jetty :: CDI Configurations</name>
+  <groupId>org.eclipse.jetty.cdi</groupId>
+  <artifactId>jetty-cdi-parent</artifactId>
+  <name>Jetty :: CDI :: Parent</name>
   <url>http://www.eclipse.org/jetty</url>
-  <packaging>jar</packaging>
+  <packaging>pom</packaging>
   <properties>
-    <bundle-symbolic-name>${project.groupId}.${project.artifactId}</bundle-symbolic-name>
+    <weld.version>2.2.9.Final</weld.version>
   </properties>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
 
-  <dependencies>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-plus</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-deploy</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-  </dependencies>
+  <modules>
+    <module>cdi-core</module>
+    <module>cdi-servlet</module>
+    <module>cdi-full-servlet</module>
+    <module>cdi-websocket</module>
+    <module>test-cdi-webapp</module>
+    <!-- needs to be fixed still 
+    <module>test-cdi-it</module>
+     -->
+  </modules>
 </project>
diff --git a/jetty-cdi/src/main/config/etc/jetty-cdi.xml b/jetty-cdi/src/main/config/etc/jetty-cdi.xml
deleted file mode 100644
index d364f4c..0000000
--- a/jetty-cdi/src/main/config/etc/jetty-cdi.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<!-- =============================================================== -->
-<!-- Mixin the Weld / CDI classes to the class loader                -->
-<!-- =============================================================== -->
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-  <Ref refid="DeploymentManager">
-    <Call name="addLifeCycleBinding">
-      <Arg>
-        <New
-          class="org.eclipse.jetty.cdi.WeldDeploymentBinding">
-        </New>
-      </Arg>
-    </Call>
-  </Ref>
-</Configure>
-
diff --git a/jetty-cdi/src/main/config/modules/cdi.mod b/jetty-cdi/src/main/config/modules/cdi.mod
deleted file mode 100644
index 68dea58..0000000
--- a/jetty-cdi/src/main/config/modules/cdi.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# CDI / Weld Jetty module
-#
-
-[depend]
-deploy
-annotations
-plus
-# JSP (and EL) are requirements for CDI and Weld
-jsp
-
-[files]
-lib/weld/
-http://central.maven.org/maven2/org/jboss/weld/servlet/weld-servlet/2.2.5.Final/weld-servlet-2.2.5.Final.jar|lib/weld/weld-servlet-2.2.5.Final.jar
-
-[lib]
-lib/weld/weld-servlet-2.2.5.Final.jar
-lib/jetty-cdi-${jetty.version}.jar
-
-[xml]
-etc/jetty-cdi.xml
-
-[license]
-Weld is an open source project hosted on Github and released under the Apache 2.0 license.
-http://weld.cdi-spec.org/
-http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/WeldDeploymentBinding.java b/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/WeldDeploymentBinding.java
deleted file mode 100644
index 2139125..0000000
--- a/jetty-cdi/src/main/java/org/eclipse/jetty/cdi/WeldDeploymentBinding.java
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.cdi;
-
-import javax.naming.Reference;
-
-import org.eclipse.jetty.deploy.App;
-import org.eclipse.jetty.deploy.AppLifeCycle;
-import org.eclipse.jetty.deploy.graph.Node;
-import org.eclipse.jetty.plus.jndi.Resource;
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.webapp.WebAppContext;
-
-/**
- * Perform some basic weld configuration of WebAppContext
- */
-public class WeldDeploymentBinding implements AppLifeCycle.Binding
-{
-    public String[] getBindingTargets()
-    {
-        return new String[]
-        { "deploying" };
-    }
-
-    public void processBinding(Node node, App app) throws Exception
-    {
-        ContextHandler handler = app.getContextHandler();
-        if (handler == null)
-        {
-            throw new NullPointerException("No Handler created for App: " + app);
-        }
-
-        if (handler instanceof WebAppContext)
-        {
-            WebAppContext webapp = (WebAppContext)handler;
-
-            // Add context specific weld container reference.
-            // See https://issues.jboss.org/browse/WELD-1710
-            // and https://github.com/weld/core/blob/2.2.5.Final/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java#L244-L253
-            webapp.setInitParameter("org.jboss.weld.environment.container.class",
-                    "org.jboss.weld.environment.jetty.JettyContainer");
-            
-            // Setup Weld BeanManager reference
-            Reference ref = new Reference("javax.enterprise.inject.spi.BeanManager",
-                    "org.jboss.weld.resources.ManagerObjectFactory", null);
-            new Resource(webapp,"BeanManager",ref);
-            
-            // webapp cannot change / replace weld classes
-            webapp.addSystemClass("org.jboss.weld.");
-            webapp.addSystemClass("org.jboss.classfilewriter.");
-            webapp.addSystemClass("org.jboss.logging.");
-            webapp.addSystemClass("com.google.common.");
-            
-            // don't hide weld classes from webapps (allow webapp to use ones from system classloader)
-            webapp.addServerClass("-org.jboss.weld.");
-            webapp.addServerClass("-org.jboss.classfilewriter.");
-            webapp.addServerClass("-org.jboss.logging.");
-            webapp.addServerClass("-com.google.common.");
-        }
-    }
-}
diff --git a/jetty-cdi/test-cdi-it/pom.xml b/jetty-cdi/test-cdi-it/pom.xml
new file mode 100644
index 0000000..160bdb0
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/pom.xml
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+// ========================================================================
+// Copyright (c) Webtide LLC
+// 
+// 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.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>cdi-webapp-it</artifactId>
+  <packaging>jar</packaging>
+  <name>Jetty :: CDI :: Test :: WebApp Integration Tests</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    <bundle-symbolic-name>${project.groupId}.cdi.webapp.it</bundle-symbolic-name>
+    <scripts-dir>${project.basedir}/src/test/scripts</scripts-dir>
+    <test-base-dir>${project.build.directory}/test-base</test-base-dir>
+    <test-home-dir>${project.build.directory}/test-home</test-home-dir>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-distribution</artifactId>
+      <version>${project.version}</version>
+      <type>zip</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>test-cdi-webapp</artifactId>
+      <version>${project.version}</version>
+      <type>war</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <!-- DO NOT DEPLOY (or Release) -->
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-apps-for-testing</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <includeArtifactIds>test-cdi-webapp</includeArtifactIds>
+              <includeScope>runtime</includeScope>
+              <includeTypes>war</includeTypes>
+              <overwriteSnapshots>true</overwriteSnapshots>
+              <overwriteReleases>true</overwriteReleases>
+              <stripVersion>true</stripVersion>
+              <outputDirectory>${test-base-dir}/webapps</outputDirectory>
+            </configuration>
+          </execution>
+          <execution>
+            <id>unpack-jetty-distro</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>unpack-dependencies</goal>
+            </goals>
+            <configuration>
+              <includeArtifactIds>jetty-distribution</includeArtifactIds>
+              <includeScope>runtime</includeScope>
+              <includeTypes>zip</includeTypes>
+              <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
+              <outputDirectory>${test-home-dir}</outputDirectory>
+              <overWriteSnapshots>true</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>2.17</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <version>1.7</version>
+        <executions>
+          <execution>
+            <id>start-jetty</id>
+            <phase>pre-integration-test</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <property name="jetty.cdi.home" location="${test-home-dir}/jetty-distribution-${project.version}"/>
+                <property name="jetty.cdi.base" location="${test-base-dir}"/>
+                <echo>Integration Test : Setup Jetty</echo>
+                <exec executable="${run.command}"
+                      dir="${scripts-dir}"
+                      spawn="false">
+                  <arg value="${run.command.xtra}"/>
+                  <arg value="${setup.script}"/>
+                  <arg file="${java.home}"/>
+                  <arg file="${jetty.cdi.home}"/>
+                  <arg file="${jetty.cdi.base}"/>
+                </exec>
+
+                <echo>Integration Test : Starting Jetty ...</echo>
+                <exec executable="${run.command}"
+                      dir="${scripts-dir}"
+                      spawn="true">
+                  <arg value="${run.command.xtra}"/>
+                  <arg value="${start.script}"/>
+                  <arg file="${java.home}"/>
+                  <arg file="${jetty.cdi.home}"/>
+                  <arg file="${jetty.cdi.base}"/>
+                </exec>
+                <waitfor maxwait="5" maxwaitunit="second"
+                  checkevery="100" checkeveryunit="millisecond">
+                  <http url="http://localhost:58080/cdi-webapp/"/>
+                </waitfor>
+                <echo>Integration Test : Jetty is now available</echo>
+              </target>
+            </configuration>
+          </execution>
+          <execution>
+            <id>stop-jetty</id>
+            <phase>post-integration-test</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <property name="jetty.cdi.home" location="${test-home-dir}/jetty-distribution-${project.version}"/>
+                <property name="jetty.cdi.base" location="${test-base-dir}"/>
+                <echo>Integration Test : Stop Jetty</echo>
+                <exec executable="${run.command}"
+                      dir="${scripts-dir}"
+                      spawn="false">
+                  <arg value="${run.command.xtra}"/>
+                  <arg value="${stop.script}"/>
+                  <arg file="${java.home}"/>
+                  <arg file="${jetty.cdi.home}"/>
+                  <arg file="${jetty.cdi.base}"/>
+                </exec>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>it-windows</id>
+      <activation>
+        <os>
+          <family>Windows</family>
+        </os>
+      </activation>
+      <properties>
+        <run.command>cmd</run.command>
+        <run.command.xtra>/c</run.command.xtra>
+        <start.script>start-jetty.bat</start.script>
+        <stop.script>stop-jetty.bat</stop.script>
+      </properties>
+    </profile>
+    <profile>
+      <id>it-unix</id>
+      <activation>
+        <os>
+          <family>unix</family>
+        </os>
+      </activation>
+      <properties>
+        <run.command>sh</run.command>
+        <run.command.xtra>--</run.command.xtra>
+        <setup.script>setup-jetty.sh</setup.script>
+        <start.script>start-jetty.sh</start.script>
+        <stop.script>stop-jetty.sh</stop.script>
+      </properties>
+    </profile>
+  </profiles>
+</project>
diff --git a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java
new file mode 100644
index 0000000..140de15
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java
@@ -0,0 +1,41 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.tests;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.net.URI;
+
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.junit.Test;
+
+/**
+ * Basic tests for a simple @WebServlet with no CDI
+ */
+public class HelloIT
+{
+    @Test
+    public void testBasic() throws Exception
+    {
+        URI serverURI = new URI("http://localhost:58080/cdi-webapp/");
+        SimpleRequest req = new SimpleRequest(serverURI);
+        assertThat(req.getString("hello"),is("Hello World" + System.lineSeparator()));
+    }
+}
diff --git a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java
new file mode 100644
index 0000000..5d39b46
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java
@@ -0,0 +1,47 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.tests;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.net.URI;
+
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.junit.Test;
+
+public class ServerInfoIT
+{
+    @Test
+    public void testGET() throws Exception {
+        URI serverURI = new URI("http://localhost:58080/cdi-webapp/");
+        SimpleRequest req = new SimpleRequest(serverURI);
+        
+        // Typical response:
+        // context = ServletContext@o.e.j.w.WebAppContext@37cb63fd{/cdi-webapp,
+        // file:///tmp/jetty-0.0.0.0-58080-cdi-webapp.war-_cdi-webapp-any-417759194514596377.dir/webapp/,AVAILABLE}
+        // {/cdi-webapp.war}\ncontext.contextPath = /cdi-webapp\ncontext.effective-version = 3.1\n
+        assertThat(req.getString("serverinfo"),
+                allOf(
+                containsString("context = ServletContext@"),
+                containsString("context.contextPath = /cdi-webapp"),
+                containsString("context.effective-version = 3.1")
+                ));
+    }
+}
diff --git a/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java
new file mode 100644
index 0000000..ab249fb
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/java/org/eclipse/jetty/tests/ws/SessionInfoIT.java
@@ -0,0 +1,106 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.tests.ws;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.net.URI;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.websocket.ClientEndpoint;
+import javax.websocket.CloseReason;
+import javax.websocket.ContainerProvider;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.junit.Test;
+
+public class SessionInfoIT
+{
+    @ClientEndpoint
+    public static class ClientSessionInfoSocket
+    {
+        private static final Logger LOG = Log.getLogger(SessionInfoIT.ClientSessionInfoSocket.class);
+        
+        public CountDownLatch openLatch = new CountDownLatch(1);
+        public CountDownLatch closeLatch = new CountDownLatch(1);
+        public Session session;
+        public EventQueue<String> messages = new EventQueue<>();
+        public CloseReason closeReason;
+        
+        @OnOpen
+        public void onOpen(Session session)
+        {
+            LOG.info("onOpen(): {}", session);
+            this.session = session;
+            this.openLatch.countDown();
+        }
+        
+        @OnClose
+        public void onClose(CloseReason close)
+        {
+            LOG.info("onClose(): {}", close);
+            this.session = null;
+            this.closeReason = close;
+            this.closeLatch.countDown();
+        }
+
+        @OnMessage
+        public void onMessage(String message)
+        {
+            LOG.info("onMessage(): {}", message);
+            this.messages.offer(message);
+        }
+    }
+
+    @Test
+    public void testSessionInfo() throws Exception
+    {
+        URI serverURI = new URI("ws://localhost:58080/cdi-webapp/");
+
+        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
+
+        ClientSessionInfoSocket socket = new ClientSessionInfoSocket();
+        
+        container.connectToServer(socket,serverURI.resolve("sessioninfo"));
+
+        assertThat("Await open", socket.openLatch.await(1,TimeUnit.SECONDS), is(true));
+        
+        socket.session.getBasicRemote().sendText("info");
+        socket.messages.awaitEventCount(1,2,TimeUnit.SECONDS);
+        
+        System.out.printf("socket.messages.size = %s%n",socket.messages.size());
+        
+        String msg = socket.messages.poll();
+        System.out.printf("Message is [%s]%n",msg);
+        
+        assertThat("Message", msg, containsString("HttpSession = HttpSession"));
+        
+        socket.session.getBasicRemote().sendText("close");
+        assertThat("Await close", socket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
+    }
+}
diff --git a/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties b/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..a3e0efd
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/resources/jetty-logging.properties
@@ -0,0 +1,10 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.jboss.LEVEL=DEBUG
+org.eclipse.jetty.LEVEL=INFO
+
+org.eclipse.jetty.util.DecoratedObjectFactory.LEVEL=DEBUG
+
+# org.eclipse.jetty.LEVEL=DEBUG
+org.eclipse.jetty.websocket.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.client.LEVEL=DEBUG
+
diff --git a/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh
new file mode 100755
index 0000000..3dc240f
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/scripts/setup-jetty.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+JAVA_HOME=$1
+JETTY_HOME=$2
+JETTY_BASE=$3
+
+echo \${java.home}  : $JAVA_HOME
+echo \${jetty.home} : $JETTY_HOME
+echo \${jetty.base} : $JETTY_BASE
+
+cd "$JETTY_BASE"
+
+"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
+    --approve-all-licenses \
+    --add-to-start=deploy,http,annotations,websocket,cdi,logging
+
+"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
+    --version
+
diff --git a/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh
new file mode 100755
index 0000000..ea7843b
--- /dev/null
+++ b/jetty-cdi/test-cdi-it/src/test/scripts/start-jetty.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+JAVA_HOME=$1
+JETTY_HOME=$2
+JETTY_BASE=$3
+
+echo \${java.home}  : $JAVA_HOME
+echo \${jetty.home} : $JETTY_HOME
+echo \${jetty.base} : $JETTY_BASE
+
+cd "$JETTY_BASE"
+
+"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
+    jetty.http.port=58080 \
+    STOP.PORT=58181 STOP.KEY=it
+
+
diff --git a/tests/test-cdi/cdi-webapp-it/src/test/scripts/stop-jetty.sh b/jetty-cdi/test-cdi-it/src/test/scripts/stop-jetty.sh
similarity index 100%
rename from tests/test-cdi/cdi-webapp-it/src/test/scripts/stop-jetty.sh
rename to jetty-cdi/test-cdi-it/src/test/scripts/stop-jetty.sh
diff --git a/jetty-cdi/test-cdi-webapp/pom.xml b/jetty-cdi/test-cdi-webapp/pom.xml
new file mode 100644
index 0000000..9bd9001
--- /dev/null
+++ b/jetty-cdi/test-cdi-webapp/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  // ========================================================================
+  // Copyright (c) Webtide LLC
+  //
+  // 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.apache.org/licenses/LICENSE-2.0.txt
+  //
+  // You may elect to redistribute this code under either of these licenses.
+  // ========================================================================
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.cdi</groupId>
+    <artifactId>jetty-cdi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>test-cdi-webapp</artifactId>
+  <packaging>war</packaging>
+  <name>Jetty :: CDI :: Test :: WebApp</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <bundle-symbolic-name>${project.groupId}.cdi.webapp.noweld</bundle-symbolic-name>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.websocket</groupId>
+      <artifactId>javax.websocket-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.enterprise</groupId>
+      <artifactId>cdi-api</artifactId>
+      <version>1.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jboss.weld.servlet</groupId>
+      <artifactId>weld-servlet</artifactId>
+      <version>${weld.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <finalName>cdi-webapp</finalName>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <!-- DO NOT DEPLOY (or Release) -->
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <executions>
+          <execution>
+            <id>with-weld</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptors>
+                <descriptor>src/assembly/with-weld.xml</descriptor>
+              </descriptors>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+         <groupId>org.eclipse.jetty</groupId>
+         <artifactId>jetty-maven-plugin</artifactId>
+         <version>${project.version}</version>
+         <configuration>
+         </configuration>
+         <dependencies>
+           <dependency>
+               <groupId>org.eclipse.jetty.cdi</groupId>
+               <artifactId>cdi-full-servlet</artifactId>
+               <version>${project.version}</version>
+               <type>pom</type>
+           </dependency>
+         </dependencies>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml b/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml
new file mode 100644
index 0000000..ca17471
--- /dev/null
+++ b/jetty-cdi/test-cdi-webapp/src/assembly/with-weld.xml
@@ -0,0 +1,31 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>with-weld</id>
+  <formats>
+    <format>war</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directory>${project.basedir}/src/main/webapp</directory>
+      <outputDirectory>/</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>${project.build.outputDirectory}</directory>
+      <outputDirectory>/WEB-INF/classes</outputDirectory>
+    </fileSet>
+  </fileSets>
+  <dependencySets>
+    <dependencySet>
+      <outputDirectory>/WEB-INF/lib</outputDirectory>
+      <useProjectArtifact>true</useProjectArtifact>
+      <unpack>false</unpack>
+      <scope>test</scope>
+      <includes>
+        <include>*:cdi-api</include>
+        <include>*:weld-servlet</include>
+      </includes>
+    </dependencySet>
+  </dependencySets>
+</assembly>
diff --git a/tests/test-cdi/cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java
similarity index 100%
rename from tests/test-cdi/cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java
rename to jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/HelloServlet.java
diff --git a/tests/test-cdi/cdi-webapp/src/main/java/org/eclipse/jetty/tests/ServerInfoServlet.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ServerInfoServlet.java
similarity index 100%
rename from tests/test-cdi/cdi-webapp/src/main/java/org/eclipse/jetty/tests/ServerInfoServlet.java
rename to jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ServerInfoServlet.java
diff --git a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULog.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULog.java
new file mode 100644
index 0000000..ac8fab6
--- /dev/null
+++ b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULog.java
@@ -0,0 +1,47 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.tests.logging;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JULog
+{
+    private final Logger log;
+
+    public JULog(Class<?> clazz)
+    {
+        this.log = Logger.getLogger(clazz.getName());
+    }
+
+    public void info(String msg)
+    {
+        log.log(Level.INFO, msg);
+    }
+
+    public void info(String msg, Object ... args)
+    {
+        log.log(Level.INFO, msg, args);
+    }
+
+    public void warn(Throwable t)
+    {
+        log.log(Level.WARNING, "", t);
+    }
+}
diff --git a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULogFactory.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULogFactory.java
new file mode 100644
index 0000000..462e896
--- /dev/null
+++ b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/logging/JULogFactory.java
@@ -0,0 +1,31 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.tests.logging;
+
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+public class JULogFactory
+{
+    @Produces
+    public JULog createJULog(InjectionPoint injectionPoint)
+    {
+        return new JULog(injectionPoint.getMember().getDeclaringClass());
+    }
+}
diff --git a/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java
new file mode 100644
index 0000000..b65ffb8
--- /dev/null
+++ b/jetty-cdi/test-cdi-webapp/src/main/java/org/eclipse/jetty/tests/ws/SessionInfoSocket.java
@@ -0,0 +1,98 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.tests.ws;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpSession;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.RemoteEndpoint;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.eclipse.jetty.tests.logging.JULog;
+
+@ServerEndpoint(value = "/sessioninfo")
+public class SessionInfoSocket
+{
+    @Inject
+    private JULog LOG;
+
+    @Inject
+    private HttpSession httpSession;
+
+    private Session wsSession;
+
+    @OnOpen
+    public void onOpen(Session session)
+    {
+        LOG.info("onOpen({0})",asClassId(session));
+        this.wsSession = session;
+    }
+
+    @OnMessage
+    public void onMessage(String message)
+    {
+        LOG.info("onMessage({0})",quoted(message));
+        
+        try
+        {
+            RemoteEndpoint.Basic remote = wsSession.getBasicRemote();
+            LOG.info("Remote.Basic: {0}", remote);
+            
+            if ("info".equalsIgnoreCase(message))
+            {
+                LOG.info("returning 'info' details");
+                remote.sendText("HttpSession = " + httpSession);
+            }
+            else if ("close".equalsIgnoreCase(message))
+            {
+                LOG.info("closing session");
+                wsSession.close();
+            }
+            else
+            {
+                LOG.info("echoing message as-is");
+                remote.sendText(message);
+            }
+        }
+        catch (Throwable t)
+        {
+            LOG.warn(t);
+        }
+    }
+
+    private String asClassId(Object obj)
+    {
+        if (obj == null)
+        {
+            return "<null>";
+        }
+        return String.format("%s@%X",obj.getClass().getName(),obj.hashCode());
+    }
+
+    private String quoted(String str)
+    {
+        if (str == null)
+        {
+            return "<null>";
+        }
+        return '"' + str + '"';
+    }
+}
diff --git a/tests/test-cdi/cdi-webapp/src/main/webapp/WEB-INF/beans.xml b/jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/beans.xml
similarity index 100%
rename from tests/test-cdi/cdi-webapp/src/main/webapp/WEB-INF/beans.xml
rename to jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/beans.xml
diff --git a/tests/test-cdi/cdi-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/web.xml
similarity index 100%
rename from tests/test-cdi/cdi-webapp/src/main/webapp/WEB-INF/web.xml
rename to jetty-cdi/test-cdi-webapp/src/main/webapp/WEB-INF/web.xml
diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml
index 3ef65d0..0dbd98b 100644
--- a/jetty-client/pom.xml
+++ b/jetty-client/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
 
   <modelVersion>4.0.0</modelVersion>
@@ -16,50 +16,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.net.*,*</Import-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <!-- Required for OSGI -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java
index cf7060f..544ab0a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractHttpClientTransport.java
@@ -19,21 +19,27 @@
 package org.eclipse.jetty.client;
 
 import java.io.IOException;
+import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.net.SocketException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.Map;
 
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectorManager;
 import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
 import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
+@ManagedObject
 public abstract class AbstractHttpClientTransport extends ContainerLifeCycle implements HttpClientTransport
 {
     protected static final Logger LOG = Log.getLogger(HttpClientTransport.class);
@@ -58,6 +64,12 @@
         this.client = client;
     }
 
+    @ManagedAttribute(value = "The number of selectors", readonly = true)
+    public int getSelectors()
+    {
+        return selectors;
+    }
+
     @Override
     protected void doStart() throws Exception
     {
@@ -75,7 +87,7 @@
     }
 
     @Override
-    public void connect(SocketAddress address, Map<String, Object> context)
+    public void connect(InetSocketAddress address, Map<String, Object> context)
     {
         SocketChannel channel = null;
         try
@@ -110,6 +122,11 @@
         // UnresolvedAddressException are not IOExceptions.
         catch (Throwable x)
         {
+            // If IPv6 is not deployed, a generic SocketException "Network is unreachable"
+            // exception is being thrown, so we attempt to provide a better error message.
+            if (x.getClass() == SocketException.class)
+                x = new SocketException("Could not connect to " + address).initCause(x);
+
             try
             {
                 if (channel != null)
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
index 72e2aa0..9d7c297 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java
@@ -37,7 +37,7 @@
 
 public abstract class AuthenticationProtocolHandler implements ProtocolHandler
 {
-    public static final int DEFAULT_MAX_CONTENT_LENGTH = 4096;
+    public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024;
     public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
     private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]+)\"(.*)", Pattern.CASE_INSENSITIVE);
     private static final String AUTHENTICATION_ATTRIBUTE = AuthenticationProtocolHandler.class.getName() + ".authentication";
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
index 5cf879f..f85c32f 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ConnectionPool.java
@@ -18,393 +18,17 @@
 
 package org.eclipse.jetty.client;
 
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.BlockingDeque;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Destination;
-import org.eclipse.jetty.util.BlockingArrayQueue;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.component.Dumpable;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.Sweeper;
+import org.eclipse.jetty.util.Callback;
 
-public class ConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
+/**
+ * @deprecated use {@link DuplexConnectionPool} instead
+ */
+@Deprecated
+public class ConnectionPool extends DuplexConnectionPool
 {
-    protected static final Logger LOG = Log.getLogger(ConnectionPool.class);
-
-    private final AtomicInteger connectionCount = new AtomicInteger();
-    private final ReentrantLock lock = new ReentrantLock();
-    private final Destination destination;
-    private final int maxConnections;
-    private final Promise<Connection> requester;
-    private final BlockingDeque<Connection> idleConnections;
-    private final BlockingQueue<Connection> activeConnections;
-
-    public ConnectionPool(Destination destination, int maxConnections, Promise<Connection> requester)
+    public ConnectionPool(Destination destination, int maxConnections, Callback requester)
     {
-        this.destination = destination;
-        this.maxConnections = maxConnections;
-        this.requester = requester;
-        this.idleConnections = new LinkedBlockingDeque<>(maxConnections);
-        this.activeConnections = new BlockingArrayQueue<>(maxConnections);
-    }
-
-    public int getConnectionCount()
-    {
-        return connectionCount.get();
-    }
-
-    public BlockingQueue<Connection> getIdleConnections()
-    {
-        return idleConnections;
-    }
-
-    public BlockingQueue<Connection> getActiveConnections()
-    {
-        return activeConnections;
-    }
-
-    public Connection acquire()
-    {
-        Connection connection = activateIdle();
-        if (connection == null)
-            connection = tryCreate();
-        return connection;
-    }
-
-    private Connection tryCreate()
-    {
-        while (true)
-        {
-            int current = getConnectionCount();
-            final int next = current + 1;
-
-            if (next > maxConnections)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Max connections {}/{} reached", current, maxConnections);
-                // Try again the idle connections
-                return activateIdle();
-            }
-
-            if (connectionCount.compareAndSet(current, next))
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Connection {}/{} creation", next, maxConnections);
-
-                destination.newConnection(new Promise<Connection>()
-                {
-                    @Override
-                    public void succeeded(Connection connection)
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Connection {}/{} creation succeeded {}", next, maxConnections, connection);
-
-                        idleCreated(connection);
-
-                        requester.succeeded(connection);
-                    }
-
-                    @Override
-                    public void failed(Throwable x)
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Connection " + next + "/" + maxConnections + " creation failed", x);
-
-                        connectionCount.decrementAndGet();
-
-                        requester.failed(x);
-                    }
-                });
-
-                // Try again the idle connections
-                return activateIdle();
-            }
-        }
-    }
-
-    protected void idleCreated(Connection connection)
-    {
-        boolean idle;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            // Use "cold" new connections as last.
-            idle = idleConnections.offerLast(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        idle(connection, idle);
-    }
-
-    private Connection activateIdle()
-    {
-        boolean acquired;
-        Connection connection;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            connection = idleConnections.pollFirst();
-            if (connection == null)
-                return null;
-            acquired = activeConnections.offer(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        if (acquired)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Connection active {}", connection);
-            acquired(connection);
-            return connection;
-        }
-        else
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Connection active overflow {}", connection);
-            connection.close();
-            return null;
-        }
-    }
-
-    protected void acquired(Connection connection)
-    {
-    }
-
-    public boolean release(Connection connection)
-    {
-        boolean idle;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            if (!activeConnections.remove(connection))
-                return false;
-            // Make sure we use "hot" connections first.
-            idle = idleConnections.offerFirst(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        released(connection);
-        return idle(connection, idle);
-    }
-
-    protected boolean idle(Connection connection, boolean idle)
-    {
-        if (idle)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Connection idle {}", connection);
-            return true;
-        }
-        else
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Connection idle overflow {}", connection);
-            connection.close();
-            return false;
-        }
-    }
-
-    protected void released(Connection connection)
-    {
-    }
-
-    public boolean remove(Connection connection)
-    {
-        boolean activeRemoved;
-        boolean idleRemoved;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            activeRemoved = activeConnections.remove(connection);
-            idleRemoved = idleConnections.remove(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        if (activeRemoved)
-            released(connection);
-        boolean removed = activeRemoved || idleRemoved;
-        if (removed)
-        {
-            int pooled = connectionCount.decrementAndGet();
-            if (LOG.isDebugEnabled())
-                LOG.debug("Connection removed {} - pooled: {}", connection, pooled);
-        }
-        return removed;
-    }
-
-    public boolean isActive(Connection connection)
-    {
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            return activeConnections.contains(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-    }
-
-    public boolean isIdle(Connection connection)
-    {
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            return idleConnections.contains(connection);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-    }
-
-    public boolean isEmpty()
-    {
-        return connectionCount.get() == 0;
-    }
-
-    public void close()
-    {
-        List<Connection> idles = new ArrayList<>();
-        List<Connection> actives = new ArrayList<>();
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            idles.addAll(idleConnections);
-            idleConnections.clear();
-            actives.addAll(activeConnections);
-            activeConnections.clear();
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        connectionCount.set(0);
-
-        for (Connection connection : idles)
-            connection.close();
-
-        // A bit drastic, but we cannot wait for all requests to complete
-        for (Connection connection : actives)
-            connection.close();
-    }
-
-    @Override
-    public String dump()
-    {
-        return ContainerLifeCycle.dump(this);
-    }
-
-    @Override
-    public void dump(Appendable out, String indent) throws IOException
-    {
-        List<Connection> actives = new ArrayList<>();
-        List<Connection> idles = new ArrayList<>();
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            actives.addAll(activeConnections);
-            idles.addAll(idleConnections);
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        ContainerLifeCycle.dumpObject(out, this);
-        ContainerLifeCycle.dump(out, indent, actives, idles);
-    }
-
-    @Override
-    public boolean sweep()
-    {
-        List<Sweeper.Sweepable> toSweep = new ArrayList<>();
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            for (Connection connection : getActiveConnections())
-            {
-                if (connection instanceof Sweeper.Sweepable)
-                    toSweep.add(((Sweeper.Sweepable)connection));
-            }
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        for (Sweeper.Sweepable candidate : toSweep)
-        {
-            if (candidate.sweep())
-            {
-                boolean removed = getActiveConnections().remove(candidate);
-                LOG.warn("Connection swept: {}{}{} from active connections{}{}",
-                        candidate,
-                        System.lineSeparator(),
-                        removed ? "Removed" : "Not removed",
-                        System.lineSeparator(),
-                        dump());
-            }
-        }
-
-        return false;
-    }
-
-    @Override
-    public String toString()
-    {
-        int activeSize;
-        int idleSize;
-        final ReentrantLock lock = this.lock;
-        lock.lock();
-        try
-        {
-            activeSize = activeConnections.size();
-            idleSize = idleConnections.size();
-        }
-        finally
-        {
-            lock.unlock();
-        }
-
-        return String.format("%s[c=%d/%d,a=%d,i=%d]",
-                getClass().getSimpleName(),
-                connectionCount.get(),
-                maxConnections,
-                activeSize,
-                idleSize);
+        super(destination, maxConnections, requester);
     }
 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java
index e68861b..80d999a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContentDecoder.java
@@ -37,10 +37,10 @@
 
     /**
      * Factory for {@link ContentDecoder}s; subclasses must implement {@link #newContentDecoder()}.
-     * <p />
+     * <p>
      * {@link Factory} have an {@link #getEncoding() encoding}, which is the string used in
      * {@code Accept-Encoding} request header and in {@code Content-Encoding} response headers.
-     * <p />
+     * <p>
      * {@link Factory} instances are configured in {@link HttpClient} via
      * {@link HttpClient#getContentDecoderFactories()}.
      */
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java
index 7f9a899..354852d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java
@@ -27,20 +27,28 @@
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
 
+/**
+ * <p>A protocol handler that handles the 100 response code.</p>
+ */
 public class ContinueProtocolHandler implements ProtocolHandler
 {
+    public static final String NAME = "continue";
     private static final String ATTRIBUTE = ContinueProtocolHandler.class.getName() + ".100continue";
 
-    private final HttpClient client;
     private final ResponseNotifier notifier;
 
-    public ContinueProtocolHandler(HttpClient client)
+    public ContinueProtocolHandler()
     {
-        this.client = client;
         this.notifier = new ResponseNotifier();
     }
 
     @Override
+    public String getName()
+    {
+        return NAME;
+    }
+
+    @Override
     public boolean accept(Request request, Response response)
     {
         boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java
new file mode 100644
index 0000000..efe7cf6
--- /dev/null
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/DuplexConnectionPool.java
@@ -0,0 +1,458 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.jetty.client.api.Connection;
+import org.eclipse.jetty.client.api.Destination;
+import org.eclipse.jetty.util.BlockingArrayQueue;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Sweeper;
+
+@ManagedObject("The connection pool")
+public class DuplexConnectionPool implements Closeable, Dumpable, Sweeper.Sweepable
+{
+    private static final Logger LOG = Log.getLogger(DuplexConnectionPool.class);
+
+    private final AtomicInteger connectionCount = new AtomicInteger();
+    private final ReentrantLock lock = new ReentrantLock();
+    private final Destination destination;
+    private final int maxConnections;
+    private final Callback requester;
+    private final Deque<Connection> idleConnections;
+    private final Queue<Connection> activeConnections;
+
+    public DuplexConnectionPool(Destination destination, int maxConnections, Callback requester)
+    {
+        this.destination = destination;
+        this.maxConnections = maxConnections;
+        this.requester = requester;
+        this.idleConnections = new LinkedBlockingDeque<>(maxConnections);
+        this.activeConnections = new BlockingArrayQueue<>(maxConnections);
+    }
+
+    @ManagedAttribute(value = "The number of connections", readonly = true)
+    public int getConnectionCount()
+    {
+        return connectionCount.get();
+    }
+
+    @ManagedAttribute(value = "The number of idle connections", readonly = true)
+    public int getIdleConnectionCount()
+    {
+        lock();
+        try
+        {
+            return idleConnections.size();
+        }
+        finally
+        {
+            unlock();
+        }
+    }
+
+    @ManagedAttribute(value = "The number of active connections", readonly = true)
+    public int getActiveConnectionCount()
+    {
+        lock();
+        try
+        {
+            return activeConnections.size();
+        }
+        finally
+        {
+            unlock();
+        }
+    }
+
+    public Queue<Connection> getIdleConnections()
+    {
+        return idleConnections;
+    }
+
+    public Queue<Connection> getActiveConnections()
+    {
+        return activeConnections;
+    }
+
+    public Connection acquire()
+    {
+        Connection connection = activateIdle();
+        if (connection == null)
+            connection = tryCreate();
+        return connection;
+    }
+
+    private Connection tryCreate()
+    {
+        while (true)
+        {
+            int current = getConnectionCount();
+            final int next = current + 1;
+
+            if (next > maxConnections)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Max connections {}/{} reached", current, maxConnections);
+                // Try again the idle connections
+                return activateIdle();
+            }
+
+            if (connectionCount.compareAndSet(current, next))
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Connection {}/{} creation", next, maxConnections);
+
+                destination.newConnection(new Promise<Connection>()
+                {
+                    @Override
+                    public void succeeded(Connection connection)
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Connection {}/{} creation succeeded {}", next, maxConnections, connection);
+
+                        idleCreated(connection);
+
+                        proceed();
+                    }
+
+                    @Override
+                    public void failed(Throwable x)
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Connection " + next + "/" + maxConnections + " creation failed", x);
+
+                        connectionCount.decrementAndGet();
+
+                        requester.failed(x);
+                    }
+                });
+
+                // Try again the idle connections
+                return activateIdle();
+            }
+        }
+    }
+
+    protected void proceed()
+    {
+        requester.succeeded();
+    }
+
+    protected void idleCreated(Connection connection)
+    {
+        boolean idle;
+        lock();
+        try
+        {
+            // Use "cold" new connections as last.
+            idle = idleConnections.offerLast(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        idle(connection, idle);
+    }
+
+    private Connection activateIdle()
+    {
+        boolean acquired;
+        Connection connection;
+        lock();
+        try
+        {
+            connection = idleConnections.pollFirst();
+            if (connection == null)
+                return null;
+            acquired = activeConnections.offer(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        if (acquired)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connection active {}", connection);
+            acquired(connection);
+            return connection;
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connection active overflow {}", connection);
+            connection.close();
+            return null;
+        }
+    }
+
+    protected void acquired(Connection connection)
+    {
+    }
+
+    public boolean release(Connection connection)
+    {
+        boolean idle;
+        lock();
+        try
+        {
+            if (!activeConnections.remove(connection))
+                return false;
+            // Make sure we use "hot" connections first.
+            idle = offerIdle(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        released(connection);
+        return idle(connection, idle);
+    }
+
+    protected boolean offerIdle(Connection connection)
+    {
+        return idleConnections.offerFirst(connection);
+    }
+
+    protected boolean idle(Connection connection, boolean idle)
+    {
+        if (idle)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connection idle {}", connection);
+            return true;
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connection idle overflow {}", connection);
+            connection.close();
+            return false;
+        }
+    }
+
+    protected void released(Connection connection)
+    {
+    }
+
+    public boolean remove(Connection connection)
+    {
+        return remove(connection, false);
+    }
+
+    protected boolean remove(Connection connection, boolean force)
+    {
+        boolean activeRemoved;
+        boolean idleRemoved;
+        lock();
+        try
+        {
+            activeRemoved = activeConnections.remove(connection);
+            idleRemoved = idleConnections.remove(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        if (activeRemoved || force)
+            released(connection);
+        boolean removed = activeRemoved || idleRemoved || force;
+        if (removed)
+        {
+            int pooled = connectionCount.decrementAndGet();
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connection removed {} - pooled: {}", connection, pooled);
+        }
+        return removed;
+    }
+
+    public boolean isActive(Connection connection)
+    {
+        lock();
+        try
+        {
+            return activeConnections.contains(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+    }
+
+    public boolean isIdle(Connection connection)
+    {
+        lock();
+        try
+        {
+            return idleConnections.contains(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+    }
+
+    public boolean isEmpty()
+    {
+        return connectionCount.get() == 0;
+    }
+
+    public void close()
+    {
+        List<Connection> idles = new ArrayList<>();
+        List<Connection> actives = new ArrayList<>();
+        lock();
+        try
+        {
+            idles.addAll(idleConnections);
+            idleConnections.clear();
+            actives.addAll(activeConnections);
+            activeConnections.clear();
+        }
+        finally
+        {
+            unlock();
+        }
+
+        connectionCount.set(0);
+
+        for (Connection connection : idles)
+            connection.close();
+
+        // A bit drastic, but we cannot wait for all requests to complete
+        for (Connection connection : actives)
+            connection.close();
+    }
+
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        List<Connection> actives = new ArrayList<>();
+        List<Connection> idles = new ArrayList<>();
+        lock();
+        try
+        {
+            actives.addAll(activeConnections);
+            idles.addAll(idleConnections);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        ContainerLifeCycle.dumpObject(out, this);
+        ContainerLifeCycle.dump(out, indent, actives, idles);
+    }
+
+    @Override
+    public boolean sweep()
+    {
+        List<Connection> toSweep = new ArrayList<>();
+        lock();
+        try
+        {
+            for (Connection connection : activeConnections)
+            {
+                if (connection instanceof Sweeper.Sweepable)
+                    toSweep.add(connection);
+            }
+        }
+        finally
+        {
+            unlock();
+        }
+
+        for (Connection connection : toSweep)
+        {
+            if (((Sweeper.Sweepable)connection).sweep())
+            {
+                boolean removed = remove(connection, true);
+                LOG.warn("Connection swept: {}{}{} from active connections{}{}",
+                        connection,
+                        System.lineSeparator(),
+                        removed ? "Removed" : "Not removed",
+                        System.lineSeparator(),
+                        dump());
+            }
+        }
+
+        return false;
+    }
+
+    protected void lock()
+    {
+        lock.lock();
+    }
+
+    protected void unlock()
+    {
+        lock.unlock();
+    }
+
+    @Override
+    public String toString()
+    {
+        int activeSize;
+        int idleSize;
+        lock();
+        try
+        {
+            activeSize = activeConnections.size();
+            idleSize = idleConnections.size();
+        }
+        finally
+        {
+            unlock();
+        }
+
+        return String.format("%s[c=%d/%d,a=%d,i=%d]",
+                getClass().getSimpleName(),
+                connectionCount.get(),
+                maxConnections,
+                activeSize,
+                idleSize);
+    }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
index 697b30a..3852ecd 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java
@@ -18,10 +18,10 @@
 
 package org.eclipse.jetty.client;
 
-import java.io.IOException;
 import java.net.CookieManager;
 import java.net.CookiePolicy;
 import java.net.CookieStore;
+import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
 import java.net.URI;
@@ -62,6 +62,8 @@
 import org.eclipse.jetty.util.Jetty;
 import org.eclipse.jetty.util.Promise;
 import org.eclipse.jetty.util.SocketAddressResolver;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -106,12 +108,13 @@
  * });
  * </pre>
  */
+@ManagedObject("The HTTP client")
 public class HttpClient extends ContainerLifeCycle
 {
     private static final Logger LOG = Log.getLogger(HttpClient.class);
 
     private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
-    private final List<ProtocolHandler> handlers = new ArrayList<>();
+    private final ProtocolHandlers handlers = new ProtocolHandlers();
     private final List<Request.Listener> requestListeners = new ArrayList<>();
     private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
     private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
@@ -136,7 +139,6 @@
     private volatile long addressResolutionTimeout = 15000;
     private volatile long idleTimeout;
     private volatile boolean tcpNoDelay = true;
-    private volatile boolean dispatchIO = true;
     private volatile boolean strictEventOrdering = false;
     private volatile HttpField encodingField;
     private volatile boolean removeIdleDestinations = false;
@@ -216,10 +218,10 @@
             resolver = new SocketAddressResolver.Async(executor, scheduler, getAddressResolutionTimeout());
         addBean(resolver);
 
-        handlers.add(new ContinueProtocolHandler(this));
-        handlers.add(new RedirectProtocolHandler(this));
-        handlers.add(new WWWAuthenticationProtocolHandler(this));
-        handlers.add(new ProxyAuthenticationProtocolHandler(this));
+        handlers.put(new ContinueProtocolHandler());
+        handlers.put(new RedirectProtocolHandler(this));
+        handlers.put(new WWWAuthenticationProtocolHandler(this));
+        handlers.put(new ProxyAuthenticationProtocolHandler(this));
 
         decoderFactories.add(new GZIPContentDecoder.Factory());
 
@@ -315,6 +317,9 @@
      *
      * @param uri the URI to GET
      * @return the {@link ContentResponse} for the request
+     * @throws InterruptedException if send threading has been interrupted
+     * @throws ExecutionException the execution failed
+     * @throws TimeoutException the send timed out
      * @see #GET(URI)
      */
     public ContentResponse GET(String uri) throws InterruptedException, ExecutionException, TimeoutException
@@ -327,6 +332,9 @@
      *
      * @param uri the URI to GET
      * @return the {@link ContentResponse} for the request
+     * @throws InterruptedException if send threading has been interrupted
+     * @throws ExecutionException the execution failed
+     * @throws TimeoutException the send timed out
      * @see #newRequest(URI)
      */
     public ContentResponse GET(URI uri) throws InterruptedException, ExecutionException, TimeoutException
@@ -340,6 +348,9 @@
      * @param uri the URI to POST
      * @param fields the fields composing the form name/value pairs
      * @return the {@link ContentResponse} for the request
+     * @throws InterruptedException if send threading has been interrupted
+     * @throws ExecutionException the execution failed
+     * @throws TimeoutException the send timed out
      */
     public ContentResponse FORM(String uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
     {
@@ -352,6 +363,9 @@
      * @param uri the URI to POST
      * @param fields the fields composing the form name/value pairs
      * @return the {@link ContentResponse} for the request
+     * @throws InterruptedException if send threading has been interrupted
+     * @throws ExecutionException the execution failed
+     * @throws TimeoutException the send timed out
      */
     public ContentResponse FORM(URI uri, Fields fields) throws InterruptedException, ExecutionException, TimeoutException
     {
@@ -483,28 +497,25 @@
         if (destination == null)
         {
             destination = transport.newHttpDestination(origin);
-            if (isRunning())
+            addManaged(destination);
+            HttpDestination existing = destinations.putIfAbsent(origin, destination);
+            if (existing != null)
             {
-                HttpDestination existing = destinations.putIfAbsent(origin, destination);
-                if (existing != null)
-                {
-                    destination = existing;
-                }
-                else
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Created {}", destination);
-                }
-                if (!isRunning())
-                    destinations.remove(origin);
+                removeBean(destination);
+                destination = existing;
             }
-
+            else
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Created {}", destination);
+            }
         }
         return destination;
     }
 
     protected boolean removeDestination(HttpDestination destination)
     {
+        removeBean(destination);
         return destinations.remove(destination.getOrigin()) != null;
     }
 
@@ -530,15 +541,14 @@
     protected void newConnection(final HttpDestination destination, final Promise<Connection> promise)
     {
         Origin.Address address = destination.getConnectAddress();
-        resolver.resolve(address.getHost(), address.getPort(), new Promise<SocketAddress>()
+        resolver.resolve(address.getHost(), address.getPort(), new Promise<List<InetSocketAddress>>()
         {
             @Override
-            public void succeeded(SocketAddress socketAddress)
+            public void succeeded(List<InetSocketAddress> socketAddresses)
             {
                 Map<String, Object> context = new HashMap<>();
                 context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, destination);
-                context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, promise);
-                transport.connect(socketAddress, context);
+                connect(socketAddresses, 0, context);
             }
 
             @Override
@@ -546,6 +556,29 @@
             {
                 promise.failed(x);
             }
+
+            private void connect(List<InetSocketAddress> socketAddresses, int index, Map<String, Object> context)
+            {
+                context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise<Connection>()
+                {
+                    @Override
+                    public void succeeded(Connection result)
+                    {
+                        promise.succeeded(result);
+                    }
+
+                    @Override
+                    public void failed(Throwable x)
+                    {
+                        int nextIndex = index + 1;
+                        if (nextIndex == socketAddresses.size())
+                            promise.failed(x);
+                        else
+                            connect(socketAddresses, nextIndex, context);
+                    }
+                });
+                transport.connect(socketAddresses.get(index), context);
+            }
         });
     }
 
@@ -554,22 +587,14 @@
         return new HttpConversation();
     }
 
-    public List<ProtocolHandler> getProtocolHandlers()
+    public ProtocolHandlers getProtocolHandlers()
     {
         return handlers;
     }
 
     protected ProtocolHandler findProtocolHandler(Request request, Response response)
     {
-        // Optimized to avoid allocations of iterator instances
-        List<ProtocolHandler> protocolHandlers = getProtocolHandlers();
-        for (int i = 0; i < protocolHandlers.size(); ++i)
-        {
-            ProtocolHandler handler = protocolHandlers.get(i);
-            if (handler.accept(request, response))
-                return handler;
-        }
-        return null;
+        return handlers.find(request, response);
     }
 
     /**
@@ -591,6 +616,7 @@
     /**
      * @return the max time, in milliseconds, a connection can take to connect to destinations
      */
+    @ManagedAttribute("The timeout, in milliseconds, for connect() operations")
     public long getConnectTimeout()
     {
         return connectTimeout;
@@ -631,6 +657,7 @@
     /**
      * @return the max time, in milliseconds, a connection can be idle (that is, without traffic of bytes in either direction)
      */
+    @ManagedAttribute("The timeout, in milliseconds, to close idle connections")
     public long getIdleTimeout()
     {
         return idleTimeout;
@@ -685,6 +712,7 @@
      * @return whether this {@link HttpClient} follows HTTP redirects
      * @see Request#isFollowRedirects()
      */
+    @ManagedAttribute("Whether HTTP redirects are followed")
     public boolean isFollowRedirects()
     {
         return followRedirects;
@@ -750,6 +778,7 @@
     /**
      * @return the max number of connections that this {@link HttpClient} opens to {@link Destination}s
      */
+    @ManagedAttribute("The max number of connections per each destination")
     public int getMaxConnectionsPerDestination()
     {
         return maxConnectionsPerDestination;
@@ -757,7 +786,7 @@
 
     /**
      * Sets the max number of connections to open to each destinations.
-     * <p />
+     * <p>
      * RFC 2616 suggests that 2 connections should be opened per each destination,
      * but browsers commonly open 6.
      * If this {@link HttpClient} is used for load testing, it is common to have only one destination
@@ -774,6 +803,7 @@
     /**
      * @return the max number of requests that may be queued to a {@link Destination}.
      */
+    @ManagedAttribute("The max number of requests queued per each destination")
     public int getMaxRequestsQueuedPerDestination()
     {
         return maxRequestsQueuedPerDestination;
@@ -781,7 +811,7 @@
 
     /**
      * Sets the max number of requests that may be queued to a destination.
-     * <p />
+     * <p>
      * If this {@link HttpClient} performs a high rate of requests to a destination,
      * and all the connections managed by that destination are busy with other requests,
      * then new requests will be queued up in the destination.
@@ -800,6 +830,7 @@
     /**
      * @return the size of the buffer used to write requests
      */
+    @ManagedAttribute("The request buffer size")
     public int getRequestBufferSize()
     {
         return requestBufferSize;
@@ -816,6 +847,7 @@
     /**
      * @return the size of the buffer used to read responses
      */
+    @ManagedAttribute("The response buffer size")
     public int getResponseBufferSize()
     {
         return responseBufferSize;
@@ -850,6 +882,7 @@
     /**
      * @return whether TCP_NODELAY is enabled
      */
+    @ManagedAttribute(value = "Whether the TCP_NODELAY option is enabled", name = "tcpNoDelay")
     public boolean isTCPNoDelay()
     {
         return tcpNoDelay;
@@ -868,14 +901,16 @@
      * @return true to dispatch I/O operations in a different thread, false to execute them in the selector thread
      * @see #setDispatchIO(boolean)
      */
+    @Deprecated
     public boolean isDispatchIO()
     {
-        return dispatchIO;
+        // TODO this did default to true, so usage needs to be evaluated.
+        return false;
     }
 
     /**
      * Whether to dispatch I/O operations from the selector thread to a different thread.
-     * <p />
+     * <p>
      * This implementation never blocks on I/O operation, but invokes application callbacks that may
      * take time to execute or block on other I/O.
      * If application callbacks are known to take time or block on I/O, then parameter {@code dispatchIO}
@@ -886,15 +921,16 @@
      * @param dispatchIO true to dispatch I/O operations in a different thread,
      *                   false to execute them in the selector thread
      */
+    @Deprecated
     public void setDispatchIO(boolean dispatchIO)
     {
-        this.dispatchIO = dispatchIO;
     }
 
     /**
      * @return whether request events must be strictly ordered
      * @see #setStrictEventOrdering(boolean)
      */
+    @ManagedAttribute("Whether request/response events must be strictly ordered")
     public boolean isStrictEventOrdering()
     {
         return strictEventOrdering;
@@ -902,17 +938,17 @@
 
     /**
      * Whether request/response events must be strictly ordered with respect to connection usage.
-     * <p />
+     * <p>
      * From the point of view of connection usage, the connection can be reused just before the
      * "complete" event notified to {@link org.eclipse.jetty.client.api.Response.CompleteListener}s
      * (but after the "success" event).
-     * <p />
+     * <p>
      * When a request/response exchange is completing, the destination may have another request
      * queued to be sent to the server.
      * If the connection for that destination is reused for the second request before the "complete"
      * event of the first exchange, it may happen that the "begin" event of the second request
      * happens before the "complete" event of the first exchange.
-     * <p />
+     * <p>
      * Enforcing strict ordering of events so that a "begin" event of a request can never happen
      * before the "complete" event of the previous exchange comes with the cost of increased
      * connection usage.
@@ -921,7 +957,7 @@
      * when the connection cannot yet be reused.
      * When strict event ordering is not enforced, the redirect request will reuse the already
      * open connection making the system more efficient.
-     * <p />
+     * <p>
      * The default value for this property is {@code false}.
      *
      * @param strictEventOrdering whether request/response events must be strictly ordered
@@ -935,6 +971,7 @@
      * @return whether destinations that have no connections should be removed
      * @see #setRemoveIdleDestinations(boolean)
      */
+    @ManagedAttribute("Whether idle destinations are removed")
     public boolean isRemoveIdleDestinations()
     {
         return removeIdleDestinations;
@@ -942,7 +979,7 @@
 
     /**
      * Whether destinations that have no connections (nor active nor idle) should be removed.
-     * <p />
+     * <p>
      * Applications typically make request to a limited number of destinations so keeping
      * destinations around is not a problem for the memory or the GC.
      * However, for applications that hit millions of different destinations (e.g. a spider
@@ -950,7 +987,7 @@
      * anymore and leave space for new destinations.
      *
      * @param removeIdleDestinations whether destinations that have no connections should be removed
-     * @see org.eclipse.jetty.client.ConnectionPool
+     * @see org.eclipse.jetty.client.DuplexConnectionPool
      */
     public void setRemoveIdleDestinations(boolean removeIdleDestinations)
     {
@@ -960,6 +997,7 @@
     /**
      * @return whether {@code connect()} operations are performed in blocking mode
      */
+    @ManagedAttribute("Whether the connect() operation is blocking")
     public boolean isConnectBlocking()
     {
         return connectBlocking;
@@ -1005,18 +1043,11 @@
         return port > 0 ? port : HttpScheme.HTTPS.is(scheme) ? 443 : 80;
     }
 
-    protected boolean isDefaultPort(String scheme, int port)
+    public boolean isDefaultPort(String scheme, int port)
     {
         return HttpScheme.HTTPS.is(scheme) ? port == 443 : port == 80;
     }
 
-    @Override
-    public void dump(Appendable out, String indent) throws IOException
-    {
-        dumpThis(out);
-        dump(out, indent, getBeans(), destinations.values());
-    }
-
     private class ContentDecoderFactorySet implements Set<ContentDecoder.Factory>
     {
         private final Set<ContentDecoder.Factory> set = new HashSet<>();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
index 4e7d7b4..7bbb22a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.client;
 
-import java.net.SocketAddress;
+import java.net.InetSocketAddress;
 import java.util.Map;
 
 import org.eclipse.jetty.io.ClientConnectionFactory;
@@ -26,13 +26,13 @@
 /**
  * {@link HttpClientTransport} represents what transport implementations should provide
  * in order to plug-in a different transport for {@link HttpClient}.
- * <p/>
+ * <p>
  * While the {@link HttpClient} APIs define the HTTP semantic (request, response, headers, etc.)
  * <em>how</em> a HTTP exchange is carried over the network depends on implementations of this class.
- * <p/>
+ * <p>
  * The default implementation uses the HTTP protocol to carry over the network the HTTP exchange,
- * but the HTTP exchange may also be carried using the SPDY protocol or the FCGI protocol or, in future,
- * other protocols.
+ * but the HTTP exchange may also be carried using the FCGI protocol, the HTTP/2 protocol or,
+ * in future, other protocols.
  */
 public interface HttpClientTransport extends ClientConnectionFactory
 {
@@ -41,7 +41,7 @@
 
     /**
      * Sets the {@link HttpClient} instance on this transport.
-     * <p />
+     * <p>
      * This is needed because of a chicken-egg problem: in order to create the {@link HttpClient}
      * a {@link HttpClientTransport} is needed, that therefore cannot have a reference yet to the
      * {@link HttpClient}.
@@ -52,9 +52,9 @@
 
     /**
      * Creates a new, transport-specific, {@link HttpDestination} object.
-     * <p />
+     * <p>
      * {@link HttpDestination} controls the destination-connection cardinality: protocols like
-     * HTTP have 1-N cardinality, while multiplexed protocols like SPDY have a 1-1 cardinality.
+     * HTTP have 1-N cardinality, while multiplexed protocols like HTTP/2 have a 1-1 cardinality.
      *
      * @param origin the destination origin
      * @return a new, transport-specific, {@link HttpDestination} object
@@ -64,8 +64,8 @@
     /**
      * Establishes a physical connection to the given {@code address}.
      *
-     * @param address the address to connect to
+     *  @param address the address to connect to
      * @param context the context information to establish the connection
      */
-    public void connect(SocketAddress address, Map<String, Object> context);
+    public void connect(InetSocketAddress address, Map<String, Object> context);
 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
index 81cde39..0759622 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java
@@ -23,6 +23,8 @@
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.eclipse.jetty.client.api.Authentication;
 import org.eclipse.jetty.client.api.Connection;
@@ -35,11 +37,15 @@
 import org.eclipse.jetty.http.HttpHeaderValue;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
 public abstract class HttpConnection implements Connection
 {
+    private static final Logger LOG = Log.getLogger(HttpConnection.class);
     private static final HttpField CHUNKED_FIELD = new HttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED);
 
+    private final AtomicInteger idleTimeoutState = new AtomicInteger();
     private final HttpDestination destination;
 
     protected HttpConnection(HttpDestination destination)
@@ -72,10 +78,12 @@
 
         HttpExchange exchange = new HttpExchange(getHttpDestination(), (HttpRequest)request, listeners);
 
-        send(exchange);
+        SendFailure result = send(exchange);
+        if (result != null)
+            request.abort(result.failure);
     }
 
-    protected abstract void send(HttpExchange exchange);
+    protected abstract SendFailure send(HttpExchange exchange);
 
     protected void normalizeRequest(Request request)
     {
@@ -167,6 +175,54 @@
         return builder;
     }
 
+    protected SendFailure send(HttpChannel channel, HttpExchange exchange)
+    {
+        // Forbid idle timeouts for the time window where
+        // the request is associated to the channel and sent.
+        // Use a counter to support multiplexed requests.
+        boolean send = false;
+        while (true)
+        {
+            int current = idleTimeoutState.get();
+            if (current < 0)
+                break;
+            if (idleTimeoutState.compareAndSet(current, current + 1))
+            {
+                send = true;
+                break;
+            }
+        }
+
+        if (send)
+        {
+            HttpRequest request = exchange.getRequest();
+            SendFailure result;
+            if (channel.associate(exchange))
+            {
+                channel.send();
+                result = null;
+            }
+            else
+            {
+                channel.release();
+                result = new SendFailure(new HttpRequestException("Could not associate request to connection", request), false);
+            }
+            idleTimeoutState.decrementAndGet();
+            return result;
+        }
+        else
+        {
+            return new SendFailure(new TimeoutException(), true);
+        }
+    }
+
+    public boolean onIdleTimeout()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Idle timeout state {} - {}", idleTimeoutState, this);
+        return idleTimeoutState.compareAndSet(0, -1);
+    }
+
     @Override
     public String toString()
     {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
index e422ce5..922b458 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java
@@ -33,7 +33,7 @@
  * {@link HttpContent} is a stateful, linear representation of the request content provided
  * by a {@link ContentProvider} that can be traversed one-way to obtain content buffers to
  * send to a HTTP server.
- * <p />
+ * <p>
  * {@link HttpContent} offers the notion of a one-way cursor to traverse the content.
  * The cursor starts in a virtual "before" position and can be advanced using {@link #advance()}
  * until it reaches a virtual "after" position where the content is fully consumed.
@@ -42,7 +42,7 @@
  *      |   |  |   |  |   |  |   |  |   |
  *      +---+  +---+  +---+  +---+  +---+
  *   ^           ^                    ^    ^
- *   |           | --> advance()      |    |
+ *   |           | --&gt; advance()      |    |
  *   |           |                  last   |
  *   |           |                         |
  * before        |                        after
@@ -57,7 +57,7 @@
  * </ul>
  * {@link HttpContent} may not have content, if the related {@link ContentProvider} is {@code null}, and this
  * is reflected by {@link #hasContent()}.
- * <p />
+ * <p>
  * {@link HttpContent} may have {@link AsyncContentProvider deferred content}, in which case {@link #advance()}
  * moves the cursor to a position that provides {@code null} {@link #getByteBuffer() buffer} and
  * {@link #getContent() content}. When the deferred content is available, a further call to {@link #advance()}
@@ -67,11 +67,13 @@
 {
     private static final Logger LOG = Log.getLogger(HttpContent.class);
     private static final ByteBuffer AFTER = ByteBuffer.allocate(0);
+    private static final ByteBuffer CLOSE = ByteBuffer.allocate(0);
 
     private final ContentProvider provider;
     private final Iterator<ByteBuffer> iterator;
     private ByteBuffer buffer;
-    private volatile ByteBuffer content;
+    private ByteBuffer content;
+    private boolean last;
 
     public HttpContent(ContentProvider provider)
     {
@@ -92,7 +94,7 @@
      */
     public boolean isLast()
     {
-        return !iterator.hasNext();
+        return last;
     }
 
     /**
@@ -113,52 +115,61 @@
 
     /**
      * Advances the cursor to the next block of content.
-     * <p />
+     * <p>
      * The next block of content may be valid (which yields a non-null buffer
      * returned by {@link #getByteBuffer()}), but may also be deferred
      * (which yields a null buffer returned by {@link #getByteBuffer()}).
-     * <p />
+     * <p>
      * If the block of content pointed by the new cursor position is valid, this method returns true.
      *
      * @return true if there is content at the new cursor's position, false otherwise.
      */
     public boolean advance()
     {
-        boolean advanced;
-        boolean hasNext;
-        ByteBuffer bytes;
         if (iterator instanceof Synchronizable)
         {
             synchronized (((Synchronizable)iterator).getLock())
             {
-                advanced = iterator.hasNext();
-                bytes = advanced ? iterator.next() : null;
-                hasNext = advanced && iterator.hasNext();
+                return advance(iterator);
             }
         }
         else
         {
-            advanced = iterator.hasNext();
-            bytes = advanced ? iterator.next() : null;
-            hasNext = advanced && iterator.hasNext();
+            return advance(iterator);
         }
+    }
 
-        if (advanced)
+    private boolean advance(Iterator<ByteBuffer> iterator)
+    {
+        boolean hasNext = iterator.hasNext();
+        ByteBuffer bytes = hasNext ? iterator.next() : null;
+        boolean hasMore = hasNext && iterator.hasNext();
+        boolean wasLast = last;
+        last = !hasMore;
+
+        if (hasNext)
         {
             buffer = bytes;
             content = bytes == null ? null : bytes.slice();
             if (LOG.isDebugEnabled())
-                LOG.debug("Advanced content to {} chunk {}", hasNext ? "next" : "last", bytes);
+                LOG.debug("Advanced content to {} chunk {}", hasMore ? "next" : "last", String.valueOf(bytes));
             return bytes != null;
         }
         else
         {
-            if (content != AFTER)
+            // No more content, but distinguish between last and consumed.
+            if (wasLast)
             {
-                content = buffer = AFTER;
+                buffer = content = AFTER;
                 if (LOG.isDebugEnabled())
                     LOG.debug("Advanced content past last chunk");
             }
+            else
+            {
+                buffer = content = CLOSE;
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Advanced content to last chunk");
+            }
             return false;
         }
     }
@@ -168,7 +179,7 @@
      */
     public boolean isConsumed()
     {
-        return content == AFTER;
+        return buffer == AFTER;
     }
 
     @Override
@@ -176,6 +187,8 @@
     {
         if (isConsumed())
             return;
+        if (buffer == CLOSE)
+            return;
         if (iterator instanceof Callback)
             ((Callback)iterator).succeeded();
     }
@@ -185,6 +198,8 @@
     {
         if (isConsumed())
             return;
+        if (buffer == CLOSE)
+            return;
         if (iterator instanceof Callback)
             ((Callback)iterator).failed(x);
     }
@@ -197,7 +212,7 @@
             if (iterator instanceof Closeable)
                 ((Closeable)iterator).close();
         }
-        catch (Exception x)
+        catch (Throwable x)
         {
             LOG.ignore(x);
         }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java
index 32194a2..189b609 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConversation.java
@@ -41,42 +41,42 @@
      * This list changes as the conversation proceeds, as follows:
      * <ol>
      * <li>
-     *     request R1 send => conversation.updateResponseListeners(null)
+     *     request R1 send =&gt; conversation.updateResponseListeners(null)
      *     <ul>
      *         <li>exchanges in conversation: E1</li>
      *         <li>listeners to be notified: E1.listeners</li>
      *     </ul>
      * </li>
      * <li>
-     *     response R1 arrived, 401 => conversation.updateResponseListeners(AuthenticationProtocolHandler.listener)
+     *     response R1 arrived, 401 =&gt; conversation.updateResponseListeners(AuthenticationProtocolHandler.listener)
      *     <ul>
      *         <li>exchanges in conversation: E1</li>
      *         <li>listeners to be notified: AuthenticationProtocolHandler.listener</li>
      *     </ul>
      * </li>
      * <li>
-     *     request R2 send => conversation.updateResponseListeners(null)
+     *     request R2 send =&gt; conversation.updateResponseListeners(null)
      *     <ul>
      *         <li>exchanges in conversation: E1 + E2</li>
      *         <li>listeners to be notified: E2.listeners + E1.listeners</li>
      *     </ul>
      * </li>
      * <li>
-     *     response R2 arrived, 302 => conversation.updateResponseListeners(RedirectProtocolHandler.listener)
+     *     response R2 arrived, 302 =&gt; conversation.updateResponseListeners(RedirectProtocolHandler.listener)
      *     <ul>
      *         <li>exchanges in conversation: E1 + E2</li>
      *         <li>listeners to be notified: E2.listeners + RedirectProtocolHandler.listener</li>
      *     </ul>
      * </li>
      * <li>
-     *     request R3 send => conversation.updateResponseListeners(null)
+     *     request R3 send =&gt; conversation.updateResponseListeners(null)
      *     <ul>
      *         <li>exchanges in conversation: E1 + E2 + E3</li>
      *         <li>listeners to be notified: E3.listeners + E1.listeners</li>
      *     </ul>
      * </li>
      * <li>
-     *     response R3 arrived, 200 => conversation.updateResponseListeners(null)
+     *     response R3 arrived, 200 =&gt; conversation.updateResponseListeners(null)
      *     <ul>
      *         <li>exchanges in conversation: E1 + E2 + E3</li>
      *         <li>listeners to be notified: E3.listeners + E1.listeners</li>
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
index 692fc71..169eb9a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java
@@ -36,12 +36,15 @@
 import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
 import org.eclipse.jetty.util.BlockingArrayQueue;
 import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-public abstract class HttpDestination implements Destination, Closeable, Dumpable
+@ManagedObject
+public abstract class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Dumpable
 {
     protected static final Logger LOG = Log.getLogger(HttpDestination.class);
 
@@ -130,12 +133,14 @@
     }
 
     @Override
+    @ManagedAttribute(value = "The destination scheme", readonly = true)
     public String getScheme()
     {
         return origin.getScheme();
     }
 
     @Override
+    @ManagedAttribute(value = "The destination host", readonly = true)
     public String getHost()
     {
         // InetSocketAddress.getHostString() transforms the host string
@@ -144,11 +149,18 @@
     }
 
     @Override
+    @ManagedAttribute(value = "The destination port", readonly = true)
     public int getPort()
     {
         return origin.getAddress().getPort();
     }
 
+    @ManagedAttribute(value = "The number of queued requests", readonly = true)
+    public int getQueuedRequestCount()
+    {
+        return exchanges.size();
+    }
+
     public Origin.Address getConnectAddress()
     {
         return proxy == null ? origin.getAddress() : proxy.getAddress();
@@ -205,7 +217,7 @@
         return queue.offer(exchange);
     }
 
-    protected abstract void send();
+    public abstract void send();
 
     public void newConnection(Promise<Connection> promise)
     {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
index 2df8b98..cd11b53 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpProxy.java
@@ -26,7 +26,6 @@
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
@@ -119,7 +118,7 @@
                     {
                         String message = String.format("Cannot perform requests over SSL, no %s in %s",
                                 SslContextFactory.class.getSimpleName(), HttpClient.class.getSimpleName());
-                        promise.failed(new IllegalStateException(message));
+                        tunnelFailed(new IllegalStateException(message));
                     }
                 }
                 else
@@ -131,7 +130,7 @@
             @Override
             public void failed(Throwable x)
             {
-                promise.failed(x);
+                tunnelFailed(x);
             }
 
             private void tunnel(HttpDestination destination, final Connection connection)
@@ -139,33 +138,31 @@
                 String target = destination.getOrigin().getAddress().asString();
                 Origin.Address proxyAddress = destination.getConnectAddress();
                 HttpClient httpClient = destination.getHttpClient();
+                long connectTimeout = httpClient.getConnectTimeout();
                 Request connect = httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort())
                         .scheme(HttpScheme.HTTP.asString())
                         .method(HttpMethod.CONNECT)
                         .path(target)
                         .header(HttpHeader.HOST, target)
-                        .timeout(httpClient.getConnectTimeout(), TimeUnit.MILLISECONDS);
+                        .idleTimeout(2 * connectTimeout, TimeUnit.MILLISECONDS)
+                        .timeout(connectTimeout, TimeUnit.MILLISECONDS);
 
-                connection.send(connect, new Response.CompleteListener()
+                connection.send(connect, result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
+                    if (result.isFailed())
                     {
-                        if (result.isFailed())
+                        tunnelFailed(result.getFailure());
+                    }
+                    else
+                    {
+                        Response response = result.getResponse();
+                        if (response.getStatus() == 200)
                         {
-                            tunnelFailed(result.getFailure());
+                            tunnelSucceeded();
                         }
                         else
                         {
-                            Response response = result.getResponse();
-                            if (response.getStatus() == 200)
-                            {
-                                tunnelSucceeded();
-                            }
-                            else
-                            {
-                                tunnelFailed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
-                            }
+                            tunnelFailed(new HttpResponseException("Received " + response + " for " + result.getRequest(), response));
                         }
                     }
                 });
@@ -182,10 +179,7 @@
                     ClientConnectionFactory sslConnectionFactory = new SslClientConnectionFactory(client.getSslContextFactory(), client.getByteBufferPool(), client.getExecutor(), connectionFactory);
                     HttpConnectionOverHTTP oldConnection = (HttpConnectionOverHTTP)endPoint.getConnection();
                     org.eclipse.jetty.io.Connection newConnection = sslConnectionFactory.newConnection(endPoint, context);
-                    Helper.replaceConnection(oldConnection, newConnection);
-                    // Avoid setting fill interest in the old Connection,
-                    // without closing the underlying EndPoint.
-                    oldConnection.softClose();
+                    endPoint.upgrade(newConnection);
                     if (LOG.isDebugEnabled())
                         LOG.debug("HTTP tunnel established: {} over {}", oldConnection, newConnection);
                 }
@@ -198,7 +192,7 @@
             private void tunnelFailed(Throwable failure)
             {
                 endPoint.close();
-                failed(failure);
+                promise.failed(failure);
             }
         }
     }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
index 02a6825..9a950a3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java
@@ -42,9 +42,9 @@
 
 /**
  * {@link HttpReceiver} provides the abstract code to implement the various steps of the receive of HTTP responses.
- * <p />
+ * <p>
  * {@link HttpReceiver} maintains a state machine that is updated when the steps of receiving a response are executed.
- * <p />
+ * <p>
  * Subclasses must handle the transport-specific details, for example how to read from the raw socket and how to parse
  * the bytes read from the socket. Then they have to call the methods defined in this class in the following order:
  * <ol>
@@ -59,7 +59,7 @@
  * (for example, because of I/O exceptions).
  * At any time, user threads may abort the response which will cause {@link #responseFailure(Throwable)} to be
  * invoked.
- * <p />
+ * <p>
  * The state machine maintained by this class ensures that the response steps are not executed by an I/O thread
  * if the response has already been failed.
  *
@@ -96,10 +96,10 @@
 
     /**
      * Method to be invoked when the response status code is available.
-     * <p />
+     * <p>
      * Subclasses must have set the response status code on the {@link Response} object of the {@link HttpExchange}
      * prior invoking this method.
-     * <p />
+     * <p>
      * This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.BeginListener}s.
      *
      * @param exchange the HTTP exchange
@@ -139,10 +139,10 @@
 
     /**
      * Method to be invoked when a response HTTP header is available.
-     * <p />
+     * <p>
      * Subclasses must not have added the header to the {@link Response} object of the {@link HttpExchange}
      * prior invoking this method.
-     * <p />
+     * <p>
      * This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.HeaderListener}s and storing cookies.
      *
      * @param exchange the HTTP exchange
@@ -223,7 +223,7 @@
 
     /**
      * Method to be invoked after all response HTTP headers are available.
-     * <p />
+     * <p>
      * This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.HeadersListener}s.
      *
      * @param exchange the HTTP exchange
@@ -281,11 +281,12 @@
 
     /**
      * Method to be invoked when response HTTP content is available.
-     * <p />
+     * <p>
      * This method takes case of decoding the content, if necessary, and notifying {@link org.eclipse.jetty.client.api.Response.ContentListener}s.
      *
      * @param exchange the HTTP exchange
      * @param buffer the response HTTP content buffer
+     * @param callback the callback
      * @return whether the processing should continue
      */
     protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, final Callback callback)
@@ -363,7 +364,7 @@
 
     /**
      * Method to be invoked when the response is successful.
-     * <p />
+     * <p>
      * This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.SuccessListener}s and possibly
      * {@link org.eclipse.jetty.client.api.Response.CompleteListener}s (if the exchange is completed).
      *
@@ -404,7 +405,7 @@
 
     /**
      * Method to be invoked when the response is failed.
-     * <p />
+     * <p>
      * This method takes care of notifying {@link org.eclipse.jetty.client.api.Response.FailureListener}s.
      *
      * @param failure the response failure
@@ -458,9 +459,9 @@
 
     /**
      * Resets this {@link HttpReceiver} state.
-     * <p />
+     * <p>
      * Subclasses should override (but remember to call {@code super}) to reset their own state.
-     * <p />
+     * <p>
      * Either this method or {@link #dispose()} is called.
      */
     protected void reset()
@@ -470,9 +471,9 @@
 
     /**
      * Disposes this {@link HttpReceiver} state.
-     * <p />
+     * <p>
      * Subclasses should override (but remember to call {@code super}) to dispose their own state.
-     * <p />
+     * <p>
      * Either this method or {@link #reset()} is called.
      */
     protected void dispose()
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
index 7dcb933..4927228 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRedirector.java
@@ -37,7 +37,7 @@
 
 /**
  * Utility class that handles HTTP redirects.
- * <p />
+ * <p>
  * Applications can disable redirection via {@link Request#followRedirects(boolean)}
  * and then rely on this class to perform the redirect in a simpler way, for example:
  * <pre>
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
index ef2a209..7270abb 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
@@ -503,7 +503,7 @@
                     listener.onContent(response, content);
                     callback.succeeded();
                 }
-                catch (Exception x)
+                catch (Throwable x)
                 {
                     callback.failed(x);
                 }
@@ -737,7 +737,7 @@
         if (value == null)
             return "";
 
-        String encoding = "UTF-8";
+        String encoding = "utf-8";
         try
         {
             return URLEncoder.encode(value, encoding);
@@ -768,7 +768,7 @@
 
     private String urlDecode(String value)
     {
-        String charset = "UTF-8";
+        String charset = "utf-8";
         try
         {
             return URLDecoder.decode(value, charset);
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java
index f5c0f2c..b6521ff 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequestException.java
@@ -20,7 +20,7 @@
 
 import org.eclipse.jetty.client.api.Request;
 
-public class HttpRequestException extends Throwable
+public class HttpRequestException extends RuntimeException
 {
     private final Request request;
 
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
index 623d127..c930740 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpSender.java
@@ -37,16 +37,16 @@
  * the transport-specific code to send requests over the wire, implementing
  * {@link #sendHeaders(HttpExchange, HttpContent, Callback)} and
  * {@link #sendContent(HttpExchange, HttpContent, Callback)}.
- * <p />
+ * <p>
  * {@link HttpSender} governs two state machines.
- * <p />
+ * <p>
  * The request state machine is updated by {@link HttpSender} as the various steps of sending a request
- * are executed, see {@link RequestState}.
+ * are executed, see <code>RequestState</code>.
  * At any point in time, a user thread may abort the request, which may (if the request has not been
- * completely sent yet) move the request state machine to {@link RequestState#FAILURE}.
+ * completely sent yet) move the request state machine to <code>RequestState#FAILURE</code>.
  * The request state machine guarantees that the request steps are executed (by I/O threads) only if
  * the request has not been failed already.
- * <p />
+ * <p>
  * The sender state machine is updated by {@link HttpSender} from three sources: deferred content notifications
  * (via {@link #onContent()}), 100-continue notifications (via {@link #proceed(HttpExchange, Throwable)})
  * and normal request send (via {@link #sendContent(HttpExchange, HttpContent, Callback)}).
@@ -392,7 +392,7 @@
     /**
      * Implementations should send the HTTP headers over the wire, possibly with some content,
      * in a single write, and notify the given {@code callback} of the result of this operation.
-     * <p />
+     * <p>
      * If there is more content to send, then {@link #sendContent(HttpExchange, HttpContent, Callback)}
      * will be invoked.
      *
@@ -404,11 +404,11 @@
 
     /**
      * Implementations should send the content at the {@link HttpContent} cursor position over the wire.
-     * <p />
+     * <p>
      * The {@link HttpContent} cursor is advanced by {@link HttpSender} at the right time, and if more
      * content needs to be sent, this method is invoked again; subclasses need only to send the content
      * at the {@link HttpContent} cursor position.
-     * <p />
+     * <p>
      * This method is invoked one last time when {@link HttpContent#isConsumed()} is true and therefore
      * there is no actual content to send.
      * This is done to allow subclasses to write "terminal" bytes (such as the terminal chunk when the
@@ -672,6 +672,13 @@
 
     private class CommitCallback implements Callback
     {
+
+        @Override
+        public boolean isNonBlocking()
+        {
+            return content.isNonBlocking();
+        }
+
         @Override
         public void succeeded()
         {
@@ -804,9 +811,9 @@
             while (true)
             {
                 boolean advanced = content.advance();
-                boolean consumed = content.isConsumed();
+                boolean lastContent = content.isLast();
                 if (LOG.isDebugEnabled())
-                    LOG.debug("Content {} consumed {} for {}", advanced, consumed, exchange.getRequest());
+                    LOG.debug("Content present {}, last {}, consumed {} for {}", advanced, lastContent, content.isConsumed(), exchange.getRequest());
 
                 if (advanced)
                 {
@@ -814,7 +821,7 @@
                     return Action.SCHEDULED;
                 }
 
-                if (consumed)
+                if (lastContent)
                 {
                     sendContent(exchange, content, lastCallback);
                     return Action.IDLE;
@@ -883,6 +890,12 @@
     private class LastContentCallback implements Callback
     {
         @Override
+        public boolean isNonBlocking()
+        {
+            return content.isNonBlocking();
+        }
+
+        @Override
         public void succeeded()
         {
             HttpExchange exchange = getHttpExchange();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java
index 2dbacb9..47f7613 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/LeakTrackingConnectionPool.java
@@ -20,11 +20,15 @@
 
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Destination;
+import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.LeakDetector;
-import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
 public class LeakTrackingConnectionPool extends ConnectionPool
 {
+    private static final Logger LOG = Log.getLogger(LeakTrackingConnectionPool.class);
+
     private final LeakDetector<Connection> leakDetector = new LeakDetector<Connection>()
     {
         @Override
@@ -34,9 +38,9 @@
         }
     };
 
-    public LeakTrackingConnectionPool(Destination destination, int maxConnections, Promise<Connection> connectionPromise)
+    public LeakTrackingConnectionPool(Destination destination, int maxConnections, Callback requester)
     {
-        super(destination, maxConnections, connectionPromise);
+        super(destination, maxConnections, requester);
         start();
     }
 
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
index 0fc83a9..c4b84e3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/MultiplexHttpDestination.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.client;
 
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.client.api.Connection;
@@ -27,6 +28,8 @@
 public abstract class MultiplexHttpDestination<C extends Connection> extends HttpDestination implements Promise<Connection>
 {
     private final AtomicReference<ConnectState> connect = new AtomicReference<>(ConnectState.DISCONNECTED);
+    private final AtomicInteger requestsPerConnection = new AtomicInteger();
+    private int maxRequestsPerConnection = 1024;
     private C connection;
 
     protected MultiplexHttpDestination(HttpClient client, Origin origin)
@@ -34,8 +37,18 @@
         super(client, origin);
     }
 
+    public int getMaxRequestsPerConnection()
+    {
+        return maxRequestsPerConnection;
+    }
+
+    public void setMaxRequestsPerConnection(int maxRequestsPerConnection)
+    {
+        this.maxRequestsPerConnection = maxRequestsPerConnection;
+    }
+
     @Override
-    protected void send()
+    public void send()
     {
         while (true)
         {
@@ -56,7 +69,7 @@
                 }
                 case CONNECTED:
                 {
-                    if (process(connection, false))
+                    if (process(connection))
                         break;
                     return;
                 }
@@ -76,12 +89,12 @@
         C connection = this.connection = (C)result;
         if (connect.compareAndSet(ConnectState.CONNECTING, ConnectState.CONNECTED))
         {
-            process(connection, true);
+            send();
         }
         else
         {
             connection.close();
-            failed(new IllegalStateException());
+            failed(new IllegalStateException("Invalid connection state " + connect));
         }
     }
 
@@ -89,47 +102,68 @@
     public void failed(Throwable x)
     {
         connect.set(ConnectState.DISCONNECTED);
+        abort(x);
     }
 
-    protected boolean process(final C connection, boolean dispatch)
+    protected boolean process(final C connection)
     {
-        HttpClient client = getHttpClient();
-        final HttpExchange exchange = getHttpExchanges().poll();
-        if (LOG.isDebugEnabled())
-            LOG.debug("Processing {} on {}", exchange, connection);
-        if (exchange == null)
-            return false;
+        while (true)
+        {
+            int max = getMaxRequestsPerConnection();
+            int count = requestsPerConnection.get();
+            int next = count + 1;
+            if (next > max)
+                return false;
 
-        final Request request = exchange.getRequest();
-        Throwable cause = request.getAbortCause();
-        if (cause != null)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Aborted before processing {}: {}", exchange, cause);
-            // It may happen that the request is aborted before the exchange
-            // is created. Aborting the exchange a second time will result in
-            // a no-operation, so we just abort here to cover that edge case.
-            exchange.abort(cause);
-        }
-        else
-        {
-            if (dispatch)
+            if (requestsPerConnection.compareAndSet(count, next))
             {
-                client.getExecutor().execute(new Runnable()
+                HttpExchange exchange = getHttpExchanges().poll();
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Processing {}/{} {} on {}", next, max, exchange, connection);
+                if (exchange == null)
                 {
-                    @Override
-                    public void run()
+                    requestsPerConnection.decrementAndGet();
+                    return false;
+                }
+
+                final Request request = exchange.getRequest();
+                Throwable cause = request.getAbortCause();
+                if (cause != null)
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Aborted before processing {}: {}", exchange, cause);
+                    // It may happen that the request is aborted before the exchange
+                    // is created. Aborting the exchange a second time will result in
+                    // a no-operation, so we just abort here to cover that edge case.
+                    exchange.abort(cause);
+                    requestsPerConnection.decrementAndGet();
+                }
+                else
+                {
+                    SendFailure result = send(connection, exchange);
+                    if (result != null)
                     {
-                        send(connection, exchange);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Send failed {} for {}", result, exchange);
+                        if (result.retry)
+                        {
+                            if (enqueue(getHttpExchanges(), exchange))
+                                return true;
+                        }
+
+                        request.abort(result.failure);
                     }
-                });
-            }
-            else
-            {
-                send(connection, exchange);
+                }
+                return getHttpExchanges().peek() != null;
             }
         }
-        return true;
+    }
+
+    @Override
+    public void release(Connection connection)
+    {
+        requestsPerConnection.decrementAndGet();
+        send();
     }
 
     @Override
@@ -157,7 +191,7 @@
         }
     }
 
-    protected abstract void send(C connection, HttpExchange exchange);
+    protected abstract SendFailure send(C connection, HttpExchange exchange);
 
     private enum ConnectState
     {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
index 8b72a7a..8416832 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/PoolingHttpDestination.java
@@ -19,70 +19,82 @@
 package org.eclipse.jetty.client;
 
 import java.io.IOException;
-import java.util.Arrays;
+import java.util.Collections;
 
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.thread.Sweeper;
 
-public abstract class PoolingHttpDestination<C extends Connection> extends HttpDestination implements Promise<Connection>
+@ManagedObject
+public abstract class PoolingHttpDestination<C extends Connection> extends HttpDestination implements Callback
 {
-    private final ConnectionPool connectionPool;
+    private DuplexConnectionPool connectionPool;
 
     public PoolingHttpDestination(HttpClient client, Origin origin)
     {
         super(client, origin);
         this.connectionPool = newConnectionPool(client);
+        addBean(connectionPool);
         Sweeper sweeper = client.getBean(Sweeper.class);
         if (sweeper != null)
             sweeper.offer(connectionPool);
     }
 
-    protected ConnectionPool newConnectionPool(HttpClient client)
+    @Override
+    protected void doStart() throws Exception
     {
-        return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this);
+        HttpClient client = getHttpClient();
+        this.connectionPool = newConnectionPool(client);
+        addBean(connectionPool);
+        super.doStart();
+        Sweeper sweeper = client.getBean(Sweeper.class);
+        if (sweeper != null)
+            sweeper.offer(connectionPool);
     }
 
-    public ConnectionPool getConnectionPool()
+    @Override
+    protected void doStop() throws Exception
+    {
+        HttpClient client = getHttpClient();
+        Sweeper sweeper = client.getBean(Sweeper.class);
+        if (sweeper != null)
+            sweeper.remove(connectionPool);
+        super.doStop();
+        removeBean(connectionPool);
+    }
+
+    protected DuplexConnectionPool newConnectionPool(HttpClient client)
+    {
+        return new DuplexConnectionPool(this, client.getMaxConnectionsPerDestination(), this);
+    }
+
+    @ManagedAttribute(value = "The connection pool", readonly = true)
+    public DuplexConnectionPool getConnectionPool()
     {
         return connectionPool;
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public void succeeded(Connection connection)
+    public void succeeded()
     {
-        send(true);
+        send();
     }
 
     @Override
     public void failed(final Throwable x)
     {
-        getHttpClient().getExecutor().execute(new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                abort(x);
-            }
-        });
+        abort(x);
     }
 
-    @Override
-    protected void send()
-    {
-        send(false);
-    }
-
-    private void send(boolean dispatch)
+    public void send()
     {
         if (getHttpExchanges().isEmpty())
             return;
-        C connection = acquire();
-        if (connection != null)
-            process(connection, dispatch);
+        process();
     }
 
     @SuppressWarnings("unchecked")
@@ -91,6 +103,19 @@
         return (C)connectionPool.acquire();
     }
 
+    private void process()
+    {
+        while (true)
+        {
+            C connection = acquire();
+            if (connection == null)
+                break;
+            boolean proceed = process(connection);
+            if (!proceed)
+                break;
+        }
+    }
+
     /**
      * <p>Processes a new connection making it idle or active depending on whether requests are waiting to be sent.</p>
      * <p>A new connection is created when a request needs to be executed; it is possible that the request that
@@ -99,9 +124,9 @@
      * <p>If a request is waiting to be executed, it will be dequeued and executed by the new connection.</p>
      *
      * @param connection the new connection
-     * @param dispatch whether to dispatch the processing to another thread
+     * @return whether to perform more processing
      */
-    public void process(final C connection, boolean dispatch)
+    public boolean process(final C connection)
     {
         HttpClient client = getHttpClient();
         final HttpExchange exchange = getHttpExchanges().poll();
@@ -111,13 +136,13 @@
         {
             if (!connectionPool.release(connection))
                 connection.close();
-
             if (!client.isRunning())
             {
                 if (LOG.isDebugEnabled())
                     LOG.debug("{} is stopping", client);
                 connection.close();
             }
+            return false;
         }
         else
         {
@@ -134,26 +159,25 @@
             }
             else
             {
-                if (dispatch)
+                SendFailure result = send(connection, exchange);
+                if (result != null)
                 {
-                    client.getExecutor().execute(new Runnable()
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Send failed {} for {}", result, exchange);
+                    if (result.retry)
                     {
-                        @Override
-                        public void run()
-                        {
-                            send(connection, exchange);
-                        }
-                    });
-                }
-                else
-                {
-                    send(connection, exchange);
+                        if (enqueue(getHttpExchanges(), exchange))
+                            return true;
+                    }
+
+                    request.abort(result.failure);
                 }
             }
+            return getHttpExchanges().peek() != null;
         }
     }
 
-    protected abstract void send(C connection, HttpExchange exchange);
+    protected abstract SendFailure send(C connection, HttpExchange exchange);
 
     @Override
     public void release(Connection c)
@@ -161,18 +185,21 @@
         @SuppressWarnings("unchecked")
         C connection = (C)c;
         if (LOG.isDebugEnabled())
-            LOG.debug("{} released", connection);
+            LOG.debug("Released {}", connection);
         HttpClient client = getHttpClient();
         if (client.isRunning())
         {
             if (connectionPool.isActive(connection))
             {
-                process(connection, false);
+                if (connectionPool.release(connection))
+                    send();
+                else
+                    connection.close();
             }
             else
             {
                 if (LOG.isDebugEnabled())
-                    LOG.debug("{} explicit", connection);
+                    LOG.debug("Released explicit {}", connection);
             }
         }
         else
@@ -184,11 +211,11 @@
     }
 
     @Override
-    public void close(Connection oldConnection)
+    public void close(Connection connection)
     {
-        super.close(oldConnection);
+        super.close(connection);
 
-        connectionPool.remove(oldConnection);
+        boolean removed = connectionPool.remove(connection);
 
         if (getHttpExchanges().isEmpty())
         {
@@ -208,9 +235,8 @@
             // We need to execute queued requests even if this connection failed.
             // We may create a connection that is not needed, but it will eventually
             // idle timeout, so no worries.
-            C newConnection = acquire();
-            if (newConnection != null)
-                process(newConnection, false);
+            if (removed)
+                process();
         }
     }
 
@@ -224,7 +250,7 @@
     public void dump(Appendable out, String indent) throws IOException
     {
         super.dump(out, indent);
-        ContainerLifeCycle.dump(out, indent, Arrays.asList(connectionPool));
+        ContainerLifeCycle.dump(out, indent, Collections.singletonList(connectionPool));
     }
 
     @Override
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java
index f470625..b952ce3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandler.java
@@ -21,9 +21,38 @@
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
 
+/**
+ * <p>A protocol handler performs HTTP protocol operations on
+ * behalf of the application, typically like a browser would.</p>
+ * <p>A typical example is handling HTTP redirects. {@link HttpClient}
+ * could just return the redirect response to the application,
+ * but the application would have to implement the redirect
+ * functionality (while browsers do this automatically).</p>
+ */
 public interface ProtocolHandler
 {
+    /**
+     * @return a unique name among protocol handlers
+     */
+    public String getName();
+
+    /**
+     * <p>Inspects the given {@code request} and {@code response}
+     * to detect whether this protocol handler should handle them.</p>
+     * <p>For example, a redirect protocol handler can inspect the
+     * response code and return true if it is a redirect response code.</p>
+     * <p>This method is being called just after the response line has
+     * been parsed, and before the response headers are available.</p>
+     *
+     * @param request  the request to accept
+     * @param response the response to accept
+     * @return true if this protocol handler can handle the given request and response
+     */
     public boolean accept(Request request, Response response);
 
+    /**
+     * @return a response listener that will handle the request and response
+     * on behalf of the application.
+     */
     public Response.Listener getResponseListener();
 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java
new file mode 100644
index 0000000..32bb9a7
--- /dev/null
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProtocolHandlers.java
@@ -0,0 +1,94 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Response;
+
+/**
+ * <p>A container for {@link ProtocolHandler}s accessible from {@link HttpClient#getProtocolHandlers()}.</p>
+ */
+public class ProtocolHandlers
+{
+    private final Map<String, ProtocolHandler> handlers = new LinkedHashMap<>();
+
+    protected ProtocolHandlers()
+    {
+    }
+
+    /**
+     * <p>Stores the given {@code protocolHandler} in this container.</p>
+     * <p>If a protocol handler with the same name exists, it is
+     * replaced by the given one, and the existing returned.</p>
+     *
+     * @param protocolHandler the protocol handler to store
+     * @return the existing protocol handler with the same name,
+     * or null if no protocol handler with that name was already stored
+     * @see #remove(String)
+     */
+    public ProtocolHandler put(ProtocolHandler protocolHandler)
+    {
+        return handlers.put(protocolHandler.getName(), protocolHandler);
+    }
+
+    /**
+     * <p>Removes the protocol handler with the given name.</p>
+     *
+     * @param name the name of the protocol handler to remove
+     * @return the removed protocol handler, or null if no
+     * protocol handler with that name was already stored
+     * @see #put(ProtocolHandler)
+     * @see #clear()
+     */
+    public ProtocolHandler remove(String name)
+    {
+        return handlers.remove(name);
+    }
+
+    /**
+     * <p>Removes all protocol handlers from this container.</p>
+     */
+    public void clear()
+    {
+        handlers.clear();
+    }
+
+    /**
+     * <p>Finds the first protocol handler that
+     * {@link ProtocolHandler#accept(Request, Response) accepts}
+     * the given request and response.</p>
+     *
+     * @param request  the request to accept
+     * @param response the response to accept
+     * @return the protocol handler that accepted the request and response,
+     * or null if none of the protocol handlers accepted the request and response
+     */
+    public ProtocolHandler find(Request request, Response response)
+    {
+        for (ProtocolHandler handler : handlers.values())
+        {
+            if (handler.accept(request, response))
+                return handler;
+        }
+        return null;
+    }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java
index 922c686..4099974 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyAuthenticationProtocolHandler.java
@@ -25,8 +25,16 @@
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpStatus;
 
+/**
+ * <p>A protocol handler that handles the 401 response code
+ * in association with the {@code Proxy-Authenticate} header.</p>
+ *
+ * @see WWWAuthenticationProtocolHandler
+ */
 public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler
 {
+    public static final String NAME = "proxy-authenticate";
+
     public ProxyAuthenticationProtocolHandler(HttpClient client)
     {
         this(client, DEFAULT_MAX_CONTENT_LENGTH);
@@ -38,6 +46,12 @@
     }
 
     @Override
+    public String getName()
+    {
+        return NAME;
+    }
+
+    @Override
     public boolean accept(Request request, Response response)
     {
         return response.getStatus() == HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java
index a72cbf0..7b544f6 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java
@@ -28,7 +28,7 @@
 
 /**
  * The configuration of the forward proxy to use with {@link org.eclipse.jetty.client.HttpClient}.
- * <p />
+ * <p>
  * Applications add subclasses of {@link Proxy} to this configuration via:
  * <pre>
  * ProxyConfiguration proxyConfig = httpClient.getProxyConfiguration();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java
index 9d76079..f6c8018 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/RedirectProtocolHandler.java
@@ -22,8 +22,13 @@
 import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.api.Result;
 
+/**
+ * <p>A protocol handler that handles redirect status codes 301, 302, 303, 307 and 308.</p>
+ */
 public class RedirectProtocolHandler extends Response.Listener.Adapter implements ProtocolHandler
 {
+    public static final String NAME = "redirect";
+
     private final HttpRedirector redirector;
 
     public RedirectProtocolHandler(HttpClient client)
@@ -32,6 +37,12 @@
     }
 
     @Override
+    public String getName()
+    {
+        return NAME;
+    }
+
+    @Override
     public boolean accept(Request request, Response response)
     {
         return redirector.isRedirect(response) && request.isFollowRedirects();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java b/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java
new file mode 100644
index 0000000..748e2fa
--- /dev/null
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/SendFailure.java
@@ -0,0 +1,37 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+public class SendFailure
+{
+    public final Throwable failure;
+    public final boolean retry;
+
+    public SendFailure(Throwable failure, boolean retry)
+    {
+        this.failure = failure;
+        this.retry = retry;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s[failure=%s,retry=%b]", super.toString(), failure, retry);
+    }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
index 2559d6c..a309fe3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/Socks4Proxy.java
@@ -198,10 +198,10 @@
                 ClientConnectionFactory connectionFactory = this.connectionFactory;
                 if (HttpScheme.HTTPS.is(destination.getScheme()))
                     connectionFactory = new SslClientConnectionFactory(client.getSslContextFactory(), client.getByteBufferPool(), client.getExecutor(), connectionFactory);
-                org.eclipse.jetty.io.Connection connection = connectionFactory.newConnection(getEndPoint(), context);
-                ClientConnectionFactory.Helper.replaceConnection(this, connection);
+                org.eclipse.jetty.io.Connection newConnection = connectionFactory.newConnection(getEndPoint(), context);
+                getEndPoint().upgrade(newConnection);
                 if (LOG.isDebugEnabled())
-                    LOG.debug("SOCKS4 tunnel established: {} over {}", this, connection);
+                    LOG.debug("SOCKS4 tunnel established: {} over {}", this, newConnection);
             }
             catch (Throwable x)
             {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java
new file mode 100644
index 0000000..95d1446
--- /dev/null
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ValidatingConnectionPool.java
@@ -0,0 +1,209 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.jetty.client.api.Connection;
+import org.eclipse.jetty.client.api.Destination;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+/**
+ * <p>A connection pool that validates connections before
+ * making them available for use.</p>
+ * <p>Connections that have just been opened are not validated.
+ * Connections that are {@link #release(Connection) released} will
+ * be validated.</p>
+ * <p>Validation by reading from the EndPoint is not reliable,
+ * since the TCP FIN may arrive just after the validation read.</p>
+ * <p>This class validates connections by putting them in a
+ * "quarantine" for a configurable timeout, where they cannot
+ * be used to send requests. When the timeout expires, the
+ * quarantined connection is made idle and therefore available
+ * to send requests.</p>
+ * <p>The existing HttpClient mechanism to detect server closes
+ * will trigger and close quarantined connections, before they
+ * are made idle (and reusable) again.</p>
+ * <p>There still is a small chance that the timeout expires,
+ * the connection is made idle and available again, it is used
+ * to send a request exactly when the server decides to close.
+ * This case is however unavoidable and may be mitigated by
+ * tuning the idle timeout of the servers to be larger than
+ * that of the client.</p>
+ */
+public class ValidatingConnectionPool extends ConnectionPool
+{
+    private static final Logger LOG = Log.getLogger(ValidatingConnectionPool.class);
+
+    private final Scheduler scheduler;
+    private final long timeout;
+    private final Map<Connection, Holder> quarantine;
+
+    public ValidatingConnectionPool(Destination destination, int maxConnections, Callback requester, Scheduler scheduler, long timeout)
+    {
+        super(destination, maxConnections, requester);
+        this.scheduler = scheduler;
+        this.timeout = timeout;
+        this.quarantine = new HashMap<>(maxConnections);
+    }
+
+    @ManagedAttribute(value = "The number of validating connections", readonly = true)
+    public int getValidatingConnectionCount()
+    {
+        return quarantine.size();
+    }
+
+    @Override
+    public boolean release(Connection connection)
+    {
+        lock();
+        try
+        {
+            if (!getActiveConnections().remove(connection))
+                return false;
+            Holder holder = new Holder(connection);
+            holder.task = scheduler.schedule(holder, timeout, TimeUnit.MILLISECONDS);
+            quarantine.put(connection, holder);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Validating for {}ms {}", timeout, connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        released(connection);
+        return true;
+    }
+
+    @Override
+    public boolean remove(Connection connection)
+    {
+        Holder holder;
+        lock();
+        try
+        {
+            holder = quarantine.remove(connection);
+        }
+        finally
+        {
+            unlock();
+        }
+
+        if (holder == null)
+            return super.remove(connection);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Removed while validating {}", connection);
+
+        boolean cancelled = holder.cancel();
+        if (cancelled)
+            return remove(connection, true);
+
+        return super.remove(connection);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        super.dump(out, indent);
+        ContainerLifeCycle.dump(out, indent, quarantine.values());
+    }
+
+    @Override
+    public String toString()
+    {
+        int size;
+        lock();
+        try
+        {
+            size = quarantine.size();
+        }
+        finally
+        {
+            unlock();
+        }
+        return String.format("%s[v=%d]", super.toString(), size);
+    }
+
+    private class Holder implements Runnable
+    {
+        private final long timestamp = System.nanoTime();
+        private final AtomicBoolean latch = new AtomicBoolean();
+        private final Connection connection;
+        public Scheduler.Task task;
+
+        public Holder(Connection connection)
+        {
+            this.connection = connection;
+        }
+
+        @Override
+        public void run()
+        {
+            if (latch.compareAndSet(false, true))
+            {
+                boolean idle;
+                lock();
+                try
+                {
+                    quarantine.remove(connection);
+                    idle = offerIdle(connection);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Validated {}", connection);
+                }
+                finally
+                {
+                    unlock();
+                }
+
+                if (idle(connection, idle))
+                    proceed();
+            }
+        }
+
+        public boolean cancel()
+        {
+            if (latch.compareAndSet(false, true))
+            {
+                task.cancel();
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s[validationLeft=%dms]",
+                    connection,
+                    timeout - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - timestamp)
+            );
+        }
+    }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java
index 4ac868b..5f023a9 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/WWWAuthenticationProtocolHandler.java
@@ -25,8 +25,16 @@
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpStatus;
 
+/**
+ * <p>A protocol handler that handles the 401 response code
+ * in association with the {@code WWW-Authenticate} header.</p>
+ *
+ * @see ProxyAuthenticationProtocolHandler
+ */
 public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler
 {
+    public static final String NAME = "www-authenticate";
+
     public WWWAuthenticationProtocolHandler(HttpClient client)
     {
         this(client, DEFAULT_MAX_CONTENT_LENGTH);
@@ -38,6 +46,12 @@
     }
 
     @Override
+    public String getName()
+    {
+        return NAME;
+    }
+
+    @Override
     public boolean accept(Request request, Response response)
     {
         return response.getStatus() == HttpStatus.UNAUTHORIZED_401;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java
index 2610e72..082e1c1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Authentication.java
@@ -25,12 +25,12 @@
 
 /**
  * {@link Authentication} represents a mechanism to authenticate requests for protected resources.
- * <p />
+ * <p>
  * {@link Authentication}s are added to an {@link AuthenticationStore}, which is then
  * {@link #matches(String, URI, String) queried} to find the right
  * {@link Authentication} mechanism to use based on its type, URI and realm, as returned by
  * {@code WWW-Authenticate} response headers.
- * <p />
+ * <p>
  * If an {@link Authentication} mechanism is found, it is then
  * {@link #authenticate(Request, ContentResponse, HeaderInfo, Attributes) executed} for the given request,
  * returning an {@link Authentication.Result}, which is then stored in the {@link AuthenticationStore}
@@ -49,8 +49,8 @@
 
     /**
      * Executes the authentication mechanism for the given request, returning a {@link Result} that can be
-     * used to actually authenticate the request via {@link Result#apply(Request)}.
-     * <p />
+     * used to actually authenticate the request via {@link org.eclipse.jetty.client.api.Authentication.Result#apply(Request)}.
+     * <p>
      * If a request for {@code "/secure"} returns a {@link Result}, then the result may be used for other
      * requests such as {@code "/secure/foo"} or {@code "/secure/bar"}, unless those resources are protected
      * by other realms.
@@ -117,7 +117,7 @@
     }
 
     /**
-     * {@link Result} holds the information needed to authenticate a {@link Request} via {@link #apply(Request)}.
+     * {@link Result} holds the information needed to authenticate a {@link Request} via {@link org.eclipse.jetty.client.api.Authentication.Result#apply(org.eclipse.jetty.client.api.Request)}.
      */
     public static interface Result
     {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
index 5b33d3f..8545440 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Connection.java
@@ -20,10 +20,12 @@
 
 import java.io.Closeable;
 
+import org.eclipse.jetty.util.Promise;
+
 /**
  * {@link Connection} represent a connection to a {@link Destination} and allow applications to send
  * requests via {@link #send(Request, Response.CompleteListener)}.
- * <p />
+ * <p>
  * {@link Connection}s are normally pooled by {@link Destination}s, but unpooled {@link Connection}s
  * may be created by applications that want to do their own connection management via
  * {@link Destination#newConnection(Promise)} and {@link Connection#close()}.
@@ -32,7 +34,7 @@
 {
     /**
      * Sends a request with an associated response listener.
-     * <p />
+     * <p>
      * {@link Request#send(Response.CompleteListener)} will eventually call this method to send the request.
      * It is exposed to allow applications to send requests via unpooled connections.
      *
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
index 0516779..d9d6bff 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/ContentProvider.java
@@ -18,19 +18,28 @@
 
 package org.eclipse.jetty.client.api;
 
+import java.io.Closeable;
 import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.eclipse.jetty.client.util.ByteBufferContentProvider;
+import org.eclipse.jetty.client.util.PathContentProvider;
 
 /**
- * {@link ContentProvider} provides a source of request content.
- * <p/>
- * Implementations should return an {@link Iterator} over the request content.
+ * <p>{@link ContentProvider} provides a source of request content.</p>
+ * <p>Implementations should return an {@link Iterator} over the request content.
  * If the request content comes from a source that needs to be closed (for
- * example, an {@link InputStream}), then the iterator implementation class
+ * example, an {@link java.io.InputStream}), then the iterator implementation class
  * must implement {@link Closeable} and will be closed when the request is
- * completed (either successfully or failed).
- * <p/>
- * Applications should rely on utility classes such as {@link ByteBufferContentProvider}
- * or {@link PathContentProvider}.
+ * completed (either successfully or failed).</p>
+ * <p>Applications should rely on utility classes such as {@link ByteBufferContentProvider}
+ * or {@link PathContentProvider}.</p>
+ * <p>{@link ContentProvider} provides a {@link #getLength() length} of the content
+ * it represents.
+ * If the length is positive, it typically overrides any {@code Content-Length}
+ * header set by applications; if the length is negative, it typically removes
+ * any {@code Content-Length} header set by applications, resulting in chunked
+ * content (i.e. {@code Transfer-Encoding: chunked}) being sent to the server.</p>
  */
 public interface ContentProvider extends Iterable<ByteBuffer>
 {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
index 73a39c2..c0a131a 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Destination.java
@@ -18,15 +18,17 @@
 
 package org.eclipse.jetty.client.api;
 
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.FuturePromise;
 import org.eclipse.jetty.util.Promise;
 
 /**
  * {@link Destination} represents the triple made of the {@link #getScheme}, the {@link #getHost}
  * and the {@link #getPort}.
- * <p />
+ * <p>
  * {@link Destination} holds a pool of {@link Connection}s, but allows to create unpooled
  * connections if the application wants full control over connection management via {@link #newConnection(Promise)}.
- * <p />
+ * <p>
  * {@link Destination}s may be obtained via {@link HttpClient#getDestination(String, String, int)}
  */
 public interface Destination
@@ -49,7 +51,7 @@
     /**
      * Creates asynchronously a new, unpooled, {@link Connection} that will be returned
      * at a later time through the given {@link Promise}.
-     * <p />
+     * <p>
      * Use {@link FuturePromise} to wait for the connection:
      * <pre>
      * Destination destination = ...;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
index e7e527e..b851c11 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Request.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.net.HttpCookie;
 import java.net.URI;
+import java.net.URLEncoder;
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.util.EventListener;
@@ -30,6 +31,8 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.util.InputStreamResponseListener;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
@@ -202,6 +205,7 @@
 
     /**
      * @param content the content provider of this request
+     * @param contentType the content type
      * @return this request object
      */
     Request content(ContentProvider content, String contentType);
@@ -282,6 +286,7 @@
     /**
      * @param listenerClass the class of the listener, or null for all listeners classes
      * @return the listeners for request events of the given class
+     * @param <T> the type of listener class
      */
     <T extends RequestListener> List<T> getRequestListeners(Class<T> listenerClass);
 
@@ -383,17 +388,20 @@
 
     /**
      * Sends this request and returns the response.
-     * <p />
+     * <p>
      * This method should be used when a simple blocking semantic is needed, and when it is known
      * that the response content can be buffered without exceeding memory constraints.
-     * <p />
+     * <p>
      * For example, this method is not appropriate to download big files from a server; consider using
      * {@link #send(Response.CompleteListener)} instead, passing your own {@link Response.Listener} or a utility
      * listener such as {@link InputStreamResponseListener}.
-     * <p />
+     * <p>
      * The method returns when the {@link Response.CompleteListener complete event} is fired.
      *
      * @return a {@link ContentResponse} for this request
+     * @throws InterruptedException if send thread is interrupted
+     * @throws TimeoutException if send times out
+     * @throws ExecutionException if execution fails
      * @see Response.CompleteListener#onComplete(Result)
      */
     ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException;
@@ -495,6 +503,7 @@
          * Callback method invoked when a chunk of request content has been sent successfully.
          * Changes to bytes in the given buffer have no effect, as the content has already been sent.
          * @param request the request that has been committed
+         * @param content the content
          */
         public void onContent(Request request, ByteBuffer content);
     }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
index ca6d028..e5fd6f3 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java
@@ -22,6 +22,7 @@
 import java.util.EventListener;
 import java.util.List;
 
+import org.eclipse.jetty.client.util.BufferingResponseListener;
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpVersion;
@@ -45,7 +46,9 @@
     Request getRequest();
 
     /**
-     * @return the response listener passed to {@link Request#send(CompleteListener)}
+     * @param listenerClass the listener class
+     * @return the response listener passed to {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)}
+     * @param <T> the type of class
      */
     <T extends ResponseListener> List<T> getListeners(Class<T> listenerClass);
 
@@ -92,7 +95,7 @@
         /**
          * Callback method invoked when the response line containing HTTP version,
          * HTTP status code and reason has been received and parsed.
-         * <p />
+         * <p>
          * This method is the best approximation to detect when the first bytes of the response arrived to the client.
          *
          * @param response the response containing the response line data
@@ -192,9 +195,9 @@
         /**
          * Callback method invoked when the request <em><b>and</b></em> the response have been processed,
          * either successfully or not.
-         * <p/>
+         * <p>
          * The {@code result} parameter contains the request, the response, and eventual failures.
-         * <p/>
+         * <p>
          * Requests may complete <em>after</em> response, for example in case of big uploads that are
          * discarded or read asynchronously by the server.
          * This method is always invoked <em>after</em> {@link SuccessListener#onSuccess(Response)} or
@@ -245,7 +248,7 @@
                     onContent(response, content);
                     callback.succeeded();
                 }
-                catch (Exception x)
+                catch (Throwable x)
                 {
                     callback.failed(x);
                 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java
index 70c25ac..cdbf1fa 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java
@@ -27,6 +27,7 @@
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpVersion;
 
 public class HttpChannelOverHTTP extends HttpChannel
@@ -96,26 +97,42 @@
 
         Response response = result.getResponse();
         HttpFields responseHeaders = response.getHeaders();
-        boolean close = result.isFailed() || receiver.isShutdown();
 
-        if (!close)
+        String closeReason = null;
+        if (result.isFailed())
+            closeReason = "failure";
+        else if (receiver.isShutdown())
+            closeReason = "server close";
+
+        if (closeReason == null)
         {
             if (response.getVersion().compareTo(HttpVersion.HTTP_1_1) < 0)
             {
-                // HTTP 1.0 must close the connection unless it has an explicit keep alive.
-                close = !responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
+                // HTTP 1.0 must close the connection unless it has
+                // an explicit keep alive or it's a CONNECT method.
+                boolean keepAlive = responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
+                boolean connect = HttpMethod.CONNECT.is(exchange.getRequest().getMethod());
+                if (!keepAlive && !connect)
+                    closeReason = "http/1.0";
             }
             else
             {
                 // HTTP 1.1 or greater closes only if it has an explicit close.
-                close = responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
+                if (responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()))
+                    closeReason = "http/1.1";
             }
         }
 
-        if (close)
+        if (closeReason != null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Closing, reason: {} - {}", closeReason, connection);
             connection.close();
+        }
         else
+        {
             release();
+        }
     }
 
     @Override
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java
index de625d2..d758da9 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpClientTransportOverHTTP.java
@@ -27,7 +27,9 @@
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 
+@ManagedObject("The HTTP/1.1 client transport")
 public class HttpClientTransportOverHTTP extends AbstractHttpClientTransport
 {
     public HttpClientTransportOverHTTP()
@@ -62,13 +64,4 @@
     {
         return new HttpConnectionOverHTTP(endPoint, destination, promise);
     }
-
-    /**
-     * @deprecated use {@link #newHttpConnection(EndPoint, HttpDestination, Promise)} instead
-     */
-    @Deprecated
-    protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination)
-    {
-        throw new UnsupportedOperationException("Deprecated, override newHttpConnection(EndPoint, HttpDestination, Promise<Connection>) instead");
-    }
 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
index 7db202a..f6371f4 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java
@@ -26,6 +26,7 @@
 import org.eclipse.jetty.client.HttpConnection;
 import org.eclipse.jetty.client.HttpDestination;
 import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.SendFailure;
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
@@ -47,19 +48,9 @@
     private final HttpChannelOverHTTP channel;
     private long idleTimeout;
 
-    /**
-     * @deprecated use {@link #HttpConnectionOverHTTP(EndPoint, HttpDestination, Promise)} instead
-     */
-    @Deprecated
-    public HttpConnectionOverHTTP(EndPoint endPoint, HttpDestination destination)
-    {
-        this(endPoint, destination, new Promise.Adapter<Connection>());
-        throw new UnsupportedOperationException("Deprecated, use HttpConnectionOverHTTP(EndPoint, HttpDestination, Promise<Connection>) instead");
-    }
-
     public HttpConnectionOverHTTP(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
     {
-        super(endPoint, destination.getHttpClient().getExecutor(), destination.getHttpClient().isDispatchIO());
+        super(endPoint, destination.getHttpClient().getExecutor());
         this.promise = promise;
         this.delegate = new Delegate(destination);
         this.channel = newHttpChannel();
@@ -86,9 +77,9 @@
         delegate.send(request, listener);
     }
 
-    protected void send(HttpExchange exchange)
+    protected SendFailure send(HttpExchange exchange)
     {
-        delegate.send(exchange);
+        return delegate.send(exchange);
     }
 
     @Override
@@ -105,11 +96,11 @@
     }
 
     @Override
-    protected boolean onReadTimeout()
+    public boolean onIdleExpired()
     {
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} idle timeout", this);
-        close(new TimeoutException());
+        boolean close = delegate.onIdleTimeout();
+        if (close)
+            close(new TimeoutException("Idle timeout " + getEndPoint().getIdleTimeout() + "ms"));
         return false;
     }
 
@@ -144,27 +135,22 @@
 
     protected void close(Throwable failure)
     {
-        if (softClose())
+        if (closed.compareAndSet(false, true))
         {
             // First close then abort, to be sure that the connection cannot be reused
             // from an onFailure() handler or by blocking code waiting for completion.
             getHttpDestination().close(this);
             getEndPoint().shutdownOutput();
             if (LOG.isDebugEnabled())
-                LOG.debug("{} oshut", this);
+                LOG.debug("Shutdown {}", this);
             getEndPoint().close();
             if (LOG.isDebugEnabled())
-                LOG.debug("{} closed", this);
+                LOG.debug("Closed {}", this);
 
             abort(failure);
         }
     }
 
-    public boolean softClose()
-    {
-        return closed.compareAndSet(false, true);
-    }
-
     protected boolean abort(Throwable failure)
     {
         HttpExchange exchange = channel.getHttpExchange();
@@ -176,10 +162,8 @@
     {
         if (!closed.get())
             return false;
-
         if (sweeps.incrementAndGet() < 4)
             return false;
-
         return true;
     }
 
@@ -203,21 +187,18 @@
         }
 
         @Override
-        protected void send(HttpExchange exchange)
+        protected SendFailure send(HttpExchange exchange)
         {
             Request request = exchange.getRequest();
             normalizeRequest(request);
 
-            // Save the old idle timeout to restore it
+            // Save the old idle timeout to restore it.
             EndPoint endPoint = getEndPoint();
             idleTimeout = endPoint.getIdleTimeout();
             endPoint.setIdleTimeout(request.getIdleTimeout());
 
-            // One channel per connection, just delegate the send
-            if (channel.associate(exchange))
-                channel.send();
-            else
-                channel.release();
+            // One channel per connection, just delegate the send.
+            return send(channel, exchange);
         }
 
         @Override
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java
index 8f8e254..37ff0ea 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTP.java
@@ -22,6 +22,7 @@
 import org.eclipse.jetty.client.HttpExchange;
 import org.eclipse.jetty.client.Origin;
 import org.eclipse.jetty.client.PoolingHttpDestination;
+import org.eclipse.jetty.client.SendFailure;
 
 public class HttpDestinationOverHTTP extends PoolingHttpDestination<HttpConnectionOverHTTP>
 {
@@ -31,8 +32,8 @@
     }
 
     @Override
-    protected void send(HttpConnectionOverHTTP connection, HttpExchange exchange)
+    protected SendFailure send(HttpConnectionOverHTTP connection, HttpExchange exchange)
     {
-        connection.send(exchange);
+        return connection.send(exchange);
     }
 }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
index 8e234f2..a201b31 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java
@@ -35,7 +35,7 @@
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.CompletableCallback;
 
-public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
+public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler
 {
     private final HttpParser parser = new HttpParser(this);
     private ByteBuffer buffer;
@@ -96,11 +96,13 @@
             EndPoint endPoint = connection.getEndPoint();
             while (true)
             {
-                // Connection may be closed in a parser callback.
-                if (connection.isClosed())
+                boolean upgraded = connection != endPoint.getConnection();
+
+                // Connection may be closed or upgraded in a parser callback.
+                if (connection.isClosed() || upgraded)
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("{} closed", connection);
+                        LOG.debug("{} {}", connection, upgraded ? "upgraded" : "closed");
                     releaseBuffer();
                     return;
                 }
@@ -209,13 +211,13 @@
     }
 
     @Override
-    public boolean parsedHeader(HttpField field)
+    public void parsedHeader(HttpField field)
     {
         HttpExchange exchange = getHttpExchange();
         if (exchange == null)
-            return false;
+            return;
 
-        return !responseHeader(exchange, field);
+        responseHeader(exchange, field);
     }
 
     @Override
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
index 2431f99e..9458339 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpSenderOverHTTP.java
@@ -28,9 +28,12 @@
 import org.eclipse.jetty.client.api.ContentProvider;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.IteratingCallback;
 
 public class HttpSenderOverHTTP extends HttpSender
 {
@@ -50,77 +53,9 @@
     @Override
     protected void sendHeaders(HttpExchange exchange, HttpContent content, Callback callback)
     {
-        Request request = exchange.getRequest();
-        ContentProvider requestContent = request.getContent();
-        long contentLength = requestContent == null ? -1 : requestContent.getLength();
-        String path = request.getPath();
-        String query = request.getQuery();
-        if (query != null)
-            path += "?" + query;
-        HttpGenerator.RequestInfo requestInfo = new HttpGenerator.RequestInfo(request.getVersion(), request.getHeaders(), contentLength, request.getMethod(), path);
-
         try
         {
-            HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
-            ByteBufferPool bufferPool = client.getByteBufferPool();
-            ByteBuffer header = bufferPool.acquire(client.getRequestBufferSize(), false);
-            ByteBuffer chunk = null;
-
-            ByteBuffer contentBuffer = null;
-            boolean lastContent = false;
-            if (!expects100Continue(request))
-            {
-                content.advance();
-                contentBuffer = content.getByteBuffer();
-                lastContent = content.isLast();
-            }
-            while (true)
-            {
-                HttpGenerator.Result result = generator.generateRequest(requestInfo, header, chunk, contentBuffer, lastContent);
-                switch (result)
-                {
-                    case NEED_CHUNK:
-                    {
-                        chunk = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false);
-                        break;
-                    }
-                    case FLUSH:
-                    {
-                        int size = 1;
-                        boolean hasChunk = chunk != null;
-                        if (hasChunk)
-                            ++size;
-                        boolean hasContent = contentBuffer != null;
-                        if (hasContent)
-                            ++size;
-                        ByteBuffer[] toWrite = new ByteBuffer[size];
-                        ByteBuffer[] toRecycle = new ByteBuffer[hasChunk ? 2 : 1];
-                        toWrite[0] = header;
-                        toRecycle[0] = header;
-                        if (hasChunk)
-                        {
-                            toWrite[1] = chunk;
-                            toRecycle[1] = chunk;
-                        }
-                        if (hasContent)
-                            toWrite[toWrite.length - 1] = contentBuffer;
-                        EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
-                        endPoint.write(new ByteBufferRecyclerCallback(callback, bufferPool, toRecycle), toWrite);
-                        return;
-                    }
-                    case DONE:
-                    {
-                        // The headers have already been generated, perhaps by a concurrent abort.
-                        callback.failed(new HttpRequestException("Could not generate headers", request));
-                        return;
-                    }
-                    default:
-                    {
-                        callback.failed(new IllegalStateException(result.toString()));
-                        return;
-                    }
-                }
-            }
+            new HeadersCallback(exchange, content, callback).iterate();
         }
         catch (Throwable x)
         {
@@ -143,6 +78,10 @@
                 ByteBuffer contentBuffer = content.getByteBuffer();
                 boolean lastContent = content.isLast();
                 HttpGenerator.Result result = generator.generateRequest(null, null, chunk, contentBuffer, lastContent);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Generated content ({} bytes) - {}/{}",
+                            contentBuffer == null ? -1 : contentBuffer.remaining(),
+                            result, generator);
                 switch (result)
                 {
                     case NEED_CHUNK:
@@ -166,22 +105,24 @@
                     }
                     case CONTINUE:
                     {
-                        break;
+                        if (lastContent)
+                            break;
+                        callback.succeeded();
+                        return;
                     }
                     case DONE:
                     {
-                        assert generator.isEnd();
                         callback.succeeded();
                         return;
                     }
                     default:
                     {
-                        throw new IllegalStateException();
+                        throw new IllegalStateException(result.toString());
                     }
                 }
             }
         }
-        catch (Exception x)
+        catch (Throwable x)
         {
             if (LOG.isDebugEnabled())
                 LOG.debug(x);
@@ -206,6 +147,8 @@
 
     private void shutdownOutput()
     {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Request shutdown output {}", getHttpExchange().getRequest());
         getHttpChannel().getHttpConnection().getEndPoint().shutdownOutput();
     }
 
@@ -215,6 +158,148 @@
         return String.format("%s[%s]", super.toString(), generator);
     }
 
+    private class HeadersCallback extends IteratingCallback
+    {
+        private final HttpExchange exchange;
+        private final Callback callback;
+        private final MetaData.Request metaData;
+        private ByteBuffer headerBuffer;
+        private ByteBuffer chunkBuffer;
+        private ByteBuffer contentBuffer;
+        private boolean lastContent;
+        private boolean generated;
+
+        public HeadersCallback(HttpExchange exchange, HttpContent content, Callback callback)
+        {
+            super(false);
+            this.exchange = exchange;
+            this.callback = callback;
+
+            Request request = exchange.getRequest();
+            ContentProvider requestContent = request.getContent();
+            long contentLength = requestContent == null ? -1 : requestContent.getLength();
+            String path = request.getPath();
+            String query = request.getQuery();
+            if (query != null)
+                path += "?" + query;
+            metaData = new MetaData.Request(request.getMethod(), new HttpURI(path), request.getVersion(), request.getHeaders(), contentLength);
+
+            if (!expects100Continue(request))
+            {
+                content.advance();
+                contentBuffer = content.getByteBuffer();
+                lastContent = content.isLast();
+            }
+        }
+
+        @Override
+        protected Action process() throws Exception
+        {
+            HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
+            ByteBufferPool bufferPool = client.getByteBufferPool();
+
+            while (true)
+            {
+                HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Generated headers ({} bytes), chunk ({} bytes), content ({} bytes) - {}/{}",
+                            headerBuffer == null ? -1 : headerBuffer.remaining(),
+                            chunkBuffer == null ? -1 : chunkBuffer.remaining(),
+                            contentBuffer == null ? -1 : contentBuffer.remaining(),
+                            result, generator);
+                switch (result)
+                {
+                    case NEED_HEADER:
+                    {
+                        headerBuffer = bufferPool.acquire(client.getRequestBufferSize(), false);
+                        break;
+                    }
+                    case NEED_CHUNK:
+                    {
+                        chunkBuffer = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false);
+                        break;
+                    }
+                    case FLUSH:
+                    {
+                        EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
+                        if (chunkBuffer == null)
+                        {
+                            if (contentBuffer == null)
+                                endPoint.write(this, headerBuffer);
+                            else
+                                endPoint.write(this, headerBuffer, contentBuffer);
+                        }
+                        else
+                        {
+                            if (contentBuffer == null)
+                                endPoint.write(this, headerBuffer, chunkBuffer);
+                            else
+                                endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer);
+                        }
+                        generated = true;
+                        return Action.SCHEDULED;
+                    }
+                    case SHUTDOWN_OUT:
+                    {
+                        shutdownOutput();
+                        return Action.SUCCEEDED;
+                    }
+                    case CONTINUE:
+                    {
+                        if (generated)
+                            return Action.SUCCEEDED;
+                        break;
+                    }
+                    case DONE:
+                    {
+                        if (generated)
+                            return Action.SUCCEEDED;
+                        // The headers have already been generated by some
+                        // other thread, perhaps by a concurrent abort().
+                        throw new HttpRequestException("Could not generate headers", exchange.getRequest());
+                    }
+                    default:
+                    {
+                        throw new IllegalStateException(result.toString());
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void succeeded()
+        {
+            release();
+            super.succeeded();
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            release();
+            callback.failed(x);
+            super.failed(x);
+        }
+
+        @Override
+        protected void onCompleteSuccess()
+        {
+            super.onCompleteSuccess();
+            callback.succeeded();
+        }
+
+        private void release()
+        {
+            HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
+            ByteBufferPool bufferPool = client.getByteBufferPool();
+            bufferPool.release(headerBuffer);
+            headerBuffer = null;
+            if (chunkBuffer != null)
+                bufferPool.release(chunkBuffer);
+            chunkBuffer = null;
+        }
+    }
+
     private class ByteBufferRecyclerCallback implements Callback
     {
         private final Callback callback;
@@ -229,6 +314,12 @@
         }
 
         @Override
+        public boolean isNonBlocking()
+        {
+            return callback.isNonBlocking();
+        }
+
+        @Override
         public void succeeded()
         {
             for (ByteBuffer buffer : buffers)
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java
index 77a29da..f6c81ca 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/package-info.java
@@ -20,32 +20,34 @@
  * Jetty Client : Implementation and Core Classes
  * 
  * This package provides APIs, utility classes and an implementation of an asynchronous HTTP client.
- * <p />
- * The core class is {@link org.eclipse.jetty.client.api.HttpClient}, which acts as a central configuration object (for example
- * for {@link org.eclipse.jetty.client.api.HttpClient#setIdleTimeout(long) idle timeouts}, {@link org.eclipse.jetty.client.api.HttpClient#setMaxConnectionsPerDestination(int)
- * max connections per destination}, etc.) and as a factory for {@link Request} objects.
- * <p />
+ * <p>
+ * The core class is {@link org.eclipse.jetty.client.HttpClient}, which acts as a central configuration object (for example
+ * for {@link org.eclipse.jetty.client.HttpClient#setIdleTimeout(long) idle timeouts}, {@link org.eclipse.jetty.client.HttpClient#setMaxConnectionsPerDestination(int)
+ * max connections per destination}, etc.) and as a factory for {@link org.eclipse.jetty.client.api.Request} objects.
+ * <p>
  * The HTTP protocol is based on the request/response paradigm, a unit that in this implementation is called
- * <em>exchange</em> and is represented by {@link org.eclipse.jetty.client.api.HttpExchange}.
+ * <em>exchange</em> and is represented by {@link org.eclipse.jetty.client.HttpExchange}.
  * An initial request may trigger a sequence of exchanges with one or more servers, called a <em>conversation</em>
- * and represented by {@link org.eclipse.jetty.client.api.HttpConversation}. A typical example of a conversation is a redirect, where
+ * and represented by {@link org.eclipse.jetty.client.HttpConversation}. A typical example of a conversation is a redirect, where
  * upon a request for a resource URI, the server replies with a redirect (for example with the 303 status code)
  * to another URI. This conversation is made of a first exchange made of the original request and its 303 response,
  * and of a second exchange made of the request for the new URI and its 200 response.
- * <p />
- * {@link org.eclipse.jetty.client.api.HttpClient} holds a number of {@link org.eclipse.jetty.client.api.HttpDestination destinations}, which in turn hold a number of
- * pooled {@link org.eclipse.jetty.client.api.HttpConnection connections}.
- * <p />
+ * <p>
+ * {@link org.eclipse.jetty.client.HttpClient} holds a number of {@link org.eclipse.jetty.client.api.Destination destinations}, which in turn hold a number of
+ * pooled {@link org.eclipse.jetty.client.api.Connection connections}.
+ * <p>
  * When a request is sent, its exchange is associated to a connection, either taken from an idle queue or created
  * anew, and when both the request and response are completed, the exchange is disassociated from the connection.
  * Conversations may span multiple connections on different destinations, and therefore are maintained at the
- * {@link org.eclipse.jetty.client.api.HttpClient} level.
- * <p />
+ * {@link org.eclipse.jetty.client.HttpClient} level.
+ * <p>
  * Applications may decide to send the request and wait for the response in a blocking way, using
  * {@link org.eclipse.jetty.client.api.Request#send()}.
  * Alternatively, application may ask to be notified of response events asynchronously, using
- * {@link org.eclipse.jetty.client.api.Request#send(Response.Listener)}.
+ * {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)}.
  */
 package org.eclipse.jetty.client;
 
+import org.eclipse.jetty.client.api.Response;
+
 
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
index e37f82b..83b449d 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java
@@ -21,7 +21,9 @@
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
 
+import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.Authentication;
+import org.eclipse.jetty.client.api.AuthenticationStore;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.http.HttpHeader;
@@ -30,7 +32,7 @@
 
 /**
  * Implementation of the HTTP "Basic" authentication defined in RFC 2617.
- * <p />
+ * <p>
  * Applications should create objects of this class and add them to the
  * {@link AuthenticationStore} retrieved from the {@link HttpClient}
  * via {@link HttpClient#getAuthenticationStore()}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
index b170f85..cde6062 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/ByteBufferContentProvider.java
@@ -22,9 +22,11 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.eclipse.jetty.client.api.ContentProvider;
+
 /**
  * A {@link ContentProvider} for {@link ByteBuffer}s.
- * <p />
+ * <p>
  * The position and limit of the {@link ByteBuffer}s passed to the constructor are not modified,
  * and each invocation of the {@link #iterator()} method returns a {@link ByteBuffer#slice() slice}
  * of the original {@link ByteBuffer}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
index 95f18ef..2140153 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BytesContentProvider.java
@@ -22,6 +22,8 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.eclipse.jetty.client.api.ContentProvider;
+
 /**
  * A {@link ContentProvider} for byte arrays.
  */
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
index bc4868d..49fadbe 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DeferredContentProvider.java
@@ -42,11 +42,11 @@
 /**
  * A {@link ContentProvider} that allows to add content after {@link Request#send(Response.CompleteListener)}
  * has been called, therefore providing the request content at a later time.
- * <p />
+ * <p>
  * {@link DeferredContentProvider} can only be used in conjunction with
  * {@link Request#send(Response.CompleteListener)} (and not with its blocking counterpart {@link Request#send()})
  * because it provides content asynchronously.
- * <p />
+ * <p>
  * The deferred content is provided once and then fully consumed.
  * Invocations to the {@link #iterator()} method after the first will return an "empty" iterator
  * because the stream has been consumed on the first invocation.
@@ -55,13 +55,13 @@
  * of of {@link #iterator()} returning the iterator provided by this
   * class on the first invocation, and an iterator on the bytes copied to the other location
   * for subsequent invocations.
- * <p />
+ * <p>
  * Typical usage of {@link DeferredContentProvider} is in asynchronous proxies, where HTTP headers arrive
  * separately from HTTP content chunks.
- * <p />
+ * <p>
  * The deferred content must be provided through {@link #offer(ByteBuffer)}, which can be invoked multiple
  * times, and when all content has been provided it must be signaled with a call to {@link #close()}.
- * <p />
+ * <p>
  * Example usage:
  * <pre>
  * HttpClient httpClient = ...;
@@ -73,7 +73,7 @@
  *             .content(content)
  *             .send(new Response.CompleteListener()
  *             {
- *                 &#64Override
+ *                 &#64;Override
  *                 public void onComplete(Result result)
  *                 {
  *                     // Your logic here
@@ -87,7 +87,7 @@
  */
 public class DeferredContentProvider implements AsyncContentProvider, Callback, Closeable
 {
-    private static final Chunk CLOSE = new Chunk(BufferUtil.EMPTY_BUFFER, Callback.Adapter.INSTANCE);
+    private static final Chunk CLOSE = new Chunk(BufferUtil.EMPTY_BUFFER, Callback.NOOP);
 
     private final Object lock = this;
     private final ArrayQueue<Chunk> chunks = new ArrayQueue<>(4, 64, lock);
@@ -143,7 +143,7 @@
      */
     public boolean offer(ByteBuffer buffer)
     {
-        return offer(buffer, Callback.Adapter.INSTANCE);
+        return offer(buffer, Callback.NOOP);
     }
 
     public boolean offer(ByteBuffer buffer, Callback callback)
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
index 0a131b7..2af088c 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/DigestAuthentication.java
@@ -33,7 +33,9 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.Authentication;
+import org.eclipse.jetty.client.api.AuthenticationStore;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.http.HttpHeader;
@@ -43,7 +45,7 @@
 
 /**
  * Implementation of the HTTP "Digest" authentication defined in RFC 2617.
- * <p />
+ * <p>
  * Applications should create objects of this class and add them to the
  * {@link AuthenticationStore} retrieved from the {@link HttpClient}
  * via {@link HttpClient#getAuthenticationStore()}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
index de60659..1246e32 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FormContentProvider.java
@@ -24,6 +24,7 @@
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
 
+import org.eclipse.jetty.client.api.ContentProvider;
 import org.eclipse.jetty.util.Fields;
 
 /**
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java
index 3519a71..90c9324 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/FutureResponseListener.java
@@ -34,7 +34,7 @@
  * A {@link BufferingResponseListener} that is also a {@link Future}, to allow applications
  * to block (indefinitely or for a timeout) until {@link #onComplete(Result)} is called,
  * or to {@link #cancel(boolean) abort} the request/response conversation.
- * <p />
+ * <p>
  * Typical usage is:
  * <pre>
  * Request request = httpClient.newRequest(...)...;
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
index 025e929..7729763 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamContentProvider.java
@@ -33,20 +33,20 @@
 
 /**
  * A {@link ContentProvider} for an {@link InputStream}.
- * <p />
+ * <p>
  * The input stream is read once and therefore fully consumed.
  * Invocations to the {@link #iterator()} method after the first will return an "empty" iterator
  * because the stream has been consumed on the first invocation.
- * <p />
+ * <p>
  * However, it is possible for subclasses to override {@link #onRead(byte[], int, int)} to copy
  * the content read from the stream to another location (for example a file), and be able to
  * support multiple invocations of {@link #iterator()}, returning the iterator provided by this
  * class on the first invocation, and an iterator on the bytes copied to the other location
  * for subsequent invocations.
- * <p />
+ * <p>
  * It is possible to specify, at the constructor, a buffer size used to read content from the
  * stream, by default 4096 bytes.
- * <p />
+ * <p>
  * The {@link InputStream} passed to the constructor is by default closed when is it fully
  * consumed (or when an exception is thrown while reading it), unless otherwise specified
  * to the {@link #InputStreamContentProvider(java.io.InputStream, int, boolean) constructor}.
@@ -87,7 +87,7 @@
      * Callback method invoked just after having read from the stream,
      * but before returning the iteration element (a {@link ByteBuffer}
      * to the caller.
-     * <p />
+     * <p>
      * Subclasses may override this method to copy the content read from
      * the stream to another location (a file, or in memory if the content
      * is known to fit).
@@ -154,12 +154,12 @@
      * means that stream reading must be performed by {@link #hasNext()}, which introduces a side-effect
      * on what is supposed to be a simple query method (with respect to the Query Command Separation
      * Principle).
-     * <p />
+     * <p>
      * Alternatively, we could return {@code true} from {@link #hasNext()} even if we don't know that
      * we will read -1, but then when {@link #next()} reads -1 it must return an empty buffer.
      * However this is problematic, since GETs with no content indication would become GET with chunked
      * content, and not understood by servers.
-     * <p />
+     * <p>
      * Therefore we need to make sure that {@link #hasNext()} does not perform any side effect (so that
      * it can be called multiple times) until {@link #next()} is called.
      */
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
index e9d5b83..258309e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
@@ -32,6 +32,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.api.Response.Listener;
 import org.eclipse.jetty.client.api.Result;
@@ -42,7 +43,7 @@
 /**
  * Implementation of {@link Listener} that produces an {@link InputStream}
  * that allows applications to read the response content.
- * <p />
+ * <p>
  * Typical usage is:
  * <pre>
  * InputStreamResponseListener listener = new InputStreamResponseListener();
@@ -59,12 +60,12 @@
  *     }
  * }
  * </pre>
- * <p />
+ * <p>
  * The {@link HttpClient} implementation (the producer) will feed the input stream
  * asynchronously while the application (the consumer) is reading from it.
  * Chunks of content are maintained in a queue, and it is possible to specify a
  * maximum buffer size for the bytes held in the queue, by default 16384 bytes.
- * <p />
+ * <p>
  * If the consumer is faster than the producer, then the consumer will block
  * with the typical {@link InputStream#read()} semantic.
  * If the consumer is slower than the producer, then the producer will block
@@ -208,7 +209,7 @@
 
     /**
      * Waits for the given timeout for the response to be available, then returns it.
-     * <p />
+     * <p>
      * The wait ends as soon as all the HTTP headers have been received, without waiting for the content.
      * To wait for the whole content, see {@link #await(long, TimeUnit)}.
      *
@@ -232,7 +233,7 @@
     /**
      * Waits for the given timeout for the whole request/response cycle to be finished,
      * then returns the corresponding result.
-     * <p />
+     * <p>
      *
      * @param timeout the time to wait
      * @param unit the timeout unit
@@ -251,7 +252,7 @@
 
     /**
      * Returns an {@link InputStream} providing the response content bytes.
-     * <p />
+     * <p>
      * The method may be invoked only once; subsequent invocations will return a closed {@link InputStream}.
      *
      * @return an input stream providing the response content
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java
new file mode 100644
index 0000000..8da7796
--- /dev/null
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartContentProvider.java
@@ -0,0 +1,404 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.jetty.client.AsyncContentProvider;
+import org.eclipse.jetty.client.Synchronizable;
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.io.RuntimeIOException;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>A {@link ContentProvider} for form uploads with the {@code "multipart/form-data"}
+ * content type.</p>
+ * <p>Example usage:</p>
+ * <pre>
+ * MultiPartContentProvider multiPart = new MultiPartContentProvider();
+ * multiPart.addFieldPart("field", new StringContentProvider("foo"), null);
+ * multiPart.addFilePart("icon", "img.png", new PathContentProvider(Paths.get("/tmp/img.png")), null);
+ * multiPart.close();
+ * ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+ *         .method(HttpMethod.POST)
+ *         .content(multiPart)
+ *         .send();
+ * </pre>
+ * <p>The above example would be the equivalent of submitting this form:</p>
+ * <pre>
+ * &lt;form method="POST" enctype="multipart/form-data"  accept-charset="UTF-8"&gt;
+ *     &lt;input type="text" name="field" value="foo" /&gt;
+ *     &lt;input type="file" name="icon" /&gt;
+ * &lt;/form&gt;
+ * </pre>
+ */
+public class MultiPartContentProvider extends AbstractTypedContentProvider implements AsyncContentProvider, Closeable
+{
+    private static final Logger LOG = Log.getLogger(MultiPartContentProvider.class);
+    private static final byte[] COLON_SPACE_BYTES = new byte[]{':', ' '};
+    private static final byte[] CR_LF_BYTES = new byte[]{'\r', '\n'};
+
+    private final List<Part> parts = new ArrayList<>();
+    private final ByteBuffer firstBoundary;
+    private final ByteBuffer middleBoundary;
+    private final ByteBuffer onlyBoundary;
+    private final ByteBuffer lastBoundary;
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private Listener listener;
+    private long length = -1;
+
+    public MultiPartContentProvider()
+    {
+        this(makeBoundary());
+    }
+
+    public MultiPartContentProvider(String boundary)
+    {
+        super("multipart/form-data; boundary=" + boundary);
+        String firstBoundaryLine = "--" + boundary + "\r\n";
+        this.firstBoundary = ByteBuffer.wrap(firstBoundaryLine.getBytes(StandardCharsets.US_ASCII));
+        String middleBoundaryLine = "\r\n" + firstBoundaryLine;
+        this.middleBoundary = ByteBuffer.wrap(middleBoundaryLine.getBytes(StandardCharsets.US_ASCII));
+        String onlyBoundaryLine = "--" + boundary + "--\r\n";
+        this.onlyBoundary = ByteBuffer.wrap(onlyBoundaryLine.getBytes(StandardCharsets.US_ASCII));
+        String lastBoundaryLine = "\r\n" + onlyBoundaryLine;
+        this.lastBoundary = ByteBuffer.wrap(lastBoundaryLine.getBytes(StandardCharsets.US_ASCII));
+    }
+
+    private static String makeBoundary()
+    {
+        Random random = new Random();
+        StringBuilder builder = new StringBuilder("JettyHttpClientBoundary");
+        int length = builder.length();
+        while (builder.length() < length + 16)
+        {
+            long rnd = random.nextLong();
+            builder.append(Long.toString(rnd < 0 ? -rnd : rnd, 36));
+        }
+        builder.setLength(length + 16);
+        return builder.toString();
+    }
+
+    /**
+     * <p>Adds a field part with the given {@code name} as field name, and the given
+     * {@code content} as part content.</p>
+     * <p>The {@code Content-Type} of this part will be obtained from:</p>
+     * <ul>
+     *     <li>the {@code Content-Type} header in the {@code fields} parameter; otherwise</li>
+     *     <li>the {@link Typed#getContentType()} method if the {@code content} parameter
+     *     implements {@link Typed}; otherwise</li>
+     *     <li>"text/plain"</li>
+     * </ul>
+     *
+     * @param name the part name
+     * @param content the part content
+     * @param fields the headers associated with this part
+     */
+    public void addFieldPart(String name, ContentProvider content, HttpFields fields)
+    {
+        addPart(new Part(name, null, "text/plain", content, fields));
+    }
+
+    /**
+     * <p>Adds a file part with the given {@code name} as field name, the given
+     * {@code fileName} as file name, and the given {@code content} as part content.</p>
+     * <p>The {@code Content-Type} of this part will be obtained from:</p>
+     * <ul>
+     *     <li>the {@code Content-Type} header in the {@code fields} parameter; otherwise</li>
+     *     <li>the {@link Typed#getContentType()} method if the {@code content} parameter
+     *     implements {@link Typed}; otherwise</li>
+     *     <li>"application/octet-stream"</li>
+     * </ul>
+     *
+     * @param name the part name
+     * @param fileName the file name associated to this part
+     * @param content the part content
+     * @param fields the headers associated with this part
+     */
+    public void addFilePart(String name, String fileName, ContentProvider content, HttpFields fields)
+    {
+        addPart(new Part(name, fileName, "application/octet-stream", content, fields));
+    }
+
+    private void addPart(Part part)
+    {
+        parts.add(part);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Added {}", part);
+    }
+
+    @Override
+    public void setListener(Listener listener)
+    {
+        this.listener = listener;
+        if (closed.get())
+            this.length = calculateLength();
+    }
+
+    private long calculateLength()
+    {
+        // Compute the length, if possible.
+        if (parts.isEmpty())
+        {
+            return onlyBoundary.remaining();
+        }
+        else
+        {
+            long result = 0;
+            for (int i = 0; i < parts.size(); ++i)
+            {
+                result += (i == 0) ? firstBoundary.remaining() : middleBoundary.remaining();
+                Part part = parts.get(i);
+                long partLength = part.length;
+                result += partLength;
+                if (partLength < 0)
+                {
+                    result = -1;
+                    break;
+                }
+            }
+            if (result > 0)
+                result += lastBoundary.remaining();
+            return result;
+        }
+    }
+
+    @Override
+    public long getLength()
+    {
+        return length;
+    }
+
+    @Override
+    public Iterator<ByteBuffer> iterator()
+    {
+        return new MultiPartIterator();
+    }
+
+    @Override
+    public void close()
+    {
+        closed.compareAndSet(false, true);
+    }
+
+    private static class Part
+    {
+        private final String name;
+        private final String fileName;
+        private final String contentType;
+        private final ContentProvider content;
+        private final HttpFields fields;
+        private final ByteBuffer headers;
+        private final long length;
+
+        private Part(String name, String fileName, String contentType, ContentProvider content, HttpFields fields)
+        {
+            this.name = name;
+            this.fileName = fileName;
+            this.contentType = contentType;
+            this.content = content;
+            this.fields = fields;
+            this.headers = headers();
+            this.length = content.getLength() < 0 ? -1 : headers.remaining() + content.getLength();
+        }
+
+        private ByteBuffer headers()
+        {
+            try
+            {
+                // Compute the Content-Disposition.
+                String contentDisposition = "Content-Disposition: form-data; name=\"" + name + "\"";
+                if (fileName != null)
+                    contentDisposition += "; filename=\"" + fileName + "\"";
+                contentDisposition += "\r\n";
+
+                // Compute the Content-Type.
+                String contentType = fields == null ? null : fields.get(HttpHeader.CONTENT_TYPE);
+                if (contentType == null)
+                {
+                    if (content instanceof Typed)
+                        contentType = ((Typed)content).getContentType();
+                    else
+                        contentType = this.contentType;
+                }
+                contentType = "Content-Type: " + contentType + "\r\n";
+
+                if (fields == null || fields.size() == 0)
+                {
+                    String headers = contentDisposition;
+                    headers += contentType;
+                    headers += "\r\n";
+                    return ByteBuffer.wrap(headers.getBytes(StandardCharsets.UTF_8));
+                }
+
+                ByteArrayOutputStream buffer = new ByteArrayOutputStream((fields.size() + 1) * contentDisposition.length());
+                buffer.write(contentDisposition.getBytes(StandardCharsets.UTF_8));
+                buffer.write(contentType.getBytes(StandardCharsets.UTF_8));
+                for (HttpField field : fields)
+                {
+                    if (HttpHeader.CONTENT_TYPE.equals(field.getHeader()))
+                        continue;
+                    buffer.write(field.getName().getBytes(StandardCharsets.US_ASCII));
+                    buffer.write(COLON_SPACE_BYTES);
+                    buffer.write(field.getValue().getBytes(StandardCharsets.UTF_8));
+                    buffer.write(CR_LF_BYTES);
+                }
+                buffer.write(CR_LF_BYTES);
+                return ByteBuffer.wrap(buffer.toByteArray());
+            }
+            catch (IOException x)
+            {
+                throw new RuntimeIOException(x);
+            }
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s@%x[name=%s,fileName=%s,length=%d,headers=%s]",
+                    getClass().getSimpleName(),
+                    hashCode(),
+                    name,
+                    fileName,
+                    content.getLength(),
+                    fields);
+        }
+    }
+
+    private class MultiPartIterator implements Iterator<ByteBuffer>, Synchronizable, Callback, Closeable
+    {
+        private Iterator<ByteBuffer> iterator;
+        private int index;
+        private State state = State.FIRST_BOUNDARY;
+
+        @Override
+        public boolean hasNext()
+        {
+            return state != State.COMPLETE;
+        }
+
+        @Override
+        public ByteBuffer next()
+        {
+            while (true)
+            {
+                switch (state)
+                {
+                    case FIRST_BOUNDARY:
+                    {
+                        if (parts.isEmpty())
+                        {
+                            state = State.COMPLETE;
+                            return onlyBoundary.slice();
+                        }
+                        else
+                        {
+                            state = State.HEADERS;
+                            return firstBoundary.slice();
+                        }
+                    }
+                    case HEADERS:
+                    {
+                        Part part = parts.get(index);
+                        ContentProvider content = part.content;
+                        if (content instanceof AsyncContentProvider)
+                            ((AsyncContentProvider)content).setListener(listener);
+                        iterator = content.iterator();
+                        state = State.CONTENT;
+                        return part.headers.slice();
+                    }
+                    case CONTENT:
+                    {
+                        if (iterator.hasNext())
+                            return iterator.next();
+                        ++index;
+                        if (index == parts.size())
+                            state = State.LAST_BOUNDARY;
+                        else
+                            state = State.MIDDLE_BOUNDARY;
+                        break;
+                    }
+                    case MIDDLE_BOUNDARY:
+                    {
+                        state = State.HEADERS;
+                        return middleBoundary.slice();
+                    }
+                    case LAST_BOUNDARY:
+                    {
+                        state = State.COMPLETE;
+                        return lastBoundary.slice();
+                    }
+                    case COMPLETE:
+                    {
+                        throw new NoSuchElementException();
+                    }
+                }
+            }
+        }
+
+        @Override
+        public Object getLock()
+        {
+            if (iterator instanceof Synchronizable)
+                return ((Synchronizable)iterator).getLock();
+            return this;
+        }
+
+        @Override
+        public void succeeded()
+        {
+            if (iterator instanceof Callback)
+                ((Callback)iterator).succeeded();
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            if (iterator instanceof Callback)
+                ((Callback)iterator).failed(x);
+        }
+
+        @Override
+        public void close() throws IOException
+        {
+            if (iterator instanceof Closeable)
+                ((Closeable)iterator).close();
+        }
+    }
+
+    private enum State
+    {
+        FIRST_BOUNDARY, HEADERS, CONTENT, MIDDLE_BOUNDARY, LAST_BOUNDARY, COMPLETE
+    }
+}
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
index f4a8c45..e93a49e 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/OutputStreamContentProvider.java
@@ -33,11 +33,11 @@
 /**
  * A {@link ContentProvider} that provides content asynchronously through an {@link OutputStream}
  * similar to {@link DeferredContentProvider}.
- * <p />
+ * <p>
  * {@link OutputStreamContentProvider} can only be used in conjunction with
  * {@link Request#send(Response.CompleteListener)} (and not with its blocking counterpart {@link Request#send()})
  * because it provides content asynchronously.
- * <p />
+ * <p>
  * The deferred content is provided once by writing to the {@link #getOutputStream() output stream}
  * and then fully consumed.
  * Invocations to the {@link #iterator()} method after the first will return an "empty" iterator
@@ -45,10 +45,10 @@
  * However, it is possible for subclasses to support multiple invocations of {@link #iterator()}
  * by overriding {@link #write(ByteBuffer)} and {@link #close()}, copying the bytes and making them
  * available for subsequent invocations.
- * <p />
+ * <p>
  * Content must be provided by writing to the {@link #getOutputStream() output stream}, that must be
  * {@link OutputStream#close() closed} when all content has been provided.
- * <p />
+ * <p>
  * Example usage:
  * <pre>
  * HttpClient httpClient = ...;
@@ -61,7 +61,7 @@
  *             .content(content)
  *             .send(new Response.CompleteListener()
  *             {
- *                 &#64Override
+ *                 &#64;Override
  *                 public void onComplete(Result result)
  *                 {
  *                     // Your logic here
@@ -79,6 +79,12 @@
     private final OutputStream output = new DeferredOutputStream();
 
     @Override
+    public boolean isNonBlocking()
+    {
+        return deferred.isNonBlocking();
+    }
+    
+    @Override
     public long getLength()
     {
         return deferred.getLength();
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
index 7af174a..ed83660 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/PathContentProvider.java
@@ -30,12 +30,13 @@
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
+import org.eclipse.jetty.client.api.ContentProvider;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
 /**
  * A {@link ContentProvider} for files using JDK 7's {@code java.nio.file} APIs.
- * <p />
+ * <p>
  * It is possible to specify, at the constructor, a buffer size used to read content from the
  * stream, by default 4096 bytes.
  */
@@ -131,7 +132,7 @@
                 close();
                 throw x;
             }
-            catch (Exception x)
+            catch (Throwable x)
             {
                 close();
                 throw (NoSuchElementException)new NoSuchElementException().initCause(x);
@@ -152,7 +153,7 @@
                 if (channel != null)
                     channel.close();
             }
-            catch (Exception x)
+            catch (Throwable x)
             {
                 LOG.ignore(x);
             }
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
index 2acbf1e..4b83fa8 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/StringContentProvider.java
@@ -21,9 +21,11 @@
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
+import org.eclipse.jetty.client.api.ContentProvider;
+
 /**
  * A {@link ContentProvider} for strings.
- * <p />
+ * <p>
  * It is possible to specify, at the constructor, an encoding used to convert
  * the string into bytes, by default UTF-8.
  */
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java
index f89988d..8f0cbff 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AbstractHttpClientServerTest.java
@@ -21,9 +21,9 @@
 import java.util.Arrays;
 import java.util.Collection;
 
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.NetworkConnector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.toolchain.test.TestTracker;
@@ -50,7 +50,7 @@
     protected String scheme;
     protected Server server;
     protected HttpClient client;
-    protected NetworkConnector connector;
+    protected ServerConnector connector;
 
     public AbstractHttpClientServerTest(SslContextFactory sslContextFactory)
     {
@@ -89,9 +89,14 @@
 
     protected void startClient() throws Exception
     {
+        startClient(new HttpClientTransportOverHTTP(1));
+    }
+
+    protected void startClient(HttpClientTransport transport) throws Exception
+    {
         QueuedThreadPool clientThreads = new QueuedThreadPool();
         clientThreads.setName("client");
-        client = new HttpClient(sslContextFactory);
+        client = new HttpClient(transport, sslContextFactory);
         client.setExecutor(clientThreads);
         client.start();
     }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java
new file mode 100644
index 0000000..ff7eb33
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ClientConnectionCloseTest.java
@@ -0,0 +1,122 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.util.DeferredContentProvider;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ClientConnectionCloseTest extends AbstractHttpClientServerTest
+{
+    public ClientConnectionCloseTest(SslContextFactory sslContextFactory)
+    {
+        super(sslContextFactory);
+    }
+
+    @Test
+    public void testClientConnectionCloseShutdownOutputWithoutRequestContent() throws Exception
+    {
+        testClientConnectionCloseShutdownOutput(null);
+    }
+
+    @Test
+    public void testClientConnectionCloseShutdownOutputWithRequestContent() throws Exception
+    {
+        testClientConnectionCloseShutdownOutput(new StringContentProvider("data", StandardCharsets.UTF_8));
+    }
+
+    @Test
+    public void testClientConnectionCloseShutdownOutputWithChunkedRequestContent() throws Exception
+    {
+        DeferredContentProvider content = new DeferredContentProvider()
+        {
+            @Override
+            public long getLength()
+            {
+                return -1;
+            }
+        };
+        content.offer(ByteBuffer.wrap("data".getBytes(StandardCharsets.UTF_8)));
+        content.close();
+        testClientConnectionCloseShutdownOutput(content);
+    }
+
+    private void testClientConnectionCloseShutdownOutput(ContentProvider content) throws Exception
+    {
+        AtomicReference<EndPoint> ref = new AtomicReference<>();
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                ref.set(baseRequest.getHttpChannel().getEndPoint());
+                ServletInputStream input = request.getInputStream();
+                while (true)
+                {
+                    int read = input.read();
+                    if (read < 0)
+                        break;
+                }
+                response.setStatus(HttpStatus.OK_200);
+            }
+        });
+
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .path("/ctx/path")
+                .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())
+                .content(content)
+                .send();
+
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+        // Wait for the FIN to arrive to the server
+        Thread.sleep(1000);
+
+        // Do not read from the server because it will trigger
+        // the send of the TLS Close Message before the response.
+
+        EndPoint serverEndPoint = ref.get();
+        ByteBuffer buffer = BufferUtil.allocate(1);
+        int read = serverEndPoint.fill(buffer);
+        Assert.assertEquals(-1, read);
+    }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java
index df8e636..f264350 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ContentResponseTest.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
index 2b70e3b..d066aec 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java
@@ -22,6 +22,7 @@
 import java.nio.channels.ClosedChannelException;
 import java.security.cert.CertificateException;
 import java.util.concurrent.ExecutionException;
+
 import javax.net.ssl.SSLHandshakeException;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -94,7 +95,7 @@
      * http://www.ietf.org/rfc/rfc2818.txt section 3.1. It uses a certificate with a common name different to localhost
      * and sends a request to localhost. This should fail with a SSLHandshakeException.
      *
-     * @throws Exception
+     * @throws Exception on test failure
      */
     @Test
     public void simpleGetWithHostnameVerificationEnabledTest() throws Exception
@@ -132,7 +133,8 @@
      * This test has hostname verification disabled and connecting, ssl handshake and sending the request should just
      * work fine.
      *
-     * @throws Exception
+     * @throws Exception on test failure
+     * 
      */
     @Test
     public void simpleGetWithHostnameVerificationDisabledTest() throws Exception
@@ -153,7 +155,7 @@
      * This test has hostname verification disabled by setting trustAll to true and connecting,
      * ssl handshake and sending the request should just work fine.
      *
-     * @throws Exception
+     * @throws Exception on test failure
      */
     @Test
     public void trustAllDisablesHostnameVerificationTest() throws Exception
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java
index 9c7bf95..7e35b55 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAsyncContentTest.java
@@ -24,6 +24,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java
index 840ba2a..d654ba0 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java
@@ -27,8 +27,6 @@
 import java.net.Socket;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
-import java.util.Iterator;
-import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import javax.servlet.ServletException;
@@ -404,7 +402,7 @@
         });
 
         client.getProtocolHandlers().clear();
-        client.getProtocolHandlers().add(new ContinueProtocolHandler(client)
+        client.getProtocolHandlers().put(new ContinueProtocolHandler()
         {
             @Override
             public Response.Listener getResponseListener()
@@ -608,14 +606,7 @@
 
         final DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(chunk1));
 
-        List<ProtocolHandler> protocolHandlers = client.getProtocolHandlers();
-        for (Iterator<ProtocolHandler> iterator = protocolHandlers.iterator(); iterator.hasNext();)
-        {
-            ProtocolHandler protocolHandler = iterator.next();
-            if (protocolHandler instanceof ContinueProtocolHandler)
-                iterator.remove();
-        }
-        protocolHandlers.add(new ContinueProtocolHandler(client)
+        client.getProtocolHandlers().put(new ContinueProtocolHandler()
         {
             @Override
             public Response.Listener getResponseListener()
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java
index 0ac4808..78fefd8 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCustomProxyTest.java
@@ -93,7 +93,7 @@
             public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
             {
                 baseRequest.setHandled(true);
-                if (!URI.create(baseRequest.getUri().toString()).isAbsolute())
+                if (!URI.create(baseRequest.getHttpURI().toString()).isAbsolute())
                     response.setStatus(HttpServletResponse.SC_USE_PROXY);
                 else if (serverHost.equals(request.getServerName()))
                     response.setStatus(status);
@@ -146,7 +146,7 @@
         }
     }
 
-    private class CAFEBABEConnection extends AbstractConnection
+    private class CAFEBABEConnection extends AbstractConnection implements Callback
     {
         private final ClientConnectionFactory connectionFactory;
         private final Map<String, Object> context;
@@ -162,8 +162,19 @@
         public void onOpen()
         {
             super.onOpen();
+            getEndPoint().write(this, ByteBuffer.wrap(CAFE_BABE));
+        }
+
+        @Override
+        public void succeeded()
+        {
             fillInterested();
-            getEndPoint().write(new Callback.Adapter(), ByteBuffer.wrap(CAFE_BABE));
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            close();
         }
 
         @Override
@@ -177,7 +188,7 @@
                 Assert.assertArrayEquals(CAFE_BABE, buffer.array());
 
                 // We are good, upgrade the connection
-                ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(getEndPoint(), context));
+                getEndPoint().upgrade(connectionFactory.newConnection(getEndPoint(), context));
             }
             catch (Throwable x)
             {
@@ -206,7 +217,7 @@
         }
     }
 
-    private class CAFEBABEServerConnection extends AbstractConnection
+    private class CAFEBABEServerConnection extends AbstractConnection implements Callback
     {
         private final org.eclipse.jetty.server.ConnectionFactory connectionFactory;
 
@@ -232,15 +243,25 @@
                 int filled = getEndPoint().fill(buffer);
                 Assert.assertEquals(4, filled);
                 Assert.assertArrayEquals(CAFE_BABE, buffer.array());
-                getEndPoint().write(new Callback.Adapter(), buffer);
-
-                // We are good, upgrade the connection
-                ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(connector, getEndPoint()));
+                getEndPoint().write(this, buffer);
             }
             catch (Throwable x)
             {
                 close();
             }
         }
+
+        @Override
+        public void succeeded()
+        {
+            // We are good, upgrade the connection
+            getEndPoint().upgrade(connectionFactory.newConnection(connector, getEndPoint()));
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            close();
+        }
     }
 }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java
index 631f9e8..b68d614 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java
@@ -59,7 +59,7 @@
             Assert.assertEquals(200, response.getStatus());
 
             HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP)destination;
-            ConnectionPool connectionPool = httpDestination.getConnectionPool();
+            DuplexConnectionPool connectionPool = httpDestination.getConnectionPool();
             Assert.assertTrue(connectionPool.getActiveConnections().isEmpty());
             Assert.assertTrue(connectionPool.getIdleConnections().isEmpty());
         }
@@ -94,7 +94,7 @@
         Assert.assertFalse(httpConnection.getEndPoint().isOpen());
 
         HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP)destination;
-        ConnectionPool connectionPool = httpDestination.getConnectionPool();
+        DuplexConnectionPool connectionPool = httpDestination.getConnectionPool();
         Assert.assertTrue(connectionPool.getActiveConnections().isEmpty());
         Assert.assertTrue(connectionPool.getIdleConnections().isEmpty());
     }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java
index 19100d1..48eea5a 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientFailureTest.java
@@ -106,7 +106,7 @@
             // Expected.
         }
 
-        ConnectionPool connectionPool = connectionRef.get().getHttpDestination().getConnectionPool();
+        DuplexConnectionPool connectionPool = connectionRef.get().getHttpDestination().getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -157,7 +157,7 @@
 
         Assert.assertTrue(commitLatch.await(5, TimeUnit.SECONDS));
         final CountDownLatch contentLatch = new CountDownLatch(1);
-        content.offer(ByteBuffer.allocate(1024), new Callback.Adapter()
+        content.offer(ByteBuffer.allocate(1024), new Callback()
         {
             @Override
             public void failed(Throwable x)
@@ -170,7 +170,7 @@
         Assert.assertTrue(contentLatch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
 
-        ConnectionPool connectionPool = connectionRef.get().getHttpDestination().getConnectionPool();
+        DuplexConnectionPool connectionPool = connectionRef.get().getHttpDestination().getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java
index f5e22c7..eac6df4 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientGZIPTest.java
@@ -32,8 +32,6 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -217,14 +215,10 @@
         final CountDownLatch latch = new CountDownLatch(1);
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .send(new Response.CompleteListener()
+                .send(result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
-                    {
-                        if (result.isFailed())
-                            latch.countDown();
-                    }
+                    if (result.isFailed())
+                        latch.countDown();
                 });
 
         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java
index 6cd0f64..6faa877 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientLoadTest.java
@@ -29,6 +29,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.IntStream;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -58,10 +59,10 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.Scheduler;
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
 
 public class HttpClientLoadTest extends AbstractHttpClientServerTest
@@ -100,7 +101,7 @@
                 return new HttpDestinationOverHTTP(getHttpClient(), origin)
                 {
                     @Override
-                    protected ConnectionPool newConnectionPool(HttpClient client)
+                    protected DuplexConnectionPool newConnectionPool(HttpClient client)
                     {
                         return new LeakTrackingConnectionPool(this, client.getMaxConnectionsPerDestination(), this)
                         {
@@ -143,18 +144,31 @@
 
         System.gc();
 
-        assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), is(0L));
+        assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), Matchers.is(0L));
+        assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), Matchers.is(0L));
+        assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), Matchers.is(0L));
 
-        assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), is(0L));
+        assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), Matchers.is(0L));
+        assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), Matchers.is(0L));
+        assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), Matchers.is(0L));
 
-        assertThat("Connection Leaks", connectionLeaks.get(), is(0L));
+        assertThat("Connection Leaks", connectionLeaks.get(), Matchers.is(0L));
     }
 
-    private void run(Random random, int iterations) throws InterruptedException
+    @Test
+    public void testConcurrent() throws Exception
+    {
+        start(new LoadHandler());
+
+        Random random = new Random();
+        int runs = 1;
+        int iterations = 256;
+        IntStream.range(0, 16).parallel().forEach(i ->
+                IntStream.range(0, runs).forEach(j ->
+                        run(random, iterations)));
+    }
+
+    private void run(Random random, int iterations)
     {
         CountDownLatch latch = new CountDownLatch(iterations);
         List<String> failures = new ArrayList<>();
@@ -173,7 +187,7 @@
                 for (String host : Arrays.asList("localhost", "127.0.0.1"))
                 {
                     HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, connector.getLocalPort());
-                    ConnectionPool connectionPool = destination.getConnectionPool();
+                    DuplexConnectionPool connectionPool = destination.getConnectionPool();
                     for (Connection connection : new ArrayList<>(connectionPool.getActiveConnections()))
                     {
                         HttpConnectionOverHTTP active = (HttpConnectionOverHTTP)connection;
@@ -190,7 +204,7 @@
             test(random, latch, failures);
 //            test("http", "localhost", "GET", false, false, 64 * 1024, false, latch, failures);
         }
-        Assert.assertTrue(latch.await(iterations, TimeUnit.SECONDS));
+        Assert.assertTrue(await(latch, iterations, TimeUnit.SECONDS));
         long end = System.nanoTime();
         task.cancel();
         long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin);
@@ -202,7 +216,7 @@
         Assert.assertTrue(failures.toString(), failures.isEmpty());
     }
 
-    private void test(Random random, final CountDownLatch latch, final List<String> failures) throws InterruptedException
+    private void test(Random random, final CountDownLatch latch, final List<String> failures)
     {
         // Choose a random destination
         String host = random.nextBoolean() ? "localhost" : "127.0.0.1";
@@ -225,7 +239,7 @@
         test(scheme, host, method.asString(), clientClose, serverClose, contentLength, true, latch, failures);
     }
 
-    private void test(String scheme, String host, String method, boolean clientClose, boolean serverClose, int contentLength, final boolean checkContentLength, final CountDownLatch latch, final List<String> failures) throws InterruptedException
+    private void test(String scheme, String host, String method, boolean clientClose, boolean serverClose, int contentLength, final boolean checkContentLength, final CountDownLatch latch, final List<String> failures)
     {
         Request request = client.newRequest(host, connector.getLocalPort())
                 .scheme(scheme)
@@ -286,7 +300,19 @@
                 latch.countDown();
             }
         });
-        requestLatch.await(5, TimeUnit.SECONDS);
+        await(requestLatch, 5, TimeUnit.SECONDS);
+    }
+
+    private boolean await(CountDownLatch latch, long time, TimeUnit unit)
+    {
+        try
+        {
+            return latch.await(time, unit);
+        }
+        catch (InterruptedException x)
+        {
+            throw new RuntimeException(x);
+        }
     }
 
     private class LoadHandler extends AbstractHandler
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java
index 5fe1caf..3d72bb7 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java
@@ -58,7 +58,7 @@
             public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
             {
                 baseRequest.setHandled(true);
-                if (!URI.create(baseRequest.getUri().toString()).isAbsolute())
+                if (!URI.create(baseRequest.getHttpURI().toString()).isAbsolute())
                     response.setStatus(HttpServletResponse.SC_USE_PROXY);
                 else if (serverHost.equals(request.getServerName()))
                     response.setStatus(status);
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java
index 65b9df8..10052b9 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientRedirectTest.java
@@ -26,6 +26,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
index 55b2359..9ee92a0 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.client;
 
+import static java.nio.file.StandardOpenOption.CREATE;
+import static org.junit.Assert.fail;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -36,9 +39,12 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.AsyncContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
@@ -64,10 +70,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import static java.nio.file.StandardOpenOption.CREATE;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 public class HttpClientStreamTest extends AbstractHttpClientServerTest
 {
     public HttpClientStreamTest(SslContextFactory sslContextFactory)
@@ -89,7 +91,7 @@
                 output.write(kb);
         }
 
-        start(new EmptyServerHandler());
+        start(new RespondThenConsumeHandler());
 
         final AtomicLong requestTime = new AtomicLong();
         ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
@@ -186,7 +188,7 @@
         for (byte b : data)
         {
             int read = input.read();
-            assertTrue(read >= 0);
+            Assert.assertTrue(read >= 0);
             Assert.assertEquals(b & 0xFF, read);
         }
 
@@ -689,7 +691,7 @@
         try (DeferredContentProvider content = new DeferredContentProvider())
         {
             // Make the content immediately available.
-            content.offer(ByteBuffer.allocate(1024), new Callback.Adapter()
+            content.offer(ByteBuffer.allocate(1024), new Callback()
             {
                 @Override
                 public void succeeded()
@@ -974,7 +976,7 @@
         start(new EmptyServerHandler());
 
         final CountDownLatch failLatch = new CountDownLatch(2);
-        final Callback.Adapter callback = new Callback.Adapter()
+        final Callback callback = new Callback()
         {
             @Override
             public void failed(Throwable x)
@@ -1012,7 +1014,7 @@
 
         // Make sure that adding more content results in the callback to be failed.
         final CountDownLatch latch = new CountDownLatch(1);
-        content.offer(ByteBuffer.wrap(new byte[128]), new Callback.Adapter()
+        content.offer(ByteBuffer.wrap(new byte[128]), new Callback()
         {
             @Override
             public void failed(Throwable x)
@@ -1059,43 +1061,52 @@
     }
 
     @Test
-    public void testUploadWithWriteFailureClosesStream() throws Exception
+    public void testUploadWithConcurrentServerCloseClosesStream() throws Exception
     {
-        start(new EmptyServerHandler());
+        final CountDownLatch serverLatch = new CountDownLatch(1);
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+                serverLatch.countDown();
+            }
+        });
 
-        final AtomicInteger bytes = new AtomicInteger();
+        final AtomicBoolean commit = new AtomicBoolean();
         final CountDownLatch closeLatch = new CountDownLatch(1);
         InputStream stream = new InputStream()
         {
             @Override
             public int read() throws IOException
             {
-                int result = bytes.incrementAndGet();
-                switch (result)
+                // This method will be called few times before
+                // the request is committed.
+                // We wait for the request to commit, and we
+                // wait for the request to reach the server,
+                // to be sure that the server endPoint has
+                // been created, before stopping the connector.
+
+                if (commit.get())
                 {
-                    case 1:
+                    try
                     {
-                        break;
+                        Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
+                        connector.stop();
+                        return 0;
                     }
-                    case 2:
+                    catch (Throwable x)
                     {
-                        try
-                        {
-                            connector.stop();
-                        }
-                        catch (Exception x)
-                        {
-                            throw new IOException(x);
-                        }
-                        break;
-                    }
-                    default:
-                    {
-                        result = -1;
-                        break;
+                        throw new IOException(x);
                     }
                 }
-                return result;
+                else
+                {
+                    return connector.isStopped() ? -1 : 0;
+                }
             }
 
             @Override
@@ -1111,6 +1122,14 @@
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
                 .content(provider)
+                .onRequestCommit(new Request.CommitListener()
+                {
+                    @Override
+                    public void onCommit(Request request)
+                    {
+                        commit.set(true);
+                    }
+                })
                 .send(new Response.CompleteListener()
                 {
                     @Override
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
index 87a0da0..2155bde 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java
@@ -22,14 +22,19 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpCookie;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
 import java.net.URI;
 import java.net.URLEncoder;
+import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
-import java.nio.channels.UnresolvedAddressException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -80,14 +85,13 @@
 import org.eclipse.jetty.util.FuturePromise;
 import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.SocketAddressResolver;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 
-import static java.nio.file.StandardOpenOption.CREATE;
-
 public class HttpClientTest extends AbstractHttpClientServerTest
 {
     @Rule
@@ -110,7 +114,7 @@
         Assert.assertEquals(200, response.getStatus());
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
         long start = System.nanoTime();
         HttpConnectionOverHTTP connection = null;
@@ -127,8 +131,8 @@
         client.stop();
 
         Assert.assertEquals(0, client.getDestinations().size());
-        Assert.assertEquals(0, connectionPool.getIdleConnections().size());
-        Assert.assertEquals(0, connectionPool.getActiveConnections().size());
+        Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
+        Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
         Assert.assertFalse(connection.getEndPoint().isOpen());
     }
 
@@ -329,7 +333,7 @@
             public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
             {
                 baseRequest.setHandled(true);
-                consume(request.getInputStream());
+                consume(request.getInputStream(), true);
                 String value = request.getParameter(paramName);
                 if (paramValue.equals(value))
                 {
@@ -360,22 +364,18 @@
             public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
             {
                 baseRequest.setHandled(true);
-                consume(request.getInputStream());
+                consume(request.getInputStream(), true);
             }
         });
 
         final byte[] content = {0, 1, 2, 3};
         ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort())
-                .onRequestContent(new Request.ContentListener()
+                .onRequestContent((request, buffer) ->
                 {
-                    @Override
-                    public void onContent(Request request, ByteBuffer buffer)
-                    {
-                        byte[] bytes = new byte[buffer.remaining()];
-                        buffer.get(bytes);
-                        if (!Arrays.equals(content, bytes))
-                            request.abort(new Exception());
-                    }
+                    byte[] bytes = new byte[buffer.remaining()];
+                    buffer.get(bytes);
+                    if (!Arrays.equals(content, bytes))
+                        request.abort(new Exception());
                 })
                 .content(new BytesContentProvider(content))
                 .timeout(5, TimeUnit.SECONDS)
@@ -394,22 +394,18 @@
             public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
             {
                 baseRequest.setHandled(true);
-                consume(request.getInputStream());
+                consume(request.getInputStream(), true);
             }
         });
 
         final AtomicInteger progress = new AtomicInteger();
         ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort())
-                .onRequestContent(new Request.ContentListener()
+                .onRequestContent((request, buffer) ->
                 {
-                    @Override
-                    public void onContent(Request request, ByteBuffer buffer)
-                    {
-                        byte[] bytes = new byte[buffer.remaining()];
-                        Assert.assertEquals(1, bytes.length);
-                        buffer.get(bytes);
-                        Assert.assertEquals(bytes[0], progress.getAndIncrement());
-                    }
+                    byte[] bytes = new byte[buffer.remaining()];
+                    Assert.assertEquals(1, bytes.length);
+                    buffer.get(bytes);
+                    Assert.assertEquals(bytes[0], progress.getAndIncrement());
                 })
                 .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4}))
                 .timeout(5, TimeUnit.SECONDS)
@@ -431,19 +427,15 @@
         final CountDownLatch successLatch = new CountDownLatch(2);
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .onRequestBegin(new Request.BeginListener()
+                .onRequestBegin(request ->
                 {
-                    @Override
-                    public void onBegin(Request request)
+                    try
                     {
-                        try
-                        {
-                            latch.await();
-                        }
-                        catch (InterruptedException x)
-                        {
-                            x.printStackTrace();
-                        }
+                        latch.await();
+                    }
+                    catch (InterruptedException x)
+                    {
+                        x.printStackTrace();
                     }
                 })
                 .send(new Response.Listener.Adapter()
@@ -458,14 +450,7 @@
 
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .onRequestQueued(new Request.QueuedListener()
-                {
-                    @Override
-                    public void onQueued(Request request)
-                    {
-                        latch.countDown();
-                    }
-                })
+                .onRequestQueued(request -> latch.countDown())
                 .send(new Response.Listener.Adapter()
                 {
                     @Override
@@ -482,74 +467,50 @@
     @Test
     public void test_QueuedRequest_IsSent_WhenPreviousRequestClosedConnection() throws Exception
     {
-        start(new EmptyServerHandler());
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                if (target.endsWith("/one"))
+                    baseRequest.getHttpChannel().getEndPoint().close();
+                else
+                    baseRequest.setHandled(true);
+            }
+        });
 
         client.setMaxConnectionsPerDestination(1);
-        final long idleTimeout = 1000;
-        client.setIdleTimeout(idleTimeout);
 
-        final CountDownLatch latch = new CountDownLatch(3);
+        final CountDownLatch latch = new CountDownLatch(2);
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
                 .path("/one")
-                .listener(new Request.Listener.Adapter()
-                {
-                    @Override
-                    public void onBegin(Request request)
-                    {
-                        try
-                        {
-                            TimeUnit.MILLISECONDS.sleep(2 * idleTimeout);
-                        }
-                        catch (InterruptedException x)
-                        {
-                            x.printStackTrace();
-                        }
-                    }
-
-                    @Override
-                    public void onFailure(Request request, Throwable failure)
-                    {
-                        latch.countDown();
-                    }
-                })
-                .onResponseFailure(new Response.FailureListener()
-                {
-                    @Override
-                    public void onFailure(Response response, Throwable failure)
-                    {
-                        latch.countDown();
-                    }
-                })
+                .onResponseFailure((response, failure) -> latch.countDown())
                 .send(null);
 
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
                 .path("/two")
-                .onResponseSuccess(new Response.SuccessListener()
+                .onResponseSuccess(response ->
                 {
-                    @Override
-                    public void onSuccess(Response response)
-                    {
-                        Assert.assertEquals(200, response.getStatus());
-                        latch.countDown();
-                    }
+                    Assert.assertEquals(200, response.getStatus());
+                    latch.countDown();
                 })
                 .send(null);
 
-        Assert.assertTrue(latch.await(5 * idleTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
     }
 
     @Test
     public void test_ExchangeIsComplete_OnlyWhenBothRequestAndResponseAreComplete() throws Exception
     {
-        start(new EmptyServerHandler());
+        start(new RespondThenConsumeHandler());
 
         // Prepare a big file to upload
-        Path targetTestsDir = testdir.getEmptyDir().toPath();
+        Path targetTestsDir = testdir.getEmptyPathDir();
         Files.createDirectories(targetTestsDir);
         Path file = Paths.get(targetTestsDir.toString(), "http_client_conversation.big");
-        try (OutputStream output = Files.newOutputStream(file, CREATE))
+        try (OutputStream output = Files.newOutputStream(file, StandardOpenOption.CREATE))
         {
             byte[] kb = new byte[1024];
             for (int i = 0; i < 10 * 1024; ++i)
@@ -563,14 +524,10 @@
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
                 .file(file)
-                .onRequestSuccess(new Request.SuccessListener()
+                .onRequestSuccess(request ->
                 {
-                    @Override
-                    public void onSuccess(Request request)
-                    {
-                        requestTime.set(System.nanoTime());
-                        latch.countDown();
-                    }
+                    requestTime.set(System.nanoTime());
+                    latch.countDown();
                 })
                 .send(new Response.Listener.Adapter()
                 {
@@ -673,14 +630,10 @@
         final int port = connector.getLocalPort();
         client.newRequest(host, port)
                 .scheme(scheme)
-                .onRequestBegin(new Request.BeginListener()
+                .onRequestBegin(request ->
                 {
-                    @Override
-                    public void onBegin(Request request)
-                    {
-                        HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-                        destination.getConnectionPool().getActiveConnections().peek().close();
-                    }
+                    HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
+                    destination.getConnectionPool().getActiveConnections().peek().close();
                 })
                 .send(new Response.Listener.Adapter()
                 {
@@ -772,14 +725,7 @@
 
         ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .onResponseHeader(new Response.HeaderListener()
-                {
-                    @Override
-                    public boolean onHeader(Response response, HttpField field)
-                    {
-                        return !field.getName().equals(headerName);
-                    }
-                })
+                .onResponseHeader((response1, field) -> !field.getName().equals(headerName))
                 .timeout(5, TimeUnit.SECONDS)
                 .send();
 
@@ -857,26 +803,71 @@
     }
 
     @Test
-    public void testConnectThrowsUnresolvedAddressException() throws Exception
+    public void testConnectThrowsUnknownHostException() throws Exception
     {
         start(new EmptyServerHandler());
 
         final CountDownLatch latch = new CountDownLatch(1);
         client.newRequest("idontexist", 80)
-                .send(new Response.CompleteListener()
+                .send(result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
-                    {
-                        Assert.assertTrue(result.isFailed());
-                        Assert.assertTrue(result.getFailure() instanceof UnresolvedAddressException);
-                        latch.countDown();
-                    }
+                    Assert.assertTrue(result.isFailed());
+                    Throwable failure = result.getFailure();
+                    Assert.assertTrue(failure instanceof UnknownHostException);
+                    latch.countDown();
                 });
         Assert.assertTrue(latch.await(10, TimeUnit.SECONDS));
     }
 
     @Test
+    public void testConnectHostWithMultipleAddresses() throws Exception
+    {
+        String host = "google.com";
+        try
+        {
+            // Likely that the DNS for google.com returns multiple addresses.
+            Assume.assumeTrue(InetAddress.getAllByName(host).length > 1);
+        }
+        catch (Throwable x)
+        {
+            Assume.assumeNoException(x);
+        }
+
+        startClient();
+        client.setFollowRedirects(false); // Avoid redirects from 80 to 443.
+        client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout())
+        {
+            @Override
+            public void resolve(String host, int port, Promise<List<InetSocketAddress>> promise)
+            {
+                super.resolve(host, port, new Promise<List<InetSocketAddress>>()
+                {
+                    @Override
+                    public void succeeded(List<InetSocketAddress> result)
+                    {
+                        // Add as first address an invalid address so that we test
+                        // that the connect operation iterates over the addresses.
+                        result.add(0, new InetSocketAddress("idontexist", 80));
+                        promise.succeeded(result);
+                    }
+
+                    @Override
+                    public void failed(Throwable x)
+                    {
+                        promise.failed(x);
+                    }
+                });
+            }
+        });
+
+        // Response code may be 200 or 302;
+        // if no exceptions the test passes.
+        client.newRequest(host, 80)
+                .header(HttpHeader.CONNECTION, "close")
+                .send();
+    }
+
+    @Test
     public void testCustomUserAgent() throws Exception
     {
         final String userAgent = "Test/1.0";
@@ -1122,7 +1113,7 @@
             }
         });
 
-        final Exchanger<Response> ex = new Exchanger<Response>();
+        final Exchanger<Response> ex = new Exchanger<>();
         BufferingResponseListener listener = new BufferingResponseListener()
         {
             @Override
@@ -1273,14 +1264,10 @@
         final CountDownLatch completeLatch = new CountDownLatch(1);
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .send(new Response.CompleteListener()
+                .send(result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
-                    {
-                        if (result.isFailed())
-                            completeLatch.countDown();
-                    }
+                    if (result.isFailed())
+                        completeLatch.countDown();
                 });
 
         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
@@ -1369,7 +1356,7 @@
                 int count = requests.incrementAndGet();
                 if (count == maxRetries)
                     baseRequest.setHandled(true);
-                consume(request.getInputStream());
+                consume(request.getInputStream(), true);
             }
         });
 
@@ -1469,33 +1456,87 @@
         final CountDownLatch latch = new CountDownLatch(2);
         client.newRequest("localhost", connector.getLocalPort())
                 .scheme(scheme)
-                .onRequestBegin(new Request.BeginListener()
+                .onRequestBegin(request ->
                 {
-                    @Override
-                    public void onBegin(Request request)
-                    {
-                        Assert.assertTrue(open.get());
-                        latch.countDown();
-                    }
+                    Assert.assertTrue(open.get());
+                    latch.countDown();
                 })
-                .send(new Response.CompleteListener()
+                .send(result ->
                 {
-                    @Override
-                    public void onComplete(Result result)
-                    {
-                        if (result.isSucceeded())
-                            latch.countDown();
-                    }
+                    if (result.isSucceeded())
+                        latch.countDown();
                 });
 
         Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
     }
 
-    private void consume(InputStream input) throws IOException
+    @Test
+    public void testCONNECTWithHTTP10() throws Exception
     {
+        try (ServerSocket server = new ServerSocket(0))
+        {
+            startClient();
+
+            String host = "localhost";
+            int port = server.getLocalPort();
+
+            Request request = client.newRequest(host, port)
+                    .method(HttpMethod.CONNECT)
+                    .version(HttpVersion.HTTP_1_0);
+            FuturePromise<Connection> promise = new FuturePromise<>();
+            client.getDestination("http", host, port).newConnection(promise);
+            Connection connection = promise.get(5, TimeUnit.SECONDS);
+            FutureResponseListener listener = new FutureResponseListener(request);
+            connection.send(request, listener);
+
+            try (Socket socket = server.accept())
+            {
+                InputStream input = socket.getInputStream();
+                consume(input, false);
+
+                // HTTP/1.0 response, the client must not close the connection.
+                String httpResponse = "" +
+                        "HTTP/1.0 200 OK\r\n" +
+                        "\r\n";
+                OutputStream output = socket.getOutputStream();
+                output.write(httpResponse.getBytes(StandardCharsets.UTF_8));
+                output.flush();
+
+                ContentResponse response = listener.get(5, TimeUnit.SECONDS);
+                Assert.assertEquals(200, response.getStatus());
+
+                // Test that I can send another request on the same connection.
+                request = client.newRequest(host, port);
+                listener = new FutureResponseListener(request);
+                connection.send(request, listener);
+
+                consume(input, false);
+
+                httpResponse = "" +
+                        "HTTP/1.1 200 OK\r\n" +
+                        "Content-Length: 0\r\n" +
+                        "\r\n";
+                output.write(httpResponse.getBytes(StandardCharsets.UTF_8));
+                output.flush();
+
+                listener.get(5, TimeUnit.SECONDS);
+            }
+        }
+    }
+
+    private void consume(InputStream input, boolean eof) throws IOException
+    {
+        int crlfs = 0;
         while (true)
         {
-            if (input.read() < 0)
+            int read = input.read();
+            if (read == '\r' || read == '\n')
+                ++crlfs;
+            else
+                crlfs = 0;
+            if (!eof && crlfs == 4)
+                break;
+            if (read < 0)
                 break;
         }
     }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java
index a067759..941532a 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientUploadDuringServerShutdown.java
@@ -272,7 +272,7 @@
         Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", connector.getLocalPort());
-        ConnectionPool pool = destination.getConnectionPool();
+        DuplexConnectionPool pool = destination.getConnectionPool();
         Assert.assertEquals(0, pool.getConnectionCount());
         Assert.assertEquals(0, pool.getIdleConnections().size());
         Assert.assertEquals(0, pool.getActiveConnections().size());
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
index 7486b45..2d1c25f 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java
@@ -21,9 +21,10 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
-import java.util.concurrent.BlockingQueue;
+import java.util.Queue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -68,12 +69,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         final CountDownLatch headersLatch = new CountDownLatch(1);
@@ -129,12 +130,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         final CountDownLatch beginLatch = new CountDownLatch(1);
@@ -180,12 +181,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         final CountDownLatch successLatch = new CountDownLatch(3);
@@ -240,12 +241,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         final long delay = 1000;
@@ -313,12 +314,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         server.stop();
@@ -366,12 +367,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         final CountDownLatch latch = new CountDownLatch(1);
@@ -416,12 +417,12 @@
             String host = "localhost";
             int port = connector.getLocalPort();
             HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-            ConnectionPool connectionPool = destination.getConnectionPool();
+            DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-            final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+            final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
             Assert.assertEquals(0, idleConnections.size());
 
-            final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+            final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
             Assert.assertEquals(0, activeConnections.size());
 
             Log.getLogger(HttpConnection.class).info("Expecting java.lang.IllegalStateException: HttpParser{s=CLOSED,...");
@@ -448,7 +449,7 @@
 
             Assert.assertEquals(0, idleConnections.size());
             Assert.assertEquals(0, activeConnections.size());
-            
+
             server.stop();
         }
         finally
@@ -466,12 +467,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         ContentResponse response = client.newRequest(host, port)
@@ -498,12 +499,12 @@
         String host = "localhost";
         int port = connector.getLocalPort();
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, host, port);
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
 
-        final BlockingQueue<Connection> idleConnections = connectionPool.getIdleConnections();
+        final Queue<Connection> idleConnections = connectionPool.getIdleConnections();
         Assert.assertEquals(0, idleConnections.size());
 
-        final BlockingQueue<Connection> activeConnections = connectionPool.getActiveConnections();
+        final Queue<Connection> activeConnections = connectionPool.getActiveConnections();
         Assert.assertEquals(0, activeConnections.size());
 
         client.setStrictEventOrdering(false);
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java
index 29f15c7..9be9b08 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpCookieTest.java
@@ -23,6 +23,7 @@
 import java.net.URI;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java
index 19d8f8f..ef1f390 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpRequestAbortTest.java
@@ -88,7 +88,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -135,7 +135,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -182,7 +182,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -225,7 +225,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -289,7 +289,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -344,7 +344,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -454,7 +454,7 @@
         }
 
         HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination(scheme, "localhost", connector.getLocalPort());
-        ConnectionPool connectionPool = destination.getConnectionPool();
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
         Assert.assertEquals(0, connectionPool.getConnectionCount());
         Assert.assertEquals(0, connectionPool.getActiveConnections().size());
         Assert.assertEquals(0, connectionPool.getIdleConnections().size());
@@ -527,7 +527,7 @@
         final AtomicBoolean aborted = new AtomicBoolean();
         final CountDownLatch latch = new CountDownLatch(1);
         client.getProtocolHandlers().clear();
-        client.getProtocolHandlers().add(new RedirectProtocolHandler(client)
+        client.getProtocolHandlers().put(new RedirectProtocolHandler(client)
         {
             @Override
             public void onComplete(Result result)
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java
index 9a615c7..d1b4dfa 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseAbortTest.java
@@ -24,6 +24,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java
index 534920d..b06ae5d 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpResponseConcurrentAbortTest.java
@@ -24,6 +24,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -42,7 +43,8 @@
     private final CountDownLatch callbackLatch = new CountDownLatch(1);
     private final CountDownLatch failureLatch = new CountDownLatch(1);
     private final CountDownLatch completeLatch = new CountDownLatch(1);
-    private final AtomicBoolean success = new AtomicBoolean();
+    private final AtomicBoolean failureWasAsync = new AtomicBoolean();
+    private final AtomicBoolean completeWasSync = new AtomicBoolean();
 
     public HttpResponseConcurrentAbortTest(SslContextFactory sslContextFactory)
     {
@@ -66,8 +68,9 @@
                 })
                 .send(new TestResponseListener());
         Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(completeLatch.await(6, TimeUnit.SECONDS));
-        Assert.assertTrue(success.get());
+        Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(failureWasAsync.get());
+        Assert.assertTrue(completeWasSync.get());
     }
 
     @Test
@@ -89,7 +92,8 @@
                 .send(new TestResponseListener());
         Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(success.get());
+        Assert.assertTrue(failureWasAsync.get());
+        Assert.assertTrue(completeWasSync.get());
     }
 
     @Test
@@ -110,7 +114,8 @@
                 .send(new TestResponseListener());
         Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(success.get());
+        Assert.assertTrue(failureWasAsync.get());
+        Assert.assertTrue(completeWasSync.get());
     }
 
     @Test
@@ -141,7 +146,8 @@
                 .send(new TestResponseListener());
         Assert.assertTrue(callbackLatch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(success.get());
+        Assert.assertTrue(failureWasAsync.get());
+        Assert.assertTrue(completeWasSync.get());
     }
 
     private void abort(final Response response)
@@ -157,14 +163,15 @@
 
         try
         {
-            // The failure callback must be executed asynchronously.
-            boolean latched = failureLatch.await(4, TimeUnit.SECONDS);
-            success.set(latched);
+            // The failure callback is executed asynchronously, but
+            // here we are within the context of another response
+            // callback, which should detect that a failure happened
+            // and therefore this thread should complete the response.
+            failureWasAsync.set(failureLatch.await(2, TimeUnit.SECONDS));
 
-            // The complete callback must not be executed
-            // until we return from this callback.
-            latched = completeLatch.await(1, TimeUnit.SECONDS);
-            success.set(!latched);
+            // The complete callback must be executed by this thread,
+            // after we return from this response callback.
+            completeWasSync.set(!completeLatch.await(1, TimeUnit.SECONDS));
 
             callbackLatch.countDown();
         }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/RespondThenConsumeHandler.java b/jetty-client/src/test/java/org/eclipse/jetty/client/RespondThenConsumeHandler.java
new file mode 100644
index 0000000..477760f
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/RespondThenConsumeHandler.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+class RespondThenConsumeHandler extends AbstractHandler
+{
+    @Override
+    public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response)
+            throws IOException, ServletException
+    {
+        baseRequest.setHandled(true);
+        response.setContentLength(0);
+        response.setStatus(200);
+        response.flushBuffer();
+        
+        InputStream in = request.getInputStream();
+        while(in.read()>=0);
+    }
+    
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java
new file mode 100644
index 0000000..639984d
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java
@@ -0,0 +1,176 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
+import org.eclipse.jetty.client.util.FutureResponseListener;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ServerConnectionCloseTest
+{
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+    private HttpClient client;
+
+    private void startClient() throws Exception
+    {
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
+        client = new HttpClient(new HttpClientTransportOverHTTP(1), null);
+        client.setExecutor(clientThreads);
+        client.start();
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (client != null)
+            client.stop();
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithoutContent() throws Exception
+    {
+        testServerSendsConnectionClose(true, false, "");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithContent() throws Exception
+    {
+        testServerSendsConnectionClose(true, false, "data");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithChunkedContent() throws Exception
+    {
+        testServerSendsConnectionClose(true, true, "data");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithoutContentButDoesNotClose() throws Exception
+    {
+        testServerSendsConnectionClose(false, false, "");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithContentButDoesNotClose() throws Exception
+    {
+        testServerSendsConnectionClose(false, false, "data");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithChunkedContentButDoesNotClose() throws Exception
+    {
+        testServerSendsConnectionClose(false, true, "data");
+    }
+
+    private void testServerSendsConnectionClose(boolean shutdownOutput, boolean chunked, String content) throws Exception
+    {
+        ServerSocket server = new ServerSocket(0);
+        int port = server.getLocalPort();
+
+        startClient();
+
+        Request request = client.newRequest("localhost", port).path("/ctx/path");
+        FutureResponseListener listener = new FutureResponseListener(request);
+        request.send(listener);
+
+        Socket socket = server.accept();
+
+        InputStream input = socket.getInputStream();
+        consumeRequest(input);
+
+        OutputStream output = socket.getOutputStream();
+        String serverResponse = "" +
+                "HTTP/1.1 200 OK\r\n" +
+                "Connection: close\r\n";
+        if (chunked)
+        {
+            serverResponse += "" +
+                    "Transfer-Encoding: chunked\r\n" +
+                    "\r\n";
+                    for (int i = 0; i < 2; ++i)
+                    {
+                        serverResponse +=
+                                Integer.toHexString(content.length()) + "\r\n" +
+                                content + "\r\n";
+                    }
+            serverResponse += "" +
+                    "0\r\n" +
+                    "\r\n";
+        }
+        else
+        {
+            serverResponse += "Content-Length: " + content.length() + "\r\n";
+            serverResponse += "\r\n";
+            serverResponse += content;
+        }
+
+        output.write(serverResponse.getBytes("UTF-8"));
+        output.flush();
+        if (shutdownOutput)
+            socket.shutdownOutput();
+
+        ContentResponse response = listener.get(5, TimeUnit.SECONDS);
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+        // Give some time to process the connection.
+        Thread.sleep(1000);
+
+        // Connection should have been removed from pool.
+        HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
+        Assert.assertEquals(0, connectionPool.getConnectionCount());
+        Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
+        Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
+    }
+
+    private boolean consumeRequest(InputStream input) throws IOException
+    {
+        int crlfs = 0;
+        while (true)
+        {
+            int read = input.read();
+            if (read < 0)
+                return true;
+            if (read == '\r' || read == '\n')
+                ++crlfs;
+            else
+                crlfs = 0;
+            if (crlfs == 4)
+                return false;
+        }
+    }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java
new file mode 100644
index 0000000..7000eb3
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java
@@ -0,0 +1,213 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
+import org.eclipse.jetty.client.util.FutureResponseListener;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class TLSServerConnectionCloseTest
+{
+    @Parameterized.Parameters(name = "CloseMode: {0}")
+    public static Object[] parameters()
+    {
+        return new Object[]{CloseMode.NONE, CloseMode.CLOSE, CloseMode.ABRUPT};
+    }
+
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+    private HttpClient client;
+    private final CloseMode closeMode;
+
+    public TLSServerConnectionCloseTest(CloseMode closeMode)
+    {
+        this.closeMode = closeMode;
+    }
+
+    private void startClient() throws Exception
+    {
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setEndpointIdentificationAlgorithm("");
+        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
+        sslContextFactory.setTrustStorePassword("storepwd");
+
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
+        client = new HttpClient(new HttpClientTransportOverHTTP(1), sslContextFactory);
+        client.setExecutor(clientThreads);
+        client.start();
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (client != null)
+            client.stop();
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithoutContent() throws Exception
+    {
+        testServerSendsConnectionClose(false, "");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithContent() throws Exception
+    {
+        testServerSendsConnectionClose(false, "data");
+    }
+
+    @Test
+    public void testServerSendsConnectionCloseWithChunkedContent() throws Exception
+    {
+        testServerSendsConnectionClose(true, "data");
+    }
+
+    private void testServerSendsConnectionClose(boolean chunked, String content) throws Exception
+    {
+        ServerSocket server = new ServerSocket(0);
+        int port = server.getLocalPort();
+
+        startClient();
+
+        Request request = client.newRequest("localhost", port).scheme("https").path("/ctx/path");
+        FutureResponseListener listener = new FutureResponseListener(request);
+        request.send(listener);
+
+        Socket socket = server.accept();
+        SSLContext sslContext = client.getSslContextFactory().getSslContext();
+        SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, "localhost", port, false);
+        sslSocket.setUseClientMode(false);
+        sslSocket.startHandshake();
+
+        InputStream input = sslSocket.getInputStream();
+        consumeRequest(input);
+
+        OutputStream output = sslSocket.getOutputStream();
+        String serverResponse = "" +
+                "HTTP/1.1 200 OK\r\n" +
+                "Connection: close\r\n";
+        if (chunked)
+        {
+            serverResponse += "" +
+                    "Transfer-Encoding: chunked\r\n" +
+                    "\r\n";
+                    for (int i = 0; i < 2; ++i)
+                    {
+                        serverResponse +=
+                                Integer.toHexString(content.length()) + "\r\n" +
+                                content + "\r\n";
+                    }
+            serverResponse += "" +
+                    "0\r\n" +
+                    "\r\n";
+        }
+        else
+        {
+            serverResponse += "Content-Length: " + content.length() + "\r\n";
+            serverResponse += "\r\n";
+            serverResponse += content;
+        }
+
+        output.write(serverResponse.getBytes("UTF-8"));
+        output.flush();
+
+        switch (closeMode)
+        {
+            case NONE:
+            {
+                break;
+            }
+            case CLOSE:
+            {
+                sslSocket.close();
+                break;
+            }
+            case ABRUPT:
+            {
+                socket.shutdownOutput();
+                break;
+            }
+            default:
+            {
+                throw new IllegalStateException();
+            }
+        }
+
+        ContentResponse response = listener.get(5, TimeUnit.SECONDS);
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+        // Give some time to process the connection.
+        Thread.sleep(1000);
+
+        // Connection should have been removed from pool.
+        HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
+        DuplexConnectionPool connectionPool = destination.getConnectionPool();
+        Assert.assertEquals(0, connectionPool.getConnectionCount());
+        Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
+        Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
+    }
+
+    private boolean consumeRequest(InputStream input) throws IOException
+    {
+        int crlfs = 0;
+        while (true)
+        {
+            int read = input.read();
+            if (read < 0)
+                return true;
+            if (read == '\r' || read == '\n')
+                ++crlfs;
+            else
+                crlfs = 0;
+            if (crlfs == 4)
+                return false;
+        }
+    }
+
+    private enum CloseMode
+    {
+        NONE, CLOSE, ABRUPT
+    }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java
new file mode 100644
index 0000000..5ed7fce
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ValidatingConnectionPoolTest.java
@@ -0,0 +1,204 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.client.http.HttpDestinationOverHTTP;
+import org.eclipse.jetty.client.util.FutureResponseListener;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ValidatingConnectionPoolTest extends AbstractHttpClientServerTest
+{
+    public ValidatingConnectionPoolTest(SslContextFactory sslContextFactory)
+    {
+        super(sslContextFactory);
+    }
+
+    @Override
+    protected void startClient() throws Exception
+    {
+        startClient(new ValidatingHttpClientTransportOverHTTP(1000));
+    }
+
+    @Test
+    public void testRequestAfterValidation() throws Exception
+    {
+        start(new EmptyServerHandler());
+
+        client.setMaxConnectionsPerDestination(1);
+
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .send();
+        Assert.assertEquals(200, response.getStatus());
+
+        // The second request should be sent after the validating timeout.
+        response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .send();
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testServerClosesConnectionAfterRedirectWithoutConnectionCloseHeader() throws Exception
+    {
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                if (target.endsWith("/redirect"))
+                {
+                    response.setStatus(HttpStatus.TEMPORARY_REDIRECT_307);
+                    response.setContentLength(0);
+                    response.setHeader(HttpHeader.LOCATION.asString(), scheme + "://localhost:" + connector.getLocalPort() + "/");
+                    response.flushBuffer();
+                    baseRequest.getHttpChannel().getEndPoint().shutdownOutput();
+                }
+                else
+                {
+                    response.setStatus(HttpStatus.OK_200);
+                    response.setContentLength(0);
+                    response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
+                }
+            }
+        });
+
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .path("/redirect")
+                .send();
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnectionsWithConnectionCloseHeader() throws Exception
+    {
+        testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                response.setStatus(HttpStatus.OK_200);
+                response.setContentLength(0);
+                response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
+            }
+        });
+    }
+
+    @Test
+    public void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnectionsWithoutConnectionCloseHeader() throws Exception
+    {
+        testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                response.setStatus(HttpStatus.OK_200);
+                response.setContentLength(0);
+                response.flushBuffer();
+                baseRequest.getHttpChannel().getEndPoint().shutdownOutput();
+            }
+        });
+    }
+
+    private void testServerClosesConnectionAfterResponseWithQueuedRequestWithMaxConnections(Handler handler) throws Exception
+    {
+        start(handler);
+        client.setMaxConnectionsPerDestination(1);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Request request1 = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .path("/one")
+                .onRequestBegin(r ->
+                {
+                    try
+                    {
+                        latch.await();
+                    }
+                    catch (InterruptedException x)
+                    {
+                        r.abort(x);
+                    }
+                });
+        FutureResponseListener listener1 = new FutureResponseListener(request1);
+        request1.send(listener1);
+
+        Request request2 = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .path("/two");
+        FutureResponseListener listener2 = new FutureResponseListener(request2);
+        request2.send(listener2);
+
+        // Now we have one request about to be sent, and one queued.
+
+        latch.countDown();
+
+        ContentResponse response1 = listener1.get(5, TimeUnit.SECONDS);
+        Assert.assertEquals(200, response1.getStatus());
+
+        ContentResponse response2 = listener2.get(5, TimeUnit.SECONDS);
+        Assert.assertEquals(200, response2.getStatus());
+    }
+
+    private static class ValidatingHttpClientTransportOverHTTP extends HttpClientTransportOverHTTP
+    {
+        private final long timeout;
+
+        public ValidatingHttpClientTransportOverHTTP(long timeout)
+        {
+            super(1);
+            this.timeout = timeout;
+        }
+
+        @Override
+        public HttpDestination newHttpDestination(Origin origin)
+        {
+            return new HttpDestinationOverHTTP(getHttpClient(), origin)
+            {
+                @Override
+                protected DuplexConnectionPool newConnectionPool(HttpClient client)
+                {
+                    return new ValidatingConnectionPool(this, client.getMaxConnectionsPerDestination(), this, client.getScheduler(), timeout);
+                }
+            };
+        }
+    }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java
index 1fdc747..4e9d095 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpDestinationOverHTTPTest.java
@@ -18,12 +18,13 @@
 
 package org.eclipse.jetty.client.http;
 
+import java.util.Queue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.client.AbstractHttpClientServerTest;
-import org.eclipse.jetty.client.ConnectionPool;
+import org.eclipse.jetty.client.DuplexConnectionPool;
 import org.eclipse.jetty.client.EmptyServerHandler;
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.Origin;
@@ -62,7 +63,7 @@
         if (connection == null)
         {
             // There are no queued requests, so the newly created connection will be idle
-            connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
+            connection = timedPoll(destination.getConnectionPool().getIdleConnections(), 5, TimeUnit.SECONDS);
         }
         Assert.assertNotNull(connection);
     }
@@ -96,9 +97,9 @@
         HttpDestinationOverHTTP destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", connector.getLocalPort()))
         {
             @Override
-            protected ConnectionPool newConnectionPool(HttpClient client)
+            protected DuplexConnectionPool newConnectionPool(HttpClient client)
             {
-                return new ConnectionPool(this, client.getMaxConnectionsPerDestination(), this)
+                return new DuplexConnectionPool(this, client.getMaxConnectionsPerDestination(), this)
                 {
                     @Override
                     protected void idleCreated(Connection connection)
@@ -132,10 +133,11 @@
 
         latch.countDown();
 
-        // There must be 2 idle connections
-        Connection connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
+        // There must be 2 idle connections.
+        Queue<Connection> idleConnections = destination.getConnectionPool().getIdleConnections();
+        Connection connection = timedPoll(idleConnections, 5, TimeUnit.SECONDS);
         Assert.assertNotNull(connection);
-        connection = destination.getConnectionPool().getIdleConnections().poll(5, TimeUnit.SECONDS);
+        connection = timedPoll(idleConnections, 5, TimeUnit.SECONDS);
         Assert.assertNotNull(connection);
     }
 
@@ -156,7 +158,7 @@
         // Acquire the connection to make it active
         Assert.assertSame(connection1, destination.acquire());
 
-        destination.process(connection1, false);
+        destination.process(connection1);
         destination.release(connection1);
 
         Connection connection2 = destination.acquire();
@@ -272,4 +274,17 @@
         destinationAfter = client.getDestination(scheme, host, port);
         Assert.assertNotSame(destinationBefore, destinationAfter);
     }
+
+    private Connection timedPoll(Queue<Connection> connections, long time, TimeUnit unit) throws InterruptedException
+    {
+        long start = System.nanoTime();
+        while (unit.toNanos(time) > System.nanoTime() - start)
+        {
+            Connection connection = connections.poll();
+            if (connection != null)
+                return connection;
+            TimeUnit.MILLISECONDS.sleep(5);
+        }
+        return connections.poll();
+    }
 }
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
index 49d97aa..051208d 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java
@@ -30,7 +30,6 @@
 import org.eclipse.jetty.client.HttpRequest;
 import org.eclipse.jetty.client.HttpResponseException;
 import org.eclipse.jetty.client.Origin;
-import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.util.FutureResponseListener;
 import org.eclipse.jetty.http.HttpFields;
@@ -62,7 +61,8 @@
         client.start();
         destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080));
         endPoint = new ByteArrayEndPoint();
-        connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
+        connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<>());
+        endPoint.setConnection(connection);
     }
 
     @After
@@ -86,7 +86,7 @@
     @Test
     public void test_Receive_NoResponseContent() throws Exception
     {
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-length: 0\r\n" +
                 "\r\n");
@@ -109,7 +109,7 @@
     public void test_Receive_ResponseContent() throws Exception
     {
         String content = "0123456789ABCDEF";
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-length: " + content.length() + "\r\n" +
                 "\r\n" +
@@ -136,7 +136,7 @@
     {
         String content1 = "0123456789";
         String content2 = "ABCDEF";
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-length: " + (content1.length() + content2.length()) + "\r\n" +
                 "\r\n" +
@@ -144,7 +144,7 @@
         HttpExchange exchange = newExchange();
         FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
         connection.getHttpChannel().receive();
-        endPoint.setInputEOF();
+        endPoint.addInputEOF();
         connection.getHttpChannel().receive();
 
         try
@@ -161,7 +161,7 @@
     @Test
     public void test_Receive_ResponseContent_IdleTimeout() throws Exception
     {
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-length: 1\r\n" +
                 "\r\n");
@@ -169,7 +169,7 @@
         FutureResponseListener listener = (FutureResponseListener)exchange.getResponseListeners().get(0);
         connection.getHttpChannel().receive();
         // Simulate an idle timeout
-        connection.onReadTimeout();
+        connection.onIdleExpired();
 
         try
         {
@@ -185,7 +185,7 @@
     @Test
     public void test_Receive_BadResponse() throws Exception
     {
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-length: A\r\n" +
                 "\r\n");
@@ -207,7 +207,7 @@
     @Test
     public void test_FillInterested_RacingWith_BufferRelease() throws Exception
     {
-        connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>())
+        connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<>())
         {
             @Override
             protected HttpChannelOverHTTP newHttpChannel()
@@ -226,7 +226,7 @@
                                 // before fillInterested() is called.
                                 Assert.assertNull(getResponseBuffer());
                                 // Fill the endpoint so receive is called again.
-                                endPoint.setInput("X");
+                                endPoint.addInput("X");
                                 super.fillInterested();
                             }
                         };
@@ -234,9 +234,10 @@
                 };
             }
         };
+        endPoint.setConnection(connection);
 
         // Partial response to trigger the call to fillInterested().
-        endPoint.setInput("" +
+        endPoint.addInput("" +
                 "HTTP/1.1 200 OK\r\n" +
                 "Content-Length: 1\r\n" +
                 "\r\n");
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
index 45b36d6..62699c9 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
@@ -56,8 +56,8 @@
 import org.eclipse.jetty.http.HttpParser;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
 import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConnection;
@@ -299,7 +299,7 @@
         closeClient(client);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testHandshakeWithResumedSessionThenClose() throws Exception
     {
         // First socket will establish the SSL session
@@ -381,7 +381,7 @@
         Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testHandshakeWithSplitBoundary() throws Exception
     {
         final SSLSocket client = newClient();
@@ -486,7 +486,7 @@
         }
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testClientHelloIncompleteThenReset() throws Exception
     {
         final SSLSocket client = newClient();
@@ -519,7 +519,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testClientHelloThenReset() throws Exception
     {
         final SSLSocket client = newClient();
@@ -550,7 +550,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testHandshakeThenReset() throws Exception
     {
         final SSLSocket client = newClient();
@@ -570,7 +570,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestIncompleteThenReset() throws Exception
     {
         final SSLSocket client = newClient();
@@ -612,7 +612,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestResponse() throws Exception
     {
         final SSLSocket client = newClient();
@@ -665,7 +665,7 @@
         closeClient(client);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testHandshakeAndRequestOneByteAtATime() throws Exception
     {
         final SSLSocket client = newClient();
@@ -752,11 +752,11 @@
 
         // Check that we did not spin
         TimeUnit.MILLISECONDS.sleep(1000);
-        Assert.assertThat(sslFills.get(), Matchers.lessThan(1000));
+        Assert.assertThat(sslFills.get(), Matchers.lessThan(2000));
         Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
         // An average of 958 httpParses is seen in standard Oracle JDK's
         // An average of 1183 httpParses is seen in OpenJDK JVMs.
-        Assert.assertThat(httpParses.get(), Matchers.lessThan(500));
+        Assert.assertThat(httpParses.get(), Matchers.lessThan(2000));
 
         client.close();
 
@@ -782,7 +782,7 @@
         }
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithCloseAlertAndShutdown() throws Exception
     {
         // See next test on why we only run in Linux
@@ -850,7 +850,7 @@
         Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithCloseAlert() throws Exception
     {
         // Currently we are ignoring this test on anything other then linux
@@ -930,7 +930,7 @@
         proxy.flushToServer(record);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithRawClose() throws Exception
     {
         final SSLSocket client = newClient();
@@ -989,7 +989,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithImmediateRawClose() throws Exception
     {
         final SSLSocket client = newClient();
@@ -1046,7 +1046,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithBigContentWriteBlockedThenReset() throws Exception
     {
         // Don't run on Windows (buggy JVM)
@@ -1107,7 +1107,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithBigContentReadBlockedThenReset() throws Exception
     {
         // Don't run on Windows (buggy JVM)
@@ -1163,7 +1163,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithCloseAlertWithSplitBoundary() throws Exception
     {
         if (!OS.IS_LINUX)
@@ -1251,7 +1251,7 @@
         Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithContentWithSplitBoundary() throws Exception
     {
         final SSLSocket client = newClient();
@@ -1314,7 +1314,7 @@
         closeClient(client);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithBigContentWithSplitBoundary() throws Exception
     {
         final SSLSocket client = newClient();
@@ -1362,8 +1362,8 @@
 
         // Check that we did not spin
         TimeUnit.MILLISECONDS.sleep(500);
-        Assert.assertThat(sslFills.get(), Matchers.lessThan(50));
-        Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
+        Assert.assertThat(sslFills.get(), Matchers.lessThan(100));
+        Assert.assertThat(sslFlushes.get(), Matchers.lessThan(50));
         Assert.assertThat(httpParses.get(), Matchers.lessThan(100));
 
         Assert.assertNull(request.get(5, TimeUnit.SECONDS));
@@ -1384,8 +1384,8 @@
 
         // Check that we did not spin
         TimeUnit.MILLISECONDS.sleep(500);
-        Assert.assertThat(sslFills.get(), Matchers.lessThan(50));
-        Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
+        Assert.assertThat(sslFills.get(), Matchers.lessThan(100));
+        Assert.assertThat(sslFlushes.get(), Matchers.lessThan(50));
         Assert.assertThat(httpParses.get(), Matchers.lessThan(100));
 
         closeClient(client);
@@ -1485,7 +1485,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestWithBigContentWithRenegotiationInMiddleOfContent() throws Exception
     {
         assumeJavaVersionSupportsTLSRenegotiations();
@@ -1781,7 +1781,7 @@
         closeClient(client);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testServerShutdownOutputClientDoesNotCloseServerCloses() throws Exception
     {
         final SSLSocket client = newClient();
@@ -1835,7 +1835,7 @@
         Assert.assertFalse(serverEndPoint.get().isOpen());
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testPlainText() throws Exception
     {
         final SSLSocket client = newClient();
@@ -1866,7 +1866,7 @@
         client.close();
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testRequestConcurrentWithIdleExpiration() throws Exception
     {
         final SSLSocket client = newClient();
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java
new file mode 100644
index 0000000..03f051c
--- /dev/null
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartContentProviderTest.java
@@ -0,0 +1,448 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.client.util;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
+
+import org.eclipse.jetty.client.AbstractHttpClientServerTest;
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MultiPartContentProviderTest extends AbstractHttpClientServerTest
+{
+    public MultiPartContentProviderTest(SslContextFactory sslContextFactory)
+    {
+        super(sslContextFactory);
+    }
+
+    @Test
+    public void testEmptyMultiPart() throws Exception
+    {
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(0, parts.size());
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testSimpleField() throws Exception
+    {
+        String name = "field";
+        String value = "value";
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(1, parts.size());
+                Part part = parts.iterator().next();
+                Assert.assertEquals(name, part.getName());
+                Assert.assertEquals(value, IO.toString(part.getInputStream()));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        multiPart.addFieldPart(name, new StringContentProvider(value), null);
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testFieldWithOverridenContentType() throws Exception
+    {
+        String name = "field";
+        String value = "\u00e8";
+        Charset encoding = StandardCharsets.ISO_8859_1;
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(1, parts.size());
+                Part part = parts.iterator().next();
+                Assert.assertEquals(name, part.getName());
+                String contentType = part.getContentType();
+                Assert.assertNotNull(contentType);
+                int equal = contentType.lastIndexOf('=');
+                Charset charset = Charset.forName(contentType.substring(equal + 1));
+                Assert.assertEquals(encoding, charset);
+                Assert.assertEquals(value, IO.toString(part.getInputStream(), charset));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        HttpFields fields = new HttpFields();
+        fields.put(HttpHeader.CONTENT_TYPE, "text/plain;charset=" + encoding.name());
+        BytesContentProvider content = new BytesContentProvider(value.getBytes(encoding));
+        multiPart.addFieldPart(name, content, fields);
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testFieldDeferred() throws Exception
+    {
+        String name = "field";
+        byte[] data = "Hello, World".getBytes(StandardCharsets.US_ASCII);
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(1, parts.size());
+                Part part = parts.iterator().next();
+                Assert.assertEquals(name, part.getName());
+                Assert.assertEquals("text/plain", part.getContentType());
+                Assert.assertArrayEquals(data, IO.readBytes(part.getInputStream()));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        DeferredContentProvider content = new DeferredContentProvider();
+        multiPart.addFieldPart(name, content, null);
+        multiPart.close();
+        CountDownLatch responseLatch = new CountDownLatch(1);
+        client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send(result ->
+                {
+                    if (result.isSucceeded())
+                    {
+                        Assert.assertEquals(200, result.getResponse().getStatus());
+                        responseLatch.countDown();
+                    }
+                });
+
+        // Wait until the request has been sent.
+        Thread.sleep(1000);
+
+        // Provide the content.
+        content.offer(ByteBuffer.wrap(data));
+        content.close();
+
+        Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testFileFromInputStream() throws Exception
+    {
+        String name = "file";
+        String fileName = "upload.png";
+        String contentType = "image/png";
+        byte[] data = new byte[512];
+        new Random().nextBytes(data);
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(1, parts.size());
+                Part part = parts.iterator().next();
+                Assert.assertEquals(name, part.getName());
+                Assert.assertEquals(contentType, part.getContentType());
+                Assert.assertEquals(fileName, part.getSubmittedFileName());
+                Assert.assertEquals(data.length, part.getSize());
+                Assert.assertArrayEquals(data, IO.readBytes(part.getInputStream()));
+            }
+        });
+
+        CountDownLatch closeLatch = new CountDownLatch(1);
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        InputStreamContentProvider content = new InputStreamContentProvider(new ByteArrayInputStream(data)
+        {
+            @Override
+            public void close() throws IOException
+            {
+                super.close();
+                closeLatch.countDown();
+            }
+        });
+        HttpFields fields = new HttpFields();
+        fields.put(HttpHeader.CONTENT_TYPE, contentType);
+        multiPart.addFilePart(name, fileName, content, fields);
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertEquals(200, response.getStatus());
+    }
+
+    @Test
+    public void testFileFromPath() throws Exception
+    {
+        // Prepare a file to upload.
+        String data = "multipart_test_\u20ac";
+        Path tmpDir = MavenTestingUtils.getTargetTestingPath();
+        Path tmpPath = Files.createTempFile(tmpDir, "multipart_", ".txt");
+        Charset encoding = StandardCharsets.UTF_8;
+        try (BufferedWriter writer = Files.newBufferedWriter(tmpPath, encoding, StandardOpenOption.CREATE))
+        {
+            writer.write(data);
+        }
+
+        String name = "file";
+        String contentType = "text/plain; charset=" + encoding.name();
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Collection<Part> parts = request.getParts();
+                Assert.assertEquals(1, parts.size());
+                Part part = parts.iterator().next();
+                Assert.assertEquals(name, part.getName());
+                Assert.assertEquals(contentType, part.getContentType());
+                Assert.assertEquals(tmpPath.getFileName().toString(), part.getSubmittedFileName());
+                Assert.assertEquals(Files.size(tmpPath), part.getSize());
+                Assert.assertEquals(data, IO.toString(part.getInputStream(), encoding));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        ContentProvider content = new PathContentProvider(contentType, tmpPath);
+        multiPart.addFilePart(name, tmpPath.getFileName().toString(), content, null);
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+
+        Files.delete(tmpPath);
+    }
+
+    @Test
+    public void testFieldWithFile() throws Exception
+    {
+        // Prepare a file to upload.
+        byte[] data = new byte[1024];
+        new Random().nextBytes(data);
+        Path tmpDir = MavenTestingUtils.getTargetTestingPath();
+        Path tmpPath = Files.createTempFile(tmpDir, "multipart_", ".txt");
+        try (OutputStream output = Files.newOutputStream(tmpPath, StandardOpenOption.CREATE))
+        {
+            output.write(data);
+        }
+
+        String field = "field";
+        String value = "\u20ac";
+        String fileField = "file";
+        Charset encoding = StandardCharsets.UTF_8;
+        String contentType = "text/plain;charset=" + encoding.name();
+        String headerName = "foo";
+        String headerValue = "bar";
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                List<Part> parts = new ArrayList<>(request.getParts());
+                Assert.assertEquals(2, parts.size());
+                Part fieldPart = parts.get(0);
+                Part filePart = parts.get(1);
+                if (!field.equals(fieldPart.getName()))
+                {
+                    Part swap = filePart;
+                    filePart = fieldPart;
+                    fieldPart = swap;
+                }
+
+                Assert.assertEquals(field, fieldPart.getName());
+                Assert.assertEquals(contentType, fieldPart.getContentType());
+                Assert.assertEquals(value, IO.toString(fieldPart.getInputStream(), encoding));
+                Assert.assertEquals(headerValue, fieldPart.getHeader(headerName));
+
+                Assert.assertEquals(fileField, filePart.getName());
+                Assert.assertEquals("application/octet-stream", filePart.getContentType());
+                Assert.assertEquals(tmpPath.getFileName().toString(), filePart.getSubmittedFileName());
+                Assert.assertEquals(Files.size(tmpPath), filePart.getSize());
+                Assert.assertArrayEquals(data, IO.readBytes(filePart.getInputStream()));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        HttpFields fields = new HttpFields();
+        fields.put(headerName, headerValue);
+        multiPart.addFieldPart(field, new StringContentProvider(value, encoding), fields);
+        multiPart.addFilePart(fileField, tmpPath.getFileName().toString(), new PathContentProvider(tmpPath), null);
+        multiPart.close();
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+
+        Files.delete(tmpPath);
+    }
+
+    @Test
+    public void testFieldDeferredAndFileDeferred() throws Exception
+    {
+        String value = "text";
+        Charset encoding = StandardCharsets.US_ASCII;
+        byte[] fileData = new byte[1024];
+        new Random().nextBytes(fileData);
+        start(new AbstractMultiPartHandler()
+        {
+            @Override
+            protected void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                List<Part> parts = new ArrayList<>(request.getParts());
+                Assert.assertEquals(2, parts.size());
+                Part fieldPart = parts.get(0);
+                Part filePart = parts.get(1);
+                if (!"field".equals(fieldPart.getName()))
+                {
+                    Part swap = filePart;
+                    filePart = fieldPart;
+                    fieldPart = swap;
+                }
+
+                Assert.assertEquals(value, IO.toString(fieldPart.getInputStream(), encoding));
+
+                Assert.assertEquals("file", filePart.getName());
+                Assert.assertEquals("application/octet-stream", filePart.getContentType());
+                Assert.assertEquals("fileName", filePart.getSubmittedFileName());
+                Assert.assertArrayEquals(fileData, IO.readBytes(filePart.getInputStream()));
+            }
+        });
+
+        MultiPartContentProvider multiPart = new MultiPartContentProvider();
+        DeferredContentProvider fieldContent = new DeferredContentProvider();
+        multiPart.addFieldPart("field", fieldContent, null);
+        DeferredContentProvider fileContent = new DeferredContentProvider();
+        multiPart.addFilePart("file", "fileName", fileContent, null);
+        CountDownLatch responseLatch = new CountDownLatch(1);
+        client.newRequest("localhost", connector.getLocalPort())
+                .scheme(scheme)
+                .method(HttpMethod.POST)
+                .content(multiPart)
+                .send(result ->
+                {
+                    if (result.isSucceeded())
+                    {
+                        Assert.assertEquals(200, result.getResponse().getStatus());
+                        responseLatch.countDown();
+                    }
+                });
+
+        // Wait until the request has been sent.
+        Thread.sleep(1000);
+
+        // Provide the content, in reversed part order.
+        fileContent.offer(ByteBuffer.wrap(fileData));
+        fileContent.close();
+
+        Thread.sleep(1000);
+
+        fieldContent.offer(encoding.encode(value));
+        fieldContent.close();
+
+        multiPart.close();
+
+        Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    private static abstract class AbstractMultiPartHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            File tmpDir = MavenTestingUtils.getTargetTestingDir();
+            request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement(tmpDir.getAbsolutePath()));
+            handle(request, response);
+        }
+
+        protected abstract void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
+    }
+}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java
index 7188936..62781cc 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/util/TypedContentProviderTest.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml
index 5ad0c92..94659c5 100644
--- a/jetty-continuation/pom.xml
+++ b/jetty-continuation/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-continuation</artifactId>
@@ -15,35 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
index 34d9fc7..d312c72 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java
@@ -18,12 +18,15 @@
 
 package org.eclipse.jetty.continuation;
 
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
 
-/* ------------------------------------------------------------ */
 /**
  * Continuation.
- * 
+ * <p> 
  * A continuation is a mechanism by which a HTTP Request can be suspended and
  * restarted after a timeout or an asynchronous event has occurred.
  * <p>
@@ -48,7 +51,7 @@
  * <p>
  * There are two distinct style of operation of the continuation API.
  * </p>
- * <h3>Suspend/Resume Usage</h3> 
+ * <h1>Suspend/Resume Usage</h1> 
  * <p>The suspend/resume style is used when a servlet and/or
  * filter is used to generate the response after a asynchronous wait that is
  * terminated by an asynchronous handler.
@@ -83,7 +86,7 @@
  *     response.getOutputStream().write(process(results));
  *   }
  * </pre> 
- * <h3>Suspend/Complete Usage</h3> 
+ * <h1>Suspend/Complete Usage</h1> 
  * <p>
  * The suspend/complete style is used when an asynchronous handler is used to 
  * generate the response:
@@ -148,7 +151,7 @@
      * @param timeoutMs
      *            The time in milliseconds to wait before expiring this
      *            continuation after a call to {@link #suspend()} or {@link #suspend(ServletResponse)}.
-     *            A timeout of <=0 means the continuation will never expire.
+     *            A timeout of &lt;=0 means the continuation will never expire.
      */
     void setTimeout(long timeoutMs);
 
@@ -160,8 +163,8 @@
      * <p>
      * After this method has been called, the lifecycle of the request will be
      * extended beyond the return to the container from the
-     * {@link Servlet#service(ServletRequest, ServletResponse)} method and
-     * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
+     * {@link javax.servlet.Servlet#service(ServletRequest, ServletResponse)} method and
+     * {@link javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
      * calls. When a suspended request is returned to the container after
      * a dispatch, then the container will not commit the associated response
      * (unless an exception other than {@link ContinuationThrowable} is thrown).
@@ -196,8 +199,8 @@
      * <p>
      * After this method has been called, the lifecycle of the request will be
      * extended beyond the return to the container from the
-     * {@link Servlet#service(ServletRequest, ServletResponse)} method and
-     * {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
+     * {@link javax.servlet.Servlet#service(ServletRequest, ServletResponse)} method and
+     * {@link javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}
      * calls. When a suspended request is returned to the container after
      * a dispatch, then the container will not commit the associated response
      * (unless an exception other than {@link ContinuationThrowable} is thrown).
@@ -361,7 +364,7 @@
     /** 
      * Add a ContinuationListener.
      * 
-     * @param listener
+     * @param listener the listener
      */
     void addContinuationListener(ContinuationListener listener);
     
diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
index 75ff4bc..45caf07 100644
--- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
+++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationListener.java
@@ -20,13 +20,13 @@
 
 import java.util.EventListener;
 
+import javax.servlet.ServletRequestListener;
 
-/* ------------------------------------------------------------ */
-/** A Continuation Listener
+/** 
+ * A Continuation Listener
  * <p>
  * A ContinuationListener may be registered with a call to
  * {@link Continuation#addContinuationListener(ContinuationListener)}.
- *
  */
 public interface ContinuationListener extends EventListener
 {
@@ -36,7 +36,7 @@
      * any calls to {@link ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)}
      * The response may still be written to during the call.
      *
-     * @param continuation
+     * @param continuation the continuation
      */
     public void onComplete(Continuation continuation);
 
@@ -46,7 +46,7 @@
      * The response may be written to and the methods
      * {@link Continuation#resume()} or {@link Continuation#complete()}
      * may be called by a onTimeout implementation,
-     * @param continuation
+     * @param continuation the continuation
      */
     public void onTimeout(Continuation continuation);
 
diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml
index 09a66ee..9e898a4 100644
--- a/jetty-deploy/pom.xml
+++ b/jetty-deploy/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-deploy</artifactId>
@@ -15,53 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package>
-                <_nouses>true</_nouses>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
index 6dfc7e5..4544362 100644
--- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml
+++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Create the deployment manager                                   -->
@@ -39,7 +39,7 @@
         <Call id="webappprovider" name="addAppProvider">
           <Arg>
             <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
-              <Set name="monitoredDirName"><Property name="jetty.base" default="." />/<Property name="jetty.deploy.monitoredDirName" default="webapps"/></Set>
+              <Set name="monitoredDirName"><Property name="jetty.base" default="." />/<Property name="jetty.deploy.monitoredDir" deprecated="jetty.deploy.monitoredDirName" default="webapps"/></Set>
               <Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
               <Set name="scanInterval"><Property name="jetty.deploy.scanInterval" default="1"/></Set>
               <Set name="extractWars"><Property name="jetty.deploy.extractWars" default="true"/></Set>
diff --git a/jetty-deploy/src/main/config/modules/deploy.mod b/jetty-deploy/src/main/config/modules/deploy.mod
index f16b3f2..f567a20 100644
--- a/jetty-deploy/src/main/config/modules/deploy.mod
+++ b/jetty-deploy/src/main/config/modules/deploy.mod
@@ -15,7 +15,11 @@
 etc/jetty-deploy.xml
 
 [ini-template]
-## DeployManager configuration
-# Monitored Directory name (relative to jetty.base)
-# jetty.deploy.monitoredDirName=webapps
+# Monitored directory name (relative to $jetty.base)
+# jetty.deploy.monitoredDir=webapps
 
+# Monitored directory scan period (seconds)
+# jetty.deploy.scanInterval=1
+
+# Whether to extract *.war files
+# jetty.deploy.extractWars=true
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java
index e2bc13f..eb13792 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/App.java
@@ -34,6 +34,8 @@
     /**
      * Create an App with specified Origin ID and archivePath
      * 
+     * @param manager the deployment manager 
+     * @param provider the app provider
      * @param originId
      *            the origin ID (The ID that the {@link AppProvider} knows
      *            about)
@@ -50,6 +52,8 @@
     /**
      * Create an App with specified Origin ID and archivePath
      * 
+     * @param manager the deployment manager 
+     * @param provider the app provider
      * @param originId
      *            the origin ID (The ID that the {@link AppProvider} knows
      *            about)
@@ -92,7 +96,7 @@
      * @return the {@link ContextHandler} to use for the App when fully started.
      *         (Portions of which might be ignored when App is not yet 
      *         {@link AppLifeCycle#DEPLOYED} or {@link AppLifeCycle#STARTED})
-     * @throws Exception
+     * @throws Exception if unable to get the context handler
      */
     public ContextHandler getContextHandler() throws Exception
     {
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java
index 9398b08..e18278d 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppLifeCycle.java
@@ -32,11 +32,11 @@
 
 /**
  * The lifecycle of an App in the {@link DeploymentManager}.
- * 
+ * <p>
  * Setups a the default {@link Graph}, and manages the bindings to the life cycle via the {@link AppLifeCycle.Binding}
  * annotation.
  * <p>
- * <img src="doc-files/AppLifeCycle.png">
+ * <img alt="app lifecycle graph" src="doc-files/AppLifeCycle.png">
  */
 public class AppLifeCycle extends Graph
 {
@@ -144,6 +144,7 @@
     /**
      * Get all objects bound to a specific {@link Node}
      * 
+     * @param node the deployment graph node 
      * @return Set of Object(s) for specific lifecycle bindings. never null.
      */
     public Set<AppLifeCycle.Binding> getBindings(Node node)
@@ -154,6 +155,7 @@
     /**
      * Get all objects bound to a specific {@link Node}
      * 
+     * @param nodeName the node name 
      * @return Set of Object(s) for specific lifecycle bindings. never null.
      */
     public Set<AppLifeCycle.Binding> getBindings(String nodeName)
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
index f504bff..81c3919 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/AppProvider.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.deploy;
 
+import java.io.IOException;
+
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.component.LifeCycle;
 
@@ -29,7 +31,7 @@
     /**
      * Set the Deployment Manager
      * 
-     * @param deploymentManager
+     * @param deploymentManager the deployment manager
      * @throws IllegalStateException
      *             if the provider {@link #isRunning()}.
      */
@@ -39,8 +41,8 @@
     /** Create a ContextHandler for an App
      * @param app The App
      * @return A ContextHandler
-     * @throws IOException
-     * @throws Exception 
+     * @throws IOException if unable to create context
+     * @throws Exception if unable to create context
      */
     ContextHandler createContextHandler(App app) throws Exception;
 }
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java
index 27949df..8a3ab4d 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java
@@ -51,14 +51,14 @@
  * <p>
  * Responsibilities:
  * <p>
- * <img src="doc-files/DeploymentManager_Roles.png">
+ * <img alt="deployment manager roles graph" src="doc-files/DeploymentManager_Roles.png">
  * <ol>
  * <li>Tracking Apps and their LifeCycle Location</li>
  * <li>Managing AppProviders and the Apps that they provide.</li>
  * <li>Executing AppLifeCycle on App based on current and desired LifeCycle Location.</li>
  * </ol>
  * <p>
- * <img src="doc-files/DeploymentManager.png">
+ * <img alt="deployment manager graph" src="doc-files/DeploymentManager.png">
  */
 @ManagedObject("Deployment Manager")
 public class DeploymentManager extends ContainerLifeCycle
@@ -131,6 +131,7 @@
      * Receive an app for processing.
      * 
      * Most commonly used by the various {@link AppProvider} implementations.
+     * @param app the app
      */
     public void addApp(App app)
     {
@@ -151,7 +152,7 @@
     /** Set the AppProviders.
      * The providers passed are added via {@link #addBean(Object)} so that 
      * their lifecycles may be managed as a {@link ContainerLifeCycle}.
-     * @param providers
+     * @param providers the app provider list
      */
     public void setAppProviders(Collection<AppProvider> providers)
     {
@@ -202,9 +203,9 @@
     /**
      * Convenience method to allow for insertion of nodes into the lifecycle.
      * 
-     * @param existingFromNodeName
-     * @param existingToNodeName
-     * @param insertedNodeName
+     * @param existingFromNodeName the existing node start
+     * @param existingToNodeName the existing node end
+     * @param insertedNodeName the new node to create between the existing nodes
      */
     public void insertLifeCycleNode(String existingFromNodeName, String existingToNodeName, String insertedNodeName)
     {
@@ -353,7 +354,7 @@
     /**
      * Get a contextAttribute that will be set for every Context deployed by this provider.
      * 
-     * @param name
+     * @param name context attribute name
      * @return the context attribute value
      */
     public Object getContextAttribute(String name)
@@ -431,7 +432,7 @@
     /**
      * Remove a contextAttribute that will be set for every Context deployed by this provider.
      * 
-     * @param name
+     * @param name the context attribute name
      */
     public void removeContextAttribute(String name)
     {
@@ -529,8 +530,8 @@
     /**
      * Set a contextAttribute that will be set for every Context deployed by this provider.
      * 
-     * @param name
-     * @param value
+     * @param name the context attribute name
+     * @param value the context attribute value
      */
     public void setContextAttribute(String name, Object value)
     {
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java
new file mode 100644
index 0000000..c0577f3
--- /dev/null
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/DebugListenerBinding.java
@@ -0,0 +1,53 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.deploy.bindings;
+
+import org.eclipse.jetty.deploy.App;
+import org.eclipse.jetty.deploy.graph.Node;
+import org.eclipse.jetty.server.DebugListener;
+
+
+/** A Deployment binding that installs a DebugListener in all deployed contexts
+ */
+public class DebugListenerBinding extends DebugBinding
+{
+    final DebugListener _debugListener;
+
+    public DebugListenerBinding()
+    {
+        this(new DebugListener());
+    }
+    
+    public DebugListenerBinding(DebugListener debugListener)
+    {
+        super(new String[]{"deploying"});
+        _debugListener=debugListener;
+    }
+    
+    public DebugListener getDebugListener()
+    {
+        return _debugListener;
+    }
+    
+    public void processBinding(Node node, App app) throws Exception
+    {
+        app.getContextHandler().addEventListener(_debugListener);
+    }
+
+}
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java
index 006438e..7b90177 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBinding.java
@@ -97,6 +97,8 @@
                 Resource resource = Resource.newResource(app.getOriginId());
                 File file = resource.getFile();
                 jettyXmlConfig.getIdMap().put("Server",app.getDeploymentManager().getServer());
+                jettyXmlConfig.getProperties().put("jetty.home",System.getProperty("jetty.home","."));
+                jettyXmlConfig.getProperties().put("jetty.base",System.getProperty("jetty.base","."));
                 jettyXmlConfig.getProperties().put("jetty.webapp",file.getCanonicalPath());
                 jettyXmlConfig.getProperties().put("jetty.webapps",file.getParentFile().getCanonicalPath());
                 
diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
index 42f9071..7b7303d 100644
--- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
+++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java
@@ -25,6 +25,7 @@
 import org.eclipse.jetty.deploy.App;
 import org.eclipse.jetty.deploy.ConfigurationManager;
 import org.eclipse.jetty.deploy.util.FileID;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
@@ -33,8 +34,8 @@
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
-/* ------------------------------------------------------------ */
-/** The webapps directory scanning provider.
+/** 
+ * The webapps directory scanning provider.
  * <p>
  * This provider scans one or more directories (typically "webapps") for contexts to
  * deploy, which may be:<ul>
@@ -213,9 +214,6 @@
     }  
     
     /* ------------------------------------------------------------ */
-    /**
-     *
-     */
     @ManagedAttribute("configuration classes for webapps to be processed through")
     public String[] getConfigurationClasses()
     {
@@ -259,7 +257,7 @@
 
         if (resource.exists() && FileID.isXmlFile(file))
         {
-            XmlConfiguration xmlc = new XmlConfiguration(resource.getURL())
+            XmlConfiguration xmlc = new XmlConfiguration(resource.getURI().toURL())
             {
                 @Override
                 public void initializeDefaults(Object context)
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
index d97db3a..96a4659 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/AppLifeCycleTest.java
@@ -36,10 +36,10 @@
  */
 public class AppLifeCycleTest
 {
-        @Rule
-        public TestingDir testdir = new TestingDir();
+    @Rule
+    public TestingDir testdir = new TestingDir();
 
-        private void assertNoPath(String from, String to)
+    private void assertNoPath(String from, String to)
     {
         assertPath(from,to,new ArrayList<String>());
     }
@@ -168,7 +168,7 @@
      * Request multiple lifecycle paths with a single lifecycle instance. Just to ensure that there is no state
      * maintained between {@link AppLifeCycle#getPath(Node, Node)} requests.
      * 
-     * @throws IOException
+     * @throws IOException on test failure
      */
     @Test
     public void testFindPathMultiple() throws IOException
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
index 7f9aa74..05a3d63 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/bindings/GlobalWebappConfigBindingTest.java
@@ -26,6 +26,7 @@
 import java.io.File;
 import java.util.List;
 
+import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
 import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
 import org.eclipse.jetty.toolchain.test.IO;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java
index 8776926..34d111a 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ScanningAppProviderRuntimeUpdatesTest.java
@@ -116,6 +116,7 @@
 
     /**
      * Simple webapp deployment after startup of server.
+     * @throws IOException on test failure
      */
     @Test
     public void testAfterStartupContext() throws IOException
@@ -131,6 +132,7 @@
 
     /**
      * Simple webapp deployment after startup of server, and then removal of the webapp.
+     * @throws IOException on test failure
      */
     @Test
     public void testAfterStartupThenRemoveContext() throws IOException
@@ -154,6 +156,7 @@
 
     /**
      * Simple webapp deployment after startup of server, and then removal of the webapp.
+     * @throws Exception on test failure
      */
     @Test
     public void testAfterStartupThenUpdateContext() throws Exception
diff --git a/jetty-deploy/src/test/resources/binding-test-contexts-1.xml b/jetty-deploy/src/test/resources/binding-test-contexts-1.xml
index 3c6a950..d49cf70 100644
--- a/jetty-deploy/src/test/resources/binding-test-contexts-1.xml
+++ b/jetty-deploy/src/test/resources/binding-test-contexts-1.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
diff --git a/jetty-deploy/src/test/resources/etc/webdefault.xml b/jetty-deploy/src/test/resources/etc/webdefault.xml
index 13a96e9..6a58d98 100644
--- a/jetty-deploy/src/test/resources/etc/webdefault.xml
+++ b/jetty-deploy/src/test/resources/etc/webdefault.xml
@@ -1,113 +1,142 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!-- ===================================================================== -->
-<!-- This file contains the default descriptor for web applications.       -->
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<!-- The intent of this descriptor is to include jetty specific or common  -->
-<!-- configuration for all webapps.   If a context has a webdefault.xml    -->
-<!-- descriptor, it is applied before the contexts own web.xml file        -->
-<!--                                                                       -->
-<!-- A context may be assigned a default descriptor by:                    -->
-<!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
-<!--  + Passed an arg to addWebApplications                                -->
-<!--                                                                       -->
-<!-- This file is used both as the resource within the jetty.jar (which is -->
-<!-- used as the default if no explicit defaults descriptor is set) and it -->
-<!-- is copied to the etc directory of the Jetty distro and explicitly     -->
-<!-- by the jetty.xml file.                                                -->
-<!--                                                                       -->
-<!-- ===================================================================== -->
 <web-app 
-   xmlns="http://java.sun.com/xml/ns/javaee" 
+   xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
-   metadata-complete="true"
-   version="2.5"> 
+   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+   metadata-complete="false"
+   version="3.1"> 
+
+  <!-- ===================================================================== -->
+  <!-- This file contains the default descriptor for web applications.       -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+  <!-- The intent of this descriptor is to include jetty specific or common  -->
+  <!-- configuration for all webapps.   If a context has a webdefault.xml    -->
+  <!-- descriptor, it is applied before the context's own web.xml file       -->
+  <!--                                                                       -->
+  <!-- A context may be assigned a default descriptor by calling             -->
+  <!-- WebAppContext.setDefaultsDescriptor(String).                          -->
+  <!--                                                                       -->
+  <!-- This file is present in the jetty-webapp.jar, and is used as the      -->
+  <!-- defaults descriptor if no other is explicitly set on a context.       -->
+  <!--                                                                       -->
+  <!-- A copy of this file is also placed into the $JETTY_HOME/etc dir of    -->
+  <!-- the  distribution, and is referenced by some of the other xml files,  -->
+  <!-- eg the jetty-deploy.xml file.                                         -->
+  <!-- ===================================================================== -->
 
   <description>
     Default web.xml file.  
     This file is applied to a Web application before it's own WEB_INF/web.xml file
   </description>
 
+  <!-- ==================================================================== -->
+  <!-- Removes static references to beans from javax.el.BeanELResolver to   -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class>
+  </listener>
+  
+  <!-- ==================================================================== -->
+  <!-- Removes static cache of Methods from java.beans.Introspector to      -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->  
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class>
+  </listener>
+  
 
   <!-- ==================================================================== -->
   <!-- Context params to control Session Cookies                            -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- UNCOMMENT TO ACTIVATE
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
-    <param-value>127.0.0.1</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
-    <param-value>/</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
-    <param-value>-1</param-value>
-  </context-param>
+  <!--
+    UNCOMMENT TO ACTIVATE 
+    <context-param> 
+      <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> 
+      <param-value>127.0.0.1</param-value> 
+    </context-param> 
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+      <param-value>/</param-value>
+    </context-param>
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+      <param-value>-1</param-value>
+    </context-param>
   -->
 
-
   <!-- ==================================================================== -->
   <!-- The default servlet.                                                 -->
   <!-- This servlet, normally mapped to /, provides the handling for static -->
   <!-- content, OPTIONS and TRACE methods for the context.                  -->
   <!-- The following initParameters are supported:                          -->
-  <!--                                                                      -->
-  <!--   acceptRanges     If true, range requests and responses are         -->
-  <!--                    supported                                         -->
-  <!--                                                                      -->
-  <!--   dirAllowed       If true, directory listings are returned if no    -->
-  <!--                    welcome file is found. Else 403 Forbidden.        -->
-  <!--                                                                      -->
-  <!--   welcomeServlets  If true, attempt to dispatch to welcome files     -->
-  <!--                    that are servlets, if no matching static          -->
-  <!--                    resources can be found.                           -->
-  <!--                                                                      -->
-  <!--   redirectWelcome  If true, redirect welcome file requests           -->
-  <!--                    else use request dispatcher forwards              -->
-  <!--                                                                      -->
-  <!--   gzip             If set to true, then static content will be served--> 
-  <!--                    as gzip content encoded if a matching resource is -->
-  <!--                    found ending with ".gz"                           -->
-  <!--                                                                      -->
-  <!--   resoureBase      Can be set to replace the context resource base   -->
-  <!--                                                                      -->
-  <!--   relativeResourceBase                                               -->
-  <!--                    Set with a pathname relative to the base of the   -->
-  <!--                    servlet context root. Useful for only serving     -->
-  <!--                    static content from only specific subdirectories. -->
-  <!--                                                                      -->
-  <!--   useFileMappedBuffer                                                -->
-  <!--                    If set to true (the default), a  memory mapped    -->
-  <!--                    file buffer will be used to serve static content  -->
-  <!--                    when using an NIO connector. Setting this value   -->
-  <!--                    to false means that a direct buffer will be used  -->
-  <!--                    instead. If you are having trouble with Windows   -->
-  <!--                    file locking, set this to false.                  -->
-  <!--                                                                      -->
-  <!--  cacheControl      If set, all static content will have this value   -->
-  <!--                    set as the cache-control header.                  -->
-  <!--                                                                      -->
-  <!--  maxCacheSize      Maximum size of the static resource cache         -->
-  <!--                                                                      -->
-  <!--  maxCachedFileSize Maximum size of any single file in the cache      -->
-  <!--                                                                      -->
-  <!--  maxCachedFiles    Maximum number of files in the cache              -->
-  <!--                                                                      -->
-  <!--  cacheType         "nio", "bio" or "both" to determine the type(s)   -->
-  <!--                    of resource cache. A bio cached buffer may be used-->
-  <!--                    by nio but is not as efficient as a nio buffer.   -->
-  <!--                    An nio cached buffer may not be used by bio.      -->
-  <!--                                                                      -->
-  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!--  
+ *  acceptRanges      If true, range requests and responses are
+ *                    supported
+ *
+ *  dirAllowed        If true, directory listings are returned if no
+ *                    welcome file is found. Else 403 Forbidden.
+ *
+ *  welcomeServlets   If true, attempt to dispatch to welcome files
+ *                    that are servlets, but only after no matching static
+ *                    resources could be found. If false, then a welcome
+ *                    file must exist on disk. If "exact", then exact
+ *                    servlet matches are supported without an existing file.
+ *                    Default is true.
+ *
+ *                    This must be false if you want directory listings,
+ *                    but have index.jsp in your welcome file list.
+ *
+ *  redirectWelcome   If true, welcome files are redirected rather than
+ *                    forwarded to.
+ *
+ *  gzip              If set to true, then static content will be served as
+ *                    gzip content encoded if a matching resource is
+ *                    found ending with ".gz"
+ *
+ *  resourceBase      Set to replace the context resource base
+ *
+ *  resourceCache     If set, this is a context attribute name, which the servlet
+ *                    will use to look for a shared ResourceCache instance.
+ *
+ *  relativeResourceBase
+ *                    Set with a pathname relative to the base of the
+ *                    servlet context root. Useful for only serving static content out
+ *                    of only specific subdirectories.
+ *
+ *  pathInfoOnly      If true, only the path info will be applied to the resourceBase
+ *
+ *  stylesheet        Set with the location of an optional stylesheet that will be used
+ *                    to decorate the directory listing html.
+ *
+ *  aliases           If True, aliases of resources are allowed (eg. symbolic
+ *                    links and caps variations). May bypass security constraints.
+ *                    
+ *  etags             If True, weak etags will be generated and handled.
+ *
+ *  maxCacheSize      The maximum total size of the cache or 0 for no cache.
+ *  maxCachedFileSize The maximum size of a file to cache
+ *  maxCachedFiles    The maximum number of files to cache
+ *
+ *  useFileMappedBuffer
+ *                    If set to true, it will use mapped file buffers to serve static content
+ *                    when using an NIO connector. Setting this value to false means that
+ *                    a direct buffer will be used instead of a mapped file buffer.
+ *                    This file sets the value to true.
+ *
+ *  cacheControl      If set, all static content will have this value set as the cache-control
+ *                    header.
+ *
+ -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet>
     <servlet-name>default</servlet-name>
     <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
     <init-param>
+      <param-name>aliases</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
       <param-name>acceptRanges</param-name>
       <param-value>true</param-value>
     </init-param>
@@ -117,8 +146,8 @@
     </init-param>
     <init-param>
       <param-name>welcomeServlets</param-name>
- 	    <param-value>false</param-value>
- 	  </init-param>
+      <param-value>false</param-value>
+    </init-param>
     <init-param>
       <param-name>redirectWelcome</param-name>
       <param-value>false</param-value>
@@ -129,24 +158,30 @@
     </init-param>
     <init-param>
       <param-name>maxCachedFileSize</param-name>
-      <param-value>10000000</param-value>
+      <param-value>200000000</param-value>
     </init-param>
     <init-param>
       <param-name>maxCachedFiles</param-name>
-      <param-value>1000</param-value>
-    </init-param>
-    <init-param>
-      <param-name>cacheType</param-name>
-      <param-value>both</param-value>
+      <param-value>2048</param-value>
     </init-param>
     <init-param>
       <param-name>gzip</param-name>
       <param-value>true</param-value>
     </init-param>
     <init-param>
+      <param-name>etags</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
       <param-name>useFileMappedBuffer</param-name>
       <param-value>true</param-value>
-    </init-param>  
+    </init-param>
+    <!--
+    <init-param>
+      <param-name>resourceCache</param-name>
+      <param-value>resourceCache</param-value>
+    </init-param>
+    -->
     <!--
     <init-param>
       <param-name>cacheControl</param-name>
@@ -154,20 +189,23 @@
     </init-param>
     -->
     <load-on-startup>0</load-on-startup>
-  </servlet> 
+  </servlet>
 
-  <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-  
+  <servlet-mapping>
+    <servlet-name>default</servlet-name>
+    <url-pattern>/</url-pattern>
+  </servlet-mapping>
+
 
   <!-- ==================================================================== -->
   <!-- JSP Servlet                                                          -->
-  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- This is the jasper JSP servlet.                                      -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
-  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
-  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
-  <!-- following initialization parameters (default values are in square    -->
-  <!-- brackets):                                                           -->
+  <!-- used by the jsp container to support JSP pages.  Traditionally,      -->
+  <!-- this servlet is mapped to URL pattern "*.jsp".  This servlet         -->
+  <!-- supports the following initialization parameters (default values     -->
+  <!-- are in square brackets):                                             -->
   <!--                                                                      -->
   <!--   checkInterval       If development is false and reloading is true, -->
   <!--                       background compiles are enabled. checkInterval -->
@@ -175,7 +213,7 @@
   <!--                       if a JSP page needs to be recompiled. [300]    -->
   <!--                                                                      -->
   <!--   compiler            Which compiler Ant should use to compile JSP   -->
-  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       pages.  See the Ant documentation for more     -->
   <!--                       information. [javac]                           -->
   <!--                                                                      -->
   <!--   classdebuginfo      Should the class file be compiled with         -->
@@ -236,28 +274,29 @@
   <!--   xpoweredBy          Determines whether X-Powered-By response       -->
   <!--                       header is added by generated servlet  [false]  -->
   <!--                                                                      -->
-  <!-- If you wish to use Jikes to compile JSP pages:                       -->
-  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
-  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
-  <!--   to cause Jikes to emit error messages in a format compatible with  -->
-  <!--   Jasper.                                                            -->
-  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
-  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet id="jsp">
     <servlet-name>jsp</servlet-name>
-    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
     <init-param>
-        <param-name>logVerbosityLevel</param-name>
-        <param-value>DEBUG</param-value>
+      <param-name>logVerbosityLevel</param-name>
+      <param-value>DEBUG</param-value>
     </init-param>
     <init-param>
-        <param-name>fork</param-name>
-        <param-value>false</param-value>
+      <param-name>fork</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
-        <param-name>xpoweredBy</param-name>
-        <param-value>false</param-value>
+      <param-name>xpoweredBy</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerTargetVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerSourceVM</param-name>
+      <param-value>1.7</param-value>
     </init-param>
     <!--  
     <init-param>
@@ -268,62 +307,22 @@
     <load-on-startup>0</load-on-startup>
   </servlet>
 
-  <servlet-mapping> 
-    <servlet-name>jsp</servlet-name> 
-    <url-pattern>*.jsp</url-pattern> 
+  <servlet-mapping>
+    <servlet-name>jsp</servlet-name>
+    <url-pattern>*.jsp</url-pattern>
     <url-pattern>*.jspf</url-pattern>
     <url-pattern>*.jspx</url-pattern>
     <url-pattern>*.xsp</url-pattern>
-    <url-pattern>*.JSP</url-pattern> 
+    <url-pattern>*.JSP</url-pattern>
     <url-pattern>*.JSPF</url-pattern>
     <url-pattern>*.JSPX</url-pattern>
     <url-pattern>*.XSP</url-pattern>
   </servlet-mapping>
-  
+
+
   <!-- ==================================================================== -->
-  <!-- Dynamic Servlet Invoker.                                             -->
-  <!-- This servlet invokes anonymous servlets that have not been defined   -->
-  <!-- in the web.xml or by other means. The first element of the pathInfo  -->
-  <!-- of a request passed to the envoker is treated as a servlet name for  -->
-  <!-- an existing servlet, or as a class name of a new servlet.            -->
-  <!-- This servlet is normally mapped to /servlet/*                        -->
-  <!-- This servlet support the following initParams:                       -->
-  <!--                                                                      -->
-  <!--  nonContextServlets       If false, the invoker can only load        -->
-  <!--                           servlets from the contexts classloader.    -->
-  <!--                           This is false by default and setting this  -->
-  <!--                           to true may have security implications.    -->
-  <!--                                                                      -->
-  <!--  verbose                  If true, log dynamic loads                 -->
-  <!--                                                                      -->
-  <!--  *                        All other parameters are copied to the     -->
-  <!--                           each dynamic servlet as init parameters    -->
+  <!-- Default session configuration                                        -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- Uncomment for dynamic invocation
-  <servlet>
-    <servlet-name>invoker</servlet-name>
-    <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
-    <init-param>
-      <param-name>verbose</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>nonContextServlets</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>dynamicParam</param-name>
-      <param-value>anyValue</param-value>
-    </init-param>
-    <load-on-startup>0</load-on-startup>
-  </servlet>
-
-  <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
-  -->
-
-
-
-  <!-- ==================================================================== -->
   <session-config>
     <session-timeout>30</session-timeout>
   </session-config>
@@ -342,6 +341,8 @@
   -->
 
   <!-- ==================================================================== -->
+  <!-- Default welcome files                                                -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <welcome-file-list>
     <welcome-file>index.html</welcome-file>
     <welcome-file>index.htm</welcome-file>
@@ -349,48 +350,170 @@
   </welcome-file-list>
 
   <!-- ==================================================================== -->
+  <!-- Default locale encodings                                             -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <locale-encoding-mapping-list>
-    <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>     
-    <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>   
+    <locale-encoding-mapping>
+      <locale>ar</locale>
+      <encoding>ISO-8859-6</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>be</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>bg</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ca</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>cs</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>da</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>de</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>el</locale>
+      <encoding>ISO-8859-7</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>en</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>es</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>et</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fi</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fr</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hr</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hu</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>is</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>it</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>iw</locale>
+      <encoding>ISO-8859-8</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ja</locale>
+      <encoding>Shift_JIS</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ko</locale>
+      <encoding>EUC-KR</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lt</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lv</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>mk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>nl</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>no</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pt</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ro</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ru</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sh</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sk</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sq</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sr</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sv</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>tr</locale>
+      <encoding>ISO-8859-9</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>uk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh</locale>
+      <encoding>GB2312</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh_TW</locale>
+      <encoding>Big5</encoding>
+    </locale-encoding-mapping>
   </locale-encoding-mapping-list>
-  
+
+  <!-- ==================================================================== -->
+  <!-- Disable TRACE method with security constraint                        -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <security-constraint>
     <web-resource-collection>
       <web-resource-name>Disable TRACE</web-resource-name>
@@ -399,6 +522,13 @@
     </web-resource-collection>
     <auth-constraint/>
   </security-constraint>
-  
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Enable everything but TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method-omission>TRACE</http-method-omission>
+    </web-resource-collection>
+  </security-constraint>
+
 </web-app>
 
diff --git a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml
index 9933cb6..1760a67 100644
--- a/jetty-deploy/src/test/resources/jetty-deploy-wars.xml
+++ b/jetty-deploy/src/test/resources/jetty-deploy-wars.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
diff --git a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
index 8d55d22..b16fbd7 100644
--- a/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
+++ b/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
   <Call name="addBean">
diff --git a/jetty-deploy/src/test/resources/jetty-http.xml b/jetty-deploy/src/test/resources/jetty-http.xml
index 42b889b..7fa6def 100644
--- a/jetty-deploy/src/test/resources/jetty-http.xml
+++ b/jetty-deploy/src/test/resources/jetty-http.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
 <!-- Configure the Jetty Server instance with an ID "Server"       -->
diff --git a/jetty-deploy/src/test/resources/jetty.xml b/jetty-deploy/src/test/resources/jetty.xml
index 25332f6..a08e270 100644
--- a/jetty-deploy/src/test/resources/jetty.xml
+++ b/jetty-deploy/src/test/resources/jetty.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Documentation of this file format can be found at:              -->
@@ -46,9 +46,9 @@
     <Arg name="threadpool"><New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool"/></Arg>
     -->
     <Get name="ThreadPool">
-      <Set name="minThreads" type="int"><Property name="threads.min" default="10"/></Set>
-      <Set name="maxThreads" type="int"><Property name="threads.max" default="200"/></Set>
-      <Set name="idleTimeout" type="int"><Property name="threads.timeout" default="60000"/></Set>
+      <Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" default="10"/></Set>
+      <Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" default="200"/></Set>
+      <Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" default="60000"/></Set>
       <Set name="detailedDump">false</Set>
     </Get>
 
@@ -64,21 +64,21 @@
     <!-- =========================================================== -->
     <!-- Http Configuration.                                         -->
     <!-- This is a common configuration instance used by all         -->
-    <!-- connectors that can carry HTTP semantics (HTTP, HTTPS, SPDY)-->
+    <!-- connectors that can carry HTTP semantics (HTTP, HTTPS, etc.)-->
     <!-- It configures the non wire protocol aspects of the HTTP     -->
     <!-- semantic.                                                   -->
     <!--                                                             -->
     <!-- This configuration is only defined here and is used by      -->
-    <!-- reference from the jetty-http.xml, jetty-https.xml and      -->
-    <!-- jetty-spdy.xml configuration files which instantiate the    -->
-    <!-- connectors.                                                 -->
+    <!-- reference from other XML files such as jetty-http.xml,      -->
+    <!-- jetty-https.xml and other configuration files which         -->
+    <!-- instantiate the connectors.                                 -->
     <!--                                                             -->
     <!-- Consult the javadoc of o.e.j.server.HttpConfiguration       -->
     <!-- for all configuration that may be set here.                 -->
     <!-- =========================================================== -->
     <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
       <Set name="secureScheme">https</Set>
-      <Set name="securePort" type="java.lang.Integer"><Property name="jetty.secure.port" default="8443" /></Set>
+      <Set name="securePort" type="java.lang.Integer"><Property name="jetty.httpConfig.securePort" default="8443" /></Set>
       <Set name="outputBufferSize">32768</Set>
       <Set name="requestHeaderSize">8192</Set>
       <Set name="responseHeaderSize">8192</Set>
@@ -125,7 +125,7 @@
     <!-- =========================================================== -->
     <Set name="stopAtShutdown">true</Set>
     <Set name="stopTimeout">5000</Set>
-    <Set name="dumpAfterStart"><Property name="jetty.dump.start" default="false"/></Set>
-    <Set name="dumpBeforeStop"><Property name="jetty.dump.stop" default="false"/></Set>
+    <Set name="dumpAfterStart"><Property name="jetty.server.dumpAfterStart" default="false"/></Set>
+    <Set name="dumpBeforeStop"><Property name="jetty.server.dumpBeforeStop" default="false"/></Set>
 
 </Configure>
diff --git a/jetty-deploy/src/test/resources/webapps/foo.xml b/jetty-deploy/src/test/resources/webapps/foo.xml
index e7c6e9d..f0a9611 100644
--- a/jetty-deploy/src/test/resources/webapps/foo.xml
+++ b/jetty-deploy/src/test/resources/webapps/foo.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
     <Set name="contextPath">/foo</Set>
     <Set name="war">
diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml
index c1eabd9..f106ee4 100644
--- a/jetty-distribution/pom.xml
+++ b/jetty-distribution/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>jetty-distribution</artifactId>
   <name>Jetty :: Distribution Assemblies</name>
@@ -11,7 +11,7 @@
   <packaging>pom</packaging>
   <properties>
     <assembly-directory>${basedir}/target/distribution</assembly-directory>
-    <jetty-setuid-version>1.0.1</jetty-setuid-version>
+    <jetty-setuid-version>1.0.3</jetty-setuid-version>
   </properties>
   <build>
     <plugins>
@@ -53,6 +53,18 @@
               </tasks>
             </configuration>
           </execution>
+          <execution>
+	    <id>removeKeystore</id>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <tasks>
+                <delete file="${assembly-directory}/etc/keystore" />
+              </tasks>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
       <plugin>
@@ -206,28 +218,6 @@
           </execution>
 
           <execution>
-            <id>unpack-setuid-config</id>
-            <phase>process-resources</phase>
-            <goals>
-              <goal>unpack</goal>
-            </goals>
-            <configuration>
-              <artifactItems>
-                <artifactItem>
-                  <groupId>org.eclipse.jetty.toolchain.setuid</groupId>
-                  <artifactId>jetty-setuid-java</artifactId>
-                  <version>${jetty-setuid-version}</version>
-                  <classifier>config</classifier>
-                  <type>jar</type>
-                  <overWrite>true</overWrite>
-                  <outputDirectory>${assembly-directory}</outputDirectory>
-                </artifactItem>
-              </artifactItems>
-              <excludes>META-INF/**</excludes>
-            </configuration>
-          </execution>
-
-          <execution>
             <id>unpack-test-jaas-config</id>
             <phase>process-resources</phase>
             <goals>
@@ -301,8 +291,8 @@
             </goals>
             <configuration>
               <includeGroupIds>org.eclipse.jetty</includeGroupIds>
-              <excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.spdy,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs</excludeGroupIds>
-              <excludeArtifactIds>jetty-all,jetty-jsp,apache-jsp,apache-jstl,jetty-start,jetty-monitor,jetty-spring</excludeArtifactIds>
+              <excludeGroupIds>org.eclipse.jetty.orbit,org.eclipse.jetty.http2,org.eclipse.jetty.websocket,org.eclipse.jetty.fcgi,org.eclipse.jetty.toolchain,org.apache.taglibs</excludeGroupIds>
+              <excludeArtifactIds>jetty-all,apache-jsp,apache-jstl,jetty-start,jetty-monitor,jetty-spring</excludeArtifactIds>
               <includeTypes>jar</includeTypes>
               <outputDirectory>${assembly-directory}/lib</outputDirectory>
             </configuration>
@@ -321,6 +311,19 @@
             </configuration>
           </execution>
           <execution>
+            <id>copy-lib-http2-deps</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <includeGroupIds>org.eclipse.jetty.http2</includeGroupIds>
+              <includeArtifactIds>http2-hpack,http2-common,http2-server</includeArtifactIds>
+              <includeTypes>jar</includeTypes>
+              <outputDirectory>${assembly-directory}/lib/http2</outputDirectory>
+            </configuration>
+          </execution>
+          <execution>
             <id>copy-lib-fcgi-deps</id>
             <phase>generate-resources</phase>
             <goals>
@@ -392,32 +395,6 @@
             </configuration>
           </execution>
           <execution>
-            <id>unpack-spdy</id>
-            <phase>process-resources</phase>
-            <goals>
-              <goal>unpack-dependencies</goal>
-            </goals>
-            <configuration>
-              <includeGroupIds>org.eclipse.jetty.spdy</includeGroupIds>
-              <classifier>config</classifier>
-              <failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
-              <excludes>META-INF/**</excludes>
-              <outputDirectory>${assembly-directory}</outputDirectory>
-            </configuration>
-          </execution>
-          <execution>
-            <id>copy-lib-spdy-deps</id>
-            <phase>process-resources</phase>
-            <goals>
-              <goal>copy-dependencies</goal>
-            </goals>
-            <configuration>
-              <includeGroupIds>org.eclipse.jetty.spdy</includeGroupIds>
-              <includeTypes>jar</includeTypes>
-              <outputDirectory>${assembly-directory}/lib/spdy</outputDirectory>
-            </configuration>
-          </execution>
-          <execution>
             <id>copy-annotations-deps</id>
             <phase>generate-resources</phase>
             <goals>
@@ -458,27 +435,14 @@
             </configuration>
           </execution>
           <execution>
-            <id>copy-glassfish-jsp-deps</id>
-            <phase>generate-resources</phase>
-            <goals>
-              <goal>copy-dependencies</goal>
-            </goals>
-            <configuration>
-              <includeGroupIds>org.eclipse.jetty.orbit,org.glassfish.web, org.glassfish, javax.el, javax.servlet.jsp, org.eclipse.jetty.toolchain, org.eclipse.jetty</includeGroupIds>
-              <includeArtifactIds>org.eclipse.jdt.core, javax.servlet.jsp-api, javax.servlet.jsp, jetty-jsp-jdt, javax.el-api, javax.el, jetty-jsp</includeArtifactIds>
-              <includeTypes>jar</includeTypes>
-              <outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
-            </configuration>
-          </execution>
-          <execution>
             <id>copy-apache-jsp-deps</id>
             <phase>generate-resources</phase>
             <goals>
               <goal>copy-dependencies</goal>
             </goals>
             <configuration>
-              <includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.toolchain,org.mortbay.jasper,org.eclipse.jetty.orbit</includeGroupIds>
-              <includeArtifactIds>apache-jsp,apache-el,org.eclipse.jdt.core</includeArtifactIds>
+              <includeGroupIds>org.eclipse.jetty,org.eclipse.jetty.toolchain,org.mortbay.jasper,org.eclipse.jetty.orbit,org.eclipse.jdt.core.compiler</includeGroupIds>
+              <includeArtifactIds>apache-jsp,apache-el,ecj</includeArtifactIds>
               <includeTypes>jar</includeTypes>
               <prependGroupId>true</prependGroupId>
               <outputDirectory>${assembly-directory}/lib/apache-jsp</outputDirectory>
@@ -499,19 +463,6 @@
            </configuration>
           </execution>
           <execution>
-           <id>copy-jstl-impl</id>
-           <phase>generate-resources</phase>
-           <goals>
-             <goal>copy-dependencies</goal>
-           </goals>
-           <configuration>
-              <includeGroupIds>org.glassfish.web</includeGroupIds>
-              <includeArtifactIds>javax.servlet.jsp.jstl</includeArtifactIds>
-              <includeTypes>jar</includeTypes>
-              <outputDirectory>${assembly-directory}/lib/jsp</outputDirectory>
-           </configuration>
-          </execution>
-          <execution>
            <id>copy-apache-jstl-deps</id>
            <phase>generate-resources</phase>
            <goals>
@@ -566,7 +517,7 @@
               <arguments>
                 <argument>jetty.home=${assembly-directory}</argument>
                 <argument>jetty.base=${assembly-directory}</argument>
-                <argument>--add-to-start=server,deploy,websocket,ext,resources,jsp,jstl,http</argument>
+                <argument>--add-to-start=deploy,websocket,ext,resources,jsp,jstl,http</argument>
               </arguments>
             </configuration>
             <goals>
@@ -574,14 +525,28 @@
             </goals>
           </execution>
           <execution>
-            <id>setup demo-base</id>
+            <id>setup demo-base-ini</id>
             <phase>process-classes</phase>
             <configuration>
               <mainClass>org.eclipse.jetty.start.Main</mainClass>
               <arguments>
                 <argument>jetty.home=${assembly-directory}</argument>
                 <argument>jetty.base=${assembly-directory}/demo-base</argument>
-                <argument>--add-to-start=server,continuation,deploy,websocket,ext,resources,client,annotations,jndi,servlets</argument>
+                <argument>--add-to-start=continuation,deploy,websocket,ext,resources,client,annotations,jndi,servlets</argument>
+              </arguments>
+            </configuration>
+            <goals>
+              <goal>java</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>setup demo-base-startd</id>
+            <phase>process-classes</phase>
+            <configuration>
+              <mainClass>org.eclipse.jetty.start.Main</mainClass>
+              <arguments>
+                <argument>jetty.home=${assembly-directory}</argument>
+                <argument>jetty.base=${assembly-directory}/demo-base</argument>
                 <argument>--add-to-startd=jsp,jstl,http,https</argument>
               </arguments>
             </configuration>
@@ -649,28 +614,6 @@
     </dependency>
 
     <dependency>
-      <groupId>org.glassfish.web</groupId>
-      <artifactId>javax.servlet.jsp.jstl</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>org.glassfish.web</groupId>
-      <artifactId>javax.servlet.jsp</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.toolchain</groupId>
-      <artifactId>jetty-jsp-jdt</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>javax.servlet.jsp</groupId>
-      <artifactId>javax.servlet.jsp-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.glassfish</groupId>
-      <artifactId>javax.el</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>org.ow2.asm</groupId>
       <artifactId>asm</artifactId>
     </dependency>
@@ -739,11 +682,6 @@
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-jsp</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
       <artifactId>apache-jsp</artifactId>
       <version>${project.version}</version>
     </dependency>
@@ -790,8 +728,13 @@
     </dependency>
 -->
     <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-cdi</artifactId>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-servlet</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.cdi</groupId>
+      <artifactId>cdi-websocket</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -810,27 +753,11 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-core</artifactId>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-example-webapp</artifactId>
-      <version>${project.version}</version>
-      <type>war</type>
-    </dependency>
-    <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-alpn-server</artifactId>
       <version>${project.version}</version>
@@ -846,5 +773,20 @@
       <artifactId>jetty-jaspi</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-infinispan</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.gcloud</groupId>
+      <artifactId>gcloud-session-manager</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-nosql</artifactId>
+      <version>${project.version}</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh
index da6f571..21c2c97 100755
--- a/jetty-distribution/src/main/resources/bin/jetty.sh
+++ b/jetty-distribution/src/main/resources/bin/jetty.sh
@@ -69,7 +69,7 @@
 # JETTY_ARGS
 #   The default arguments to pass to jetty.
 #   For example
-#      JETTY_ARGS=jetty.port=8080 jetty.spdy.port=8443 jetty.secure.port=443
+#      JETTY_ARGS=jetty.http.port=8080 jetty.ssl.port=8443
 #
 # JETTY_USER
 #   if set, then used as a username to run the server as
@@ -166,7 +166,7 @@
   ETC=$HOME/etc
 fi
 
-for CONFIG in $ETC/default/${NAME}{,9} $HOME/.${NAME}rc; do
+for CONFIG in {/etc,~/etc}/default/${NAME}{,9} $HOME/.${NAME}rc; do
   if [ -f "$CONFIG" ] ; then 
     readConfig "$CONFIG"
   fi
@@ -350,7 +350,7 @@
   CYGWIN*) JETTY_LOGS="`cygpath -w $JETTY_LOGS`";;
   esac
 
-  JAVA_OPTIONS=(${JAVA_OPTIONS[*]} "-Djetty.logs=$JETTY_LOGS")
+  JAVA_OPTIONS=(${JAVA_OPTIONS[*]} "-Djetty.logging.dir=$JETTY_LOGS")
 fi
 
 #####################################################
@@ -445,7 +445,7 @@
         exit 1
       fi
 
-      if [ -n "$JETTY_USER" ] 
+      if [ -n "$JETTY_USER" ] && [ `whoami` != "$JETTY_USER" ]
       then
         unset SU_SHELL
         if [ "$JETTY_SHELL" ]
@@ -457,11 +457,11 @@
         chown "$JETTY_USER" "$JETTY_PID"
         # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc.
         su - "$JETTY_USER" $SU_SHELL -c "
-          exec ${RUN_CMD[*]} start-log-file="$JETTY_LOGS/start.log" &
+          exec ${RUN_CMD[*]} start-log-file="$JETTY_LOGS/start.log" > /dev/null &
           disown \$!
           echo \$! > '$JETTY_PID'"
       else
-        "${RUN_CMD[@]}" &
+        "${RUN_CMD[@]}" > /dev/null &
         disown $!
         echo $! > "$JETTY_PID"
       fi
diff --git a/jetty-distribution/src/main/resources/demo-base/etc/keystore b/jetty-distribution/src/main/resources/demo-base/etc/keystore
deleted file mode 100644
index 08f6cda..0000000
--- a/jetty-distribution/src/main/resources/demo-base/etc/keystore
+++ /dev/null
Binary files differ
diff --git a/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html b/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
index ce03053..4d5a13f 100644
--- a/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
+++ b/jetty-distribution/src/main/resources/demo-base/webapps/ROOT/index.html
@@ -21,7 +21,7 @@
       Container which supports asynchronous server and client
       implementations of the <a href="http://en.wikipedia.org/wiki/HTTP">HTTP</a>,
       <a href="http://en.wikipedia.org/wiki/WebSocket">Websocket</a> and <a
-        href="http://en.wikipedia.org/wiki/SPDY">SPDY</a> protocols. The
+        href="http://en.wikipedia.org/wiki/HTTP/2">HTTP/2</a> protocols. The
       project is 100% <a href="http://en.wikipedia.org/wiki/Open_source">Open Source</a> and hosted by the <a href="http://www.eclipse.org">Eclipse Foundation</a> at <a href="http://www.eclipse.org/jetty/">http://www.eclipse.org/jetty</a>.
     </p>
   </div>
diff --git a/jetty-distribution/src/main/resources/demo-base/webapps/example-moved.xml b/jetty-distribution/src/main/resources/demo-base/webapps/example-moved.xml
index 53d6bfd..e9ad124 100644
--- a/jetty-distribution/src/main/resources/demo-base/webapps/example-moved.xml
+++ b/jetty-distribution/src/main/resources/demo-base/webapps/example-moved.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- Simple handler to redirect from old path to new -->
 <Configure class="org.eclipse.jetty.server.handler.MovedContextHandler">
diff --git a/jetty-distribution/src/main/resources/etc/hawtio.xml b/jetty-distribution/src/main/resources/etc/hawtio.xml
index 228adc1..cc87fce 100644
--- a/jetty-distribution/src/main/resources/etc/hawtio.xml
+++ b/jetty-distribution/src/main/resources/etc/hawtio.xml
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
   <Call name="addHandler">
     <Arg>
       <New class="org.eclipse.jetty.webapp.WebAppContext">
-	<Set name="contextPath">/hawtio</Set>
-	<Set name="war"><Property name="jetty.base" default="."/>/lib/hawtio/hawtio.war</Set>
-	<Set name="extractWAR">true</Set>
-	<Set name="copyWebDir">false</Set>
-	<Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
+        <Set name="contextPath">/hawtio</Set>
+        <Set name="war"><Property name="jetty.base" default="."/>/lib/hawtio/hawtio.war</Set>
+        <Set name="extractWAR">true</Set>
+        <Set name="copyWebDir">false</Set>
+        <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
       </New>
     </Arg>
   </Call>
diff --git a/jetty-distribution/src/main/resources/etc/jamon.xml b/jetty-distribution/src/main/resources/etc/jamon.xml
index d00d9c7..ec1d3f5 100644
--- a/jetty-distribution/src/main/resources/etc/jamon.xml
+++ b/jetty-distribution/src/main/resources/etc/jamon.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Mixin the Jamon Handler                                         -->
@@ -18,13 +18,13 @@
   <Ref refid="Contexts">
     <Call name="addHandler">
       <Arg>
-	<New class="org.eclipse.jetty.webapp.WebAppContext">
-	  <Set name="contextPath">/jamon</Set>
-	  <Set name="war"><Property name="jetty.base" default="."/>/lib/jamon/jamon.war</Set>
-	  <Set name="extractWAR">true</Set>
-	  <Set name="copyWebDir">false</Set>
-	  <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
-	</New>
+        <New class="org.eclipse.jetty.webapp.WebAppContext">
+          <Set name="contextPath">/jamon</Set>
+          <Set name="war"><Property name="jetty.base" default="."/>/lib/jamon/jamon.war</Set>
+          <Set name="extractWAR">true</Set>
+          <Set name="copyWebDir">false</Set>
+          <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
+        </New>
       </Arg>
     </Call>
   </Ref>
diff --git a/jetty-distribution/src/main/resources/etc/jetty-setuid.xml b/jetty-distribution/src/main/resources/etc/jetty-setuid.xml
new file mode 100644
index 0000000..cb33a1a
--- /dev/null
+++ b/jetty-distribution/src/main/resources/etc/jetty-setuid.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ================================================================ -->
+<!-- Configure the Jetty SetUIDListener                                -->
+<!-- ================================================================ -->
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <Call name="addLifeCycleListener">
+    <Arg>
+      <New class="org.eclipse.jetty.setuid.SetUIDListener">
+        <Set name="startServerAsPrivileged"><Property name="jetty.setuid.startServerAsPrivileged" deprecated="jetty.startServerAsPrivileged" default="false"/></Set>
+        <Set name="umaskOctal"><Property name="jetty.setuid.umask" deprecated="jetty.umask" default="002"/></Set>
+        <Set name="username"><Property name="jetty.setuid.userName" deprecated="jetty.username" default="jetty"/></Set>
+        <Set name="groupname"><Property name="jetty.setuid.groupName" deprecated="jetty.groupname" default="jetty"/></Set>
+        <!-- uncomment to change the limits on number of open file descriptors for root -->
+        <!--
+        <Call name="setRLimitNoFiles">
+          <Arg>
+            <New class="org.eclipse.jetty.setuid.RLimit">
+              <Set name="soft">20000</Set>
+              <Set name="hard">40000</Set>
+            </New>
+          </Arg>
+        </Call>
+        -->
+      </New>
+    </Arg>
+  </Call>
+</Configure>
diff --git a/jetty-distribution/src/main/resources/etc/jetty-started.xml b/jetty-distribution/src/main/resources/etc/jetty-started.xml
index b958074..faa2839 100644
--- a/jetty-distribution/src/main/resources/etc/jetty-started.xml
+++ b/jetty-distribution/src/main/resources/etc/jetty-started.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Mixin the Start FileNoticeLifeCycleListener                     -->
diff --git a/jetty-distribution/src/main/resources/etc/jminix.xml b/jetty-distribution/src/main/resources/etc/jminix.xml
index 1be4757..15c699e 100644
--- a/jetty-distribution/src/main/resources/etc/jminix.xml
+++ b/jetty-distribution/src/main/resources/etc/jminix.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
  
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
   <Call name="addBean">
diff --git a/jetty-distribution/src/main/resources/etc/jolokia.xml b/jetty-distribution/src/main/resources/etc/jolokia.xml
index 575912f..b6e2404 100644
--- a/jetty-distribution/src/main/resources/etc/jolokia.xml
+++ b/jetty-distribution/src/main/resources/etc/jolokia.xml
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection">
   <Call name="addHandler">
     <Arg>
       <New class="org.eclipse.jetty.webapp.WebAppContext">
-	<Set name="contextPath">/jolokia</Set>
-	<Set name="war"><Property name="jetty.base" default="."/>/lib/jolokia/jolokia.war</Set>
-	<Set name="extractWAR">true</Set>
-	<Set name="copyWebDir">false</Set>
-	<Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
+        <Set name="contextPath">/jolokia</Set>
+        <Set name="war"><Property name="jetty.base" default="."/>/lib/jolokia/jolokia.war</Set>
+        <Set name="extractWAR">true</Set>
+        <Set name="copyWebDir">false</Set>
+        <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
       </New>
     </Arg>
   </Call>
diff --git a/jetty-distribution/src/main/resources/modules/hawtio.mod b/jetty-distribution/src/main/resources/modules/hawtio.mod
index 2dfb31b..f6d0d9d 100644
--- a/jetty-distribution/src/main/resources/modules/hawtio.mod
+++ b/jetty-distribution/src/main/resources/modules/hawtio.mod
@@ -22,7 +22,7 @@
 http://www.apache.org/licenses/LICENSE-2.0.html
 
 [ini-template]
-
+## Hawt.io configuration
 -Dhawtio.authenticationEnabled=false
 -Dhawtio.dirname=/dirname
 -Dhawtio.config.dir=${jetty.base}/etc/hawtio
diff --git a/jetty-distribution/src/main/resources/modules/jamon.mod b/jetty-distribution/src/main/resources/modules/jamon.mod
index 2aeb2ad..2d1f144 100644
--- a/jetty-distribution/src/main/resources/modules/jamon.mod
+++ b/jetty-distribution/src/main/resources/modules/jamon.mod
@@ -13,8 +13,8 @@
 
 [files]
 lib/jamon/
-http://central.maven.org/maven2/com/jamonapi/jamon/2.79/jamon-2.79.jar|lib/jamon/jamon-2.79.jar
-http://central.maven.org/maven2/com/jamonapi/jamon_war/2.79/jamon_war-2.79.war|lib/jamon/jamon.war
+maven://com.jamonapi/jamon/2.79|lib/jamon/jamon-2.79.jar
+maven://com.jamonapi/jamon_war/2.79/war|lib/jamon/jamon.war
 
 [lib]
 lib/jamon/**.jar
@@ -25,6 +25,7 @@
 http://jamonapi.sourceforge.net/JAMonLicense.html
 
 [ini-template]
+## Jamon Configuration
+# jamon.summaryLabels=demo
 jamon.summaryLabels=default, request.getStatus().contextpath.value.ms
-#jamon.summaryLabels=demo
 
diff --git a/jetty-distribution/src/main/resources/modules/jminix.mod b/jetty-distribution/src/main/resources/modules/jminix.mod
index b35d702..05788f0 100644
--- a/jetty-distribution/src/main/resources/modules/jminix.mod
+++ b/jetty-distribution/src/main/resources/modules/jminix.mod
@@ -11,21 +11,21 @@
 
 [files]
 lib/jminix/
-http://central.maven.org/maven2/org/jminix/jminix/1.1.0/jminix-1.1.0.jar|lib/jminix/jminix-1.1.0.jar
+maven://org.jminix/jminix/1.1.0|lib/jminix/jminix-1.1.0.jar
 http://maven.restlet.com/org/restlet/org.restlet/1.1.5/org.restlet-1.1.5.jar|lib/jminix/org.restlet-1.1.5.jar
 http://maven.restlet.com/org/restlet/org.restlet.ext.velocity/1.1.5/org.restlet.ext.velocity-1.1.5.jar|lib/jminix/org.restlet.ext.velocity-1.1.5.jar
-http://central.maven.org/maven2/org/apache/velocity/velocity/1.5/velocity-1.5.jar|lib/jminix/velocity-1.5.jar
-http://central.maven.org/maven2/oro/oro/2.0.8/oro-2.0.8.jar|lib/jminix/oro-2.0.8.jar
+maven://org.apache.velocity/velocity/1.5|lib/jminix/velocity-1.5.jar
+maven://oro/oro/2.0.8|lib/jminix/oro-2.0.8.jar
 http://maven.restlet.com/com/noelios/restlet/com.noelios.restlet/1.1.5/com.noelios.restlet-1.1.5.jar|lib/jminix/com.noelios.restlet-1.1.5.jar
 http://maven.restlet.com/com/noelios/restlet/com.noelios.restlet.ext.servlet/1.1.5/com.noelios.restlet.ext.servlet-1.1.5.jar|lib/jminix/com.noelios.restlet.ext.servlet-1.1.5.jar
-http://central.maven.org/maven2/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar|lib/jminix/commons-logging-1.1.1.jar
-http://repo2.maven.org/maven2/net/sf/json-lib/json-lib/2.2.3/json-lib-2.2.3-jdk15.jar|lib/jminix/json-lib-2.2.3-jdk15.jar
-http://central.maven.org/maven2/commons-lang/commons-lang/2.4/commons-lang-2.4.jar|lib/jminix/commons-lang-2.4.jar
-http://central.maven.org/maven2/commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar|lib/jminix/commons-beanutils-1.7.0.jar
-http://central.maven.org/maven2/commons-collections/commons-collections/3.2/commons-collections-3.2.jar|lib/jminix/commons-collections-3.2.jar
-http://central.maven.org/maven2/net/sf/ezmorph/ezmorph/1.0.6/ezmorph-1.0.6.jar|lib/jminix/ezmorph-1.0.6.jar
-http://central.maven.org/maven2/org/jgroups/jgroups/2.12.1.3.Final/jgroups-2.12.1.3.Final.jar|lib/jminix/jgroups-2.12.1.3.Final.jar
-http://central.maven.org/maven2/org/jasypt/jasypt/1.8/jasypt-1.8.jar|lib/jminix/jasypt-1.8.jar
+maven://commons-logging/commons-logging/1.1.1|lib/jminix/commons-logging-1.1.1.jar
+maven://net.sf.json-lib/json-lib/2.2.3/jar/jdk15|lib/jminix/json-lib-2.2.3-jdk15.jar
+maven://commons-lang/commons-lang/2.4|lib/jminix/commons-lang-2.4.jar
+maven://commons-beanutils/commons-beanutils/1.7.0|lib/jminix/commons-beanutils-1.7.0.jar
+maven://commons-collections/commons-collections/3.2|lib/jminix/commons-collections-3.2.jar
+maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar
+maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar
+maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar
 
 [lib]
 lib/jminix/**.jar
@@ -36,6 +36,6 @@
 http://www.apache.org/licenses/LICENSE-2.0
 
 [ini-template]
-# Jminix Configuration
+## Jminix Configuration
 jminix.port=8088
 
diff --git a/jetty-distribution/src/main/resources/modules/jolokia.mod b/jetty-distribution/src/main/resources/modules/jolokia.mod
index 876c2fc..da8ac8f 100644
--- a/jetty-distribution/src/main/resources/modules/jolokia.mod
+++ b/jetty-distribution/src/main/resources/modules/jolokia.mod
@@ -11,7 +11,7 @@
 etc/jolokia.xml
 
 [files]
-http://repo1.maven.org/maven2/org/jolokia/jolokia-war/1.2.2/jolokia-war-1.2.2.war|lib/jolokia/jolokia.war
+maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war
 
 [license]
 Jolokia is released under the Apache License 2.0
diff --git a/jetty-distribution/src/main/resources/modules/jsp.mod b/jetty-distribution/src/main/resources/modules/jsp.mod
index bb31ca7..a16cc93 100644
--- a/jetty-distribution/src/main/resources/modules/jsp.mod
+++ b/jetty-distribution/src/main/resources/modules/jsp.mod
@@ -5,17 +5,5 @@
 [depend]
 servlet
 annotations
-jsp-impl/${jsp-impl}-jsp
+apache-jsp
 
-[ini-template]
-# JSP Configuration
-
-# Select JSP implementation, choices are
-#   glassfish : The reference implementation 
-#               default in jetty <= 9.1
-#   apache    : The apache version 
-#               default jetty >= 9.2
-jsp-impl=apache
-
-# To use a non-jdk compiler for JSP compilation when using glassfish uncomment next line
-# -Dorg.apache.jasper.compiler.disablejsr199=true
diff --git a/jetty-distribution/src/main/resources/modules/jstl.mod b/jetty-distribution/src/main/resources/modules/jstl.mod
index cb06244..efc310a 100644
--- a/jetty-distribution/src/main/resources/modules/jstl.mod
+++ b/jetty-distribution/src/main/resources/modules/jstl.mod
@@ -1,14 +1,8 @@
 #
-# Jetty JSP Module
+# Jetty JSTL Module
 #
 
 [depend]
 jsp
-jsp-impl/${jsp-impl}-jstl
+apache-jstl
 
-[ini-template]
-# JSTL Configuration
-# The glassfish jsp-impl includes JSTL by default and this module
-# is not required to activate it.
-# The apache jsp-impl does not include JSTL by default and this module
-# is required to put JSTL on the container classpath
diff --git a/jetty-distribution/src/main/resources/modules/protonego.mod b/jetty-distribution/src/main/resources/modules/protonego.mod
deleted file mode 100644
index fbf4d08..0000000
--- a/jetty-distribution/src/main/resources/modules/protonego.mod
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Protocol Negotiatin Selection Module
-#
-
-[depend]
-protonego-impl/${protonego}
-
-[ini-template]
-# Protocol Negotiation Implementation Selection
-#  choices are:
-#    'npn'  : original implementation for SPDY (now deprecated)
-#    'alpn' : replacement for NPN, in use by current SPDY implementations
-#             and the future HTTP/2 spec
-#  Note: java 1.8+ are ALPN only.
-protonego=alpn
-
-# Configuration for NPN
-# npn.protocols=spdy/3,http/1.1
-# npn.defaultProtocol=http/1.1
-
-# Configuration for ALPN
-# alpn.protocols=h2-14,http/1.1
-# alpn.defaultProtocol=http/1.1
-
diff --git a/jetty-distribution/src/main/resources/modules/setuid.mod b/jetty-distribution/src/main/resources/modules/setuid.mod
index 64c9e23..41ef757 100644
--- a/jetty-distribution/src/main/resources/modules/setuid.mod
+++ b/jetty-distribution/src/main/resources/modules/setuid.mod
@@ -6,14 +6,14 @@
 server
 
 [lib]
-lib/setuid/jetty-setuid-java-1.0.1.jar
+lib/setuid/jetty-setuid-java-1.0.3.jar
 
 [xml]
 etc/jetty-setuid.xml
 
 [ini-template]
 ## SetUID Configuration
-# jetty.startServerAsPrivileged=false
-# jetty.username=jetty
-# jetty.groupname=jetty
-# jetty.umask=002
+# jetty.setuid.startServerAsPrivileged=false
+# jetty.setuid.userName=jetty
+# jetty.setuid.groupName=jetty
+# jetty.setuid.umask=002
diff --git a/jetty-fcgi/fcgi-client/pom.xml b/jetty-fcgi/fcgi-client/pom.xml
index 47a1651..72d5bf0 100644
--- a/jetty-fcgi/fcgi-client/pom.xml
+++ b/jetty-fcgi/fcgi-client/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.fcgi</groupId>
         <artifactId>fcgi-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java
index 8ebee57..cd3370f 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpChannelOverFCGI.java
@@ -79,6 +79,7 @@
         if (exchange != null)
         {
             version = exchange.getRequest().getVersion();
+            idle.onOpen();
             sender.send(exchange);
         }
     }
@@ -91,6 +92,7 @@
 
     protected boolean responseBegin(int code, String reason)
     {
+        idle.notIdle();
         HttpExchange exchange = getHttpExchange();
         if (exchange == null)
             return false;
@@ -106,12 +108,14 @@
 
     protected boolean responseHeaders()
     {
+       idle.notIdle();
         HttpExchange exchange = getHttpExchange();
         return exchange != null && receiver.responseHeaders(exchange);
     }
 
     protected boolean content(ByteBuffer buffer, Callback callback)
     {
+        idle.notIdle();
         HttpExchange exchange = getHttpExchange();
         if (exchange != null)
             return receiver.responseContent(exchange, buffer, callback);
@@ -151,6 +155,7 @@
     private class FCGIIdleTimeout extends IdleTimeout
     {
         private final HttpConnectionOverFCGI connection;
+        private boolean open;
 
         public FCGIIdleTimeout(HttpConnectionOverFCGI connection, long idleTimeout)
         {
@@ -160,6 +165,21 @@
         }
 
         @Override
+        public void onOpen()
+        {
+            open = true;
+            notIdle();
+            super.onOpen();
+        }
+
+        @Override
+        public void onClose()
+        {
+            super.onClose();
+            open = false;
+        }
+
+        @Override
         protected void onIdleExpired(TimeoutException timeout)
         {
             if (LOG.isDebugEnabled())
@@ -170,7 +190,7 @@
         @Override
         public boolean isOpen()
         {
-            return connection.getEndPoint().isOpen();
+            return open;
         }
     }
 }
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java
index b9882cd..929767d 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpClientTransportOverFCGI.java
@@ -30,7 +30,10 @@
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 
+@ManagedObject("The FastCGI/1.0 client transport")
 public class HttpClientTransportOverFCGI extends AbstractHttpClientTransport
 {
     private final boolean multiplexed;
@@ -53,6 +56,7 @@
         return multiplexed;
     }
 
+    @ManagedAttribute(value = "The scripts root directory", readonly = true)
     public String getScriptRoot()
     {
         return scriptRoot;
@@ -71,12 +75,17 @@
         HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
         @SuppressWarnings("unchecked")
         Promise<Connection> promise = (Promise<Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
-        HttpConnectionOverFCGI connection = new HttpConnectionOverFCGI(endPoint, destination, promise, isMultiplexed());
+        HttpConnectionOverFCGI connection = newHttpConnection(endPoint, destination, promise);
         if (LOG.isDebugEnabled())
             LOG.debug("Created {}", connection);
         return connection;
     }
 
+    protected HttpConnectionOverFCGI newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
+    {
+        return new HttpConnectionOverFCGI(endPoint, destination, promise, isMultiplexed());
+    }
+
     protected void customize(Request request, HttpFields fastCGIHeaders)
     {
         fastCGIHeaders.put(FCGI.Headers.DOCUMENT_ROOT, getScriptRoot());
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java
index aa3bb9b..0dfca0c 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpConnectionOverFCGI.java
@@ -31,6 +31,7 @@
 import org.eclipse.jetty.client.HttpConnection;
 import org.eclipse.jetty.client.HttpDestination;
 import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.SendFailure;
 import org.eclipse.jetty.client.api.Connection;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.Response;
@@ -57,27 +58,17 @@
     private final LinkedList<Integer> requests = new LinkedList<>();
     private final Map<Integer, HttpChannelOverFCGI> channels = new ConcurrentHashMap<>();
     private final AtomicBoolean closed = new AtomicBoolean();
-    private final Flusher flusher;
     private final HttpDestination destination;
     private final Promise<Connection> promise;
     private final boolean multiplexed;
+    private final Flusher flusher;
     private final Delegate delegate;
     private final ClientParser parser;
     private ByteBuffer buffer;
 
-    /**
-     * @deprecated use {@link #HttpConnectionOverFCGI(EndPoint, HttpDestination, Promise, boolean)} instead
-     */
-    @Deprecated
-    public HttpConnectionOverFCGI(EndPoint endPoint, HttpDestination destination, boolean multiplexed)
-    {
-        this(endPoint, destination, new Promise.Adapter<Connection>(), multiplexed);
-        throw new UnsupportedOperationException("Deprecated, use HttpConnectionOverFCGI(EndPoint, HttpDestination, Promise<Connection>, boolean) instead");
-    }
-
     public HttpConnectionOverFCGI(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise, boolean multiplexed)
     {
-        super(endPoint, destination.getHttpClient().getExecutor(), destination.getHttpClient().isDispatchIO());
+        super(endPoint, destination.getHttpClient().getExecutor());
         this.destination = destination;
         this.promise = promise;
         this.multiplexed = multiplexed;
@@ -92,15 +83,20 @@
         return destination;
     }
 
+    protected Flusher getFlusher()
+    {
+        return flusher;
+    }
+
     @Override
     public void send(Request request, Response.CompleteListener listener)
     {
         delegate.send(request, listener);
     }
 
-    protected void send(HttpExchange exchange)
+    protected SendFailure send(HttpExchange exchange)
     {
-        delegate.send(exchange);
+        return delegate.send(exchange);
     }
 
     @Override
@@ -114,61 +110,68 @@
     @Override
     public void onFillable()
     {
+        buffer = acquireBuffer();
+        process(buffer);
+    }
+
+    private ByteBuffer acquireBuffer()
+    {
         HttpClient client = destination.getHttpClient();
         ByteBufferPool bufferPool = client.getByteBufferPool();
-        buffer = bufferPool.acquire(client.getResponseBufferSize(), true);
-        process();
+        return bufferPool.acquire(client.getResponseBufferSize(), true);
     }
 
-    private void process()
+    private void releaseBuffer(ByteBuffer buffer)
     {
-        if (readAndParse())
-        {
-            HttpClient client = destination.getHttpClient();
-            ByteBufferPool bufferPool = client.getByteBufferPool();
-            bufferPool.release(buffer);
-            // Don't linger the buffer around if we are idle.
-            buffer = null;
-        }
+        assert this.buffer == buffer;
+        HttpClient client = destination.getHttpClient();
+        ByteBufferPool bufferPool = client.getByteBufferPool();
+        bufferPool.release(buffer);
+        this.buffer = null;
     }
 
-    private boolean readAndParse()
+    private void process(ByteBuffer buffer)
     {
-        EndPoint endPoint = getEndPoint();
-        ByteBuffer buffer = this.buffer;
-        while (true)
+        try
         {
-            try
+            EndPoint endPoint = getEndPoint();
+            boolean looping = false;
+            while (true)
             {
-                if (parse(buffer))
-                    return false;
+                if (!looping && parse(buffer))
+                    return;
 
                 int read = endPoint.fill(buffer);
-                if (LOG.isDebugEnabled()) // Avoid boxing of variable 'read'.
+                if (LOG.isDebugEnabled())
                     LOG.debug("Read {} bytes from {}", read, endPoint);
+
                 if (read > 0)
                 {
                     if (parse(buffer))
-                        return false;
+                        return;
                 }
                 else if (read == 0)
                 {
+                    releaseBuffer(buffer);
                     fillInterested();
-                    return true;
+                    return;
                 }
                 else
                 {
+                    releaseBuffer(buffer);
                     shutdown();
-                    return true;
+                    return;
                 }
+
+                looping = true;
             }
-            catch (Exception x)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug(x);
-                close(x);
-                return false;
-            }
+        }
+        catch (Exception x)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(x);
+            releaseBuffer(buffer);
+            close(x);
         }
     }
 
@@ -184,13 +187,17 @@
         if (channels.isEmpty())
             close();
         else
-            failAndClose(new EOFException());
+            failAndClose(new EOFException(String.valueOf(getEndPoint())));
     }
 
     @Override
-    protected boolean onReadTimeout()
+    public boolean onIdleExpired()
     {
-        close(new TimeoutException());
+        boolean close = delegate.onIdleTimeout();
+        if (multiplexed)
+            close &= isFillInterested();
+        if (close)
+            close(new TimeoutException("Idle timeout " + getEndPoint().getIdleTimeout() + "ms"));
         return false;
     }
 
@@ -200,6 +207,11 @@
         destination.release(this);
     }
 
+    public boolean isClosed()
+    {
+        return closed.get();
+    }
+
     @Override
     public void close()
     {
@@ -215,10 +227,10 @@
             getHttpDestination().close(this);
             getEndPoint().shutdownOutput();
             if (LOG.isDebugEnabled())
-                LOG.debug("{} oshut", this);
+                LOG.debug("Shutdown {}", this);
             getEndPoint().close();
             if (LOG.isDebugEnabled())
-                LOG.debug("{} closed", this);
+                LOG.debug("Closed {}", this);
 
             abort(failure);
         }
@@ -273,6 +285,11 @@
         }
     }
 
+    protected HttpChannelOverFCGI newHttpChannel(int id, Request request)
+    {
+        return new HttpChannelOverFCGI(this, getFlusher(), id, request.getIdleTimeout());
+    }
+
     @Override
     public String toString()
     {
@@ -291,19 +308,17 @@
         }
 
         @Override
-        protected void send(HttpExchange exchange)
+        protected SendFailure send(HttpExchange exchange)
         {
             Request request = exchange.getRequest();
             normalizeRequest(request);
 
             // FCGI may be multiplexed, so create one channel for each request.
             int id = acquireRequest();
-            HttpChannelOverFCGI channel = new HttpChannelOverFCGI(HttpConnectionOverFCGI.this, flusher, id, request.getIdleTimeout());
+            HttpChannelOverFCGI channel = newHttpChannel(id, request);
             channels.put(id, channel);
-            if (channel.associate(exchange))
-                channel.send();
-            else
-                channel.release();
+
+            return send(channel, exchange);
         }
 
         @Override
@@ -312,6 +327,11 @@
             HttpConnectionOverFCGI.this.close();
         }
 
+        protected void close(Throwable failure)
+        {
+            HttpConnectionOverFCGI.this.close(failure);
+        }
+
         @Override
         public String toString()
         {
@@ -368,7 +388,7 @@
                             {
                                 if (LOG.isDebugEnabled())
                                     LOG.debug("Content consumed asynchronously, resuming processing");
-                                process();
+                                process(HttpConnectionOverFCGI.this.buffer);
                             }
 
                             @Override
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java
index 4287341..a6ac2cc 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpDestinationOverFCGI.java
@@ -22,6 +22,7 @@
 import org.eclipse.jetty.client.HttpExchange;
 import org.eclipse.jetty.client.Origin;
 import org.eclipse.jetty.client.PoolingHttpDestination;
+import org.eclipse.jetty.client.SendFailure;
 
 public class HttpDestinationOverFCGI extends PoolingHttpDestination<HttpConnectionOverFCGI>
 {
@@ -31,8 +32,8 @@
     }
 
     @Override
-    protected void send(HttpConnectionOverFCGI connection, HttpExchange exchange)
+    protected SendFailure send(HttpConnectionOverFCGI connection, HttpExchange exchange)
     {
-        connection.send(exchange);
+        return connection.send(exchange);
     }
 }
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java
index f24a358..eaa7423 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/HttpSenderOverFCGI.java
@@ -99,7 +99,7 @@
         int id = getHttpChannel().getRequest();
         boolean hasContent = content.hasContent();
         Generator.Result headersResult = generator.generateRequestHeaders(id, fcgiHeaders,
-                hasContent ? callback : Callback.Adapter.INSTANCE);
+                hasContent ? callback : Callback.NOOP);
         if (hasContent)
         {
             getHttpChannel().flush(headersResult);
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java
index 6d19184..bf7f403 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/client/http/MultiplexHttpDestinationOverFCGI.java
@@ -22,6 +22,7 @@
 import org.eclipse.jetty.client.HttpExchange;
 import org.eclipse.jetty.client.MultiplexHttpDestination;
 import org.eclipse.jetty.client.Origin;
+import org.eclipse.jetty.client.SendFailure;
 
 public class MultiplexHttpDestinationOverFCGI extends MultiplexHttpDestination<HttpConnectionOverFCGI>
 {
@@ -31,8 +32,8 @@
     }
 
     @Override
-    protected void send(HttpConnectionOverFCGI connection, HttpExchange exchange)
+    protected SendFailure send(HttpConnectionOverFCGI connection, HttpExchange exchange)
     {
-        connection.send(exchange);
+        return connection.send(exchange);
     }
 }
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java
index b6a6ed9..c033fa2 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ClientGenerator.java
@@ -20,6 +20,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -46,7 +47,7 @@
     {
         request &= 0xFF_FF;
 
-        Charset utf8 = Charset.forName("UTF-8");
+        final Charset utf8 = StandardCharsets.UTF_8;
         List<byte[]> bytes = new ArrayList<>(fields.size() * 2);
         int fieldsLength = 0;
         for (HttpField field : fields)
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java
index a28f8ed..666a37b 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Generator.java
@@ -80,6 +80,7 @@
         return result;
     }
 
+    // TODO: rewrite this class in light of ByteBufferPool.Lease.
     public static class Result implements Callback
     {
         private final List<Callback> callbacks = new ArrayList<>(2);
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java
index 635ab8b..9e75c56 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/ServerGenerator.java
@@ -20,6 +20,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -54,7 +55,7 @@
     {
         request &= 0xFF_FF;
 
-        Charset utf8 = Charset.forName("UTF-8");
+        final Charset utf8 = StandardCharsets.UTF_8;
         List<byte[]> bytes = new ArrayList<>(fields.size() * 2);
         int length = 0;
 
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java
index e6f9a19..cac8caf 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/BeginRequestContentParser.java
@@ -22,6 +22,16 @@
 
 import org.eclipse.jetty.fcgi.FCGI;
 
+/**
+ * <p>Parser for the BEGIN_REQUEST frame body.</p>
+ * <pre>
+ * struct begin_request_body {
+ *     ushort role;
+ *     ubyte flags;
+ *     ubyte[5] reserved;
+ * }
+ * </pre>
+ */
 public class BeginRequestContentParser extends ContentParser
 {
     private final ServerParser.Listener listener;
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java
index eb28a8d..be7a5e1 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/EndRequestContentParser.java
@@ -20,6 +20,16 @@
 
 import java.nio.ByteBuffer;
 
+/**
+ * <p>Parser for the END_REQUEST frame body.</p>
+ * <pre>
+ * struct end_request_body {
+ *     uint applicationStatus;
+ *     ubyte protocolStatus;
+ *     ubyte[3] reserved;
+ * }
+ * </pre>
+ */
 public class EndRequestContentParser extends ContentParser
 {
     private final Parser.Listener listener;
@@ -80,7 +90,7 @@
                     }
                     else
                     {
-                        state = State.APPLICATION_BYTES;
+                        state = State.RESERVED_BYTES;
                         cursor = 0;
                         break;
                     }
@@ -88,7 +98,7 @@
                 case RESERVED_BYTES:
                 {
                     buffer.get();
-                    if (++cursor == 0)
+                    if (++cursor == 3)
                     {
                         onEnd();
                         reset();
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java
index 3b3d399..8f9e99b 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/HeaderParser.java
@@ -21,9 +21,28 @@
 import java.nio.ByteBuffer;
 
 import org.eclipse.jetty.fcgi.FCGI;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
+/**
+ * <p>Parser for FastCGI frame headers.</p>
+ * <pre>
+ * struct frame_header {
+ *     ubyte version;
+ *     ubyte type;
+ *     ushort requestId;
+ *     ushort contentLength;
+ *     ubyte paddingLength;
+ *     ubyte reserved;
+ * }
+ * </pre>
+ *
+ * @see Parser
+ */
 public class HeaderParser
 {
+    private static final Logger LOG = Log.getLogger(Parser.class);
+
     private State state = State.VERSION;
     private int cursor;
     private int version;
@@ -109,6 +128,8 @@
                 case RESERVED:
                 {
                     buffer.get();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Parsed request {} header {} length={}", getRequest(), getFrameType(), getContentLength());
                     return true;
                 }
                 default:
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java
index 00b1f78..cf6b109 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ParamsContentParser.java
@@ -20,11 +20,44 @@
 
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
+/**
+ * <p>Parser for the PARAMS frame body.</p>
+ * <pre>
+ * struct small_name_small_value_params_body {
+ *     ubyte nameLength;
+ *     ubyte valueLength;
+ *     ubyte[] nameBytes;
+ *     ubyte[] valueBytes;
+ * }
+ *
+ * struct small_name_large_value_params_body {
+ *     ubyte nameLength;
+ *     uint valueLength;
+ *     ubyte[] nameBytes;
+ *     ubyte[] valueBytes;
+ * }
+ *
+ * struct large_name_small_value_params_body {
+ *     uint nameLength;
+ *     ubyte valueLength;
+ *     ubyte[] nameBytes;
+ *     ubyte[] valueBytes;
+ * }
+ *
+ * struct large_name_large_value_params_body {
+ *     uint nameLength;
+ *     uint valueLength;
+ *     ubyte[] nameBytes;
+ *     ubyte[] valueBytes;
+ * }
+ * </pre>
+ */
 public class ParamsContentParser extends ContentParser
 {
     private static final Logger LOG = Log.getLogger(ParamsContentParser.class);
@@ -179,7 +212,7 @@
                 }
                 case PARAM:
                 {
-                    Charset utf8 = Charset.forName("UTF-8");
+                    Charset utf8 = StandardCharsets.UTF_8;
                     onParam(new String(nameBytes, utf8), new String(valueBytes, utf8));
                     partialReset();
                     if (length == 0)
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java
index 30c1405..ad698c4 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/Parser.java
@@ -22,9 +22,33 @@
 
 import org.eclipse.jetty.fcgi.FCGI;
 import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
+/**
+ * <p>The FastCGI protocol exchanges <em>frames</em>.</p>
+ * <pre>
+ * struct frame {
+ *     ubyte version;
+ *     ubyte type;
+ *     ushort requestId;
+ *     ushort contentLength;
+ *     ubyte paddingLength;
+ *     ubyte reserved;
+ *     ubyte[] content;
+ *     ubyte[] padding;
+ * }
+ * </pre>
+ * <p>Depending on the {@code type}, the content may have a different format,
+ * so there are specialized content parsers.</p>
+ *
+ * @see HeaderParser
+ * @see ContentParser
+ */
 public abstract class Parser
 {
+    private static final Logger LOG = Log.getLogger(Parser.class);
+
     protected final HeaderParser headerParser = new HeaderParser();
     private State state = State.HEADER;
     private int padding;
@@ -56,6 +80,9 @@
                     else
                     {
                         ContentParser.Result result = contentParser.parse(buffer);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Parsed request {} content {} result={}", headerParser.getRequest(), headerParser.getFrameType(), result);
+
                         if (result == ContentParser.Result.PENDING)
                         {
                             // Not enough data, signal to read/parse more.
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java
index 125ea28..99cc51e 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/ResponseContentParser.java
@@ -18,11 +18,13 @@
 
 package org.eclipse.jetty.fcgi.parser;
 
+import java.io.EOFException;
 import java.nio.ByteBuffer;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.jetty.fcgi.FCGI;
+import org.eclipse.jetty.http.BadMessageException;
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
@@ -32,6 +34,14 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
+/**
+ * <p>The parser for STDOUT type frame bodies.</p>
+ * <p>STDOUT frame bodies contain both the HTTP headers (but not the response line)
+ * and the HTTP content (either Content-Length delimited or chunked).</p>
+ * <p>For this reason, a special HTTP parser is used to parse the frames body.
+ * This special HTTP parser is configured to skip the response line, and to
+ * parse HTTP headers and HTTP content.</p>
+ */
 public class ResponseContentParser extends StreamContentParser
 {
     private static final Logger LOG = Log.getLogger(ResponseContentParser.class);
@@ -71,7 +81,7 @@
         parsers.remove(request);
     }
 
-    private class ResponseParser implements HttpParser.ResponseHandler<ByteBuffer>
+    private class ResponseParser implements HttpParser.ResponseHandler
     {
         private final HttpFields fields = new HttpFields();
         private ClientParser.Listener listener;
@@ -89,12 +99,12 @@
 
         public boolean parse(ByteBuffer buffer)
         {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Response {} {} content {} {}", request, FCGI.StreamType.STD_OUT, state, buffer);
-
             int remaining = buffer.remaining();
             while (remaining > 0)
             {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Response {} {}, state {} {}", request, FCGI.StreamType.STD_OUT, state, buffer);
+
                 switch (state)
                 {
                     case HEADERS:
@@ -154,7 +164,7 @@
         }
 
         @Override
-        public boolean parsedHeader(HttpField httpField)
+        public void parsedHeader(HttpField httpField)
         {
             try
             {
@@ -190,7 +200,6 @@
                 if (LOG.isDebugEnabled())
                     LOG.debug("Exception while invoking listener " + listener, x);
             }
-            return false;
         }
 
         private void notifyBegin(int code, String reason)
@@ -246,12 +255,12 @@
         {
             if (!seenResponseCode)
             {
-                // No Status header but we have other headers, assume 200 OK
+                // No Status header but we have other headers, assume 200 OK.
                 notifyBegin(200, "OK");
                 notifyHeaders(fields);
             }
             notifyHeaders();
-            // Return from parsing so that we can parse the content
+            // Return from HTTP parsing so that we can parse the content.
             return true;
         }
 
@@ -278,28 +287,41 @@
         @Override
         public boolean messageComplete()
         {
-            // Return from parsing so that we can parse the next headers or the raw content.
-            // No need to notify the listener because it will be done by FCGI_END_REQUEST.
-            return true;
+            // No need to notify the end of the response to the
+            // listener because it will be done by FCGI_END_REQUEST.
+            return false;
         }
 
         @Override
         public void earlyEOF()
         {
-            // TODO
+            fail(new EOFException());
         }
 
         @Override
         public void badMessage(int status, String reason)
         {
-            // TODO
+            fail(new BadMessageException(status, reason));
+        }
+
+        protected void fail(Throwable failure)
+        {
+            try
+            {
+                listener.onFailure(request, failure);
+            }
+            catch (Throwable x)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Exception while invoking listener " + listener, x);
+            }
         }
     }
 
     // Methods overridden to make them visible here
     private static class FCGIHttpParser extends HttpParser
     {
-        private FCGIHttpParser(ResponseHandler<ByteBuffer> handler)
+        private FCGIHttpParser(ResponseHandler handler)
         {
             super(handler, 65 * 1024, true);
             reset();
diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java
index 288751e..fd16813 100644
--- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java
+++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/parser/StreamContentParser.java
@@ -24,6 +24,10 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
+/**
+ * <p>A stream content parser parses frame bodies of type STDIN, STDOUT and STDERR.</p>
+ * <p>STDOUT frame bodies are handled specially by {@link ResponseContentParser}.
+ */
 public class StreamContentParser extends ContentParser
 {
     private static final Logger LOG = Log.getLogger(StreamContentParser.class);
diff --git a/jetty-fcgi/fcgi-server/pom.xml b/jetty-fcgi/fcgi-server/pom.xml
index 76feb19..15921a3 100644
--- a/jetty-fcgi/fcgi-server/pom.xml
+++ b/jetty-fcgi/fcgi-server/pom.xml
@@ -1,73 +1,67 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.fcgi</groupId>
-        <artifactId>fcgi-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
+  <parent>
+    <groupId>org.eclipse.jetty.fcgi</groupId>
+    <artifactId>fcgi-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
 
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>fcgi-server</artifactId>
-    <name>Jetty :: FastCGI :: Server</name>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>fcgi-server</artifactId>
+  <name>Jetty :: FastCGI :: Server</name>
 
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name>
-    </properties>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name>
+  </properties>
 
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <configuration>
-                            <descriptorRefs>
-                                <descriptorRef>config</descriptorRef>
-                            </descriptorRefs>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+  <build>
+    <plugins>
+    </plugins>
+  </build>
 
-    <dependencies>
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.fcgi</groupId>
-            <artifactId>fcgi-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-proxy</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-servlet</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
+  <dependencies>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.fcgi</groupId>
+      <artifactId>fcgi-client</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-proxy</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-alpn-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
 </project>
diff --git a/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod b/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod
index e837b00..14152d5 100644
--- a/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod
+++ b/jetty-fcgi/fcgi-server/src/main/config/modules/fcgi.mod
@@ -12,4 +12,4 @@
 
 [ini-template]
 ## For configuration of FastCGI contexts, see
-## TODO: documentation url here
+## https://www.eclipse.org/jetty/documentation/current/fastcgi.html
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java
index 5b42b34..59f83e9 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpChannelOverFCGI.java
@@ -18,41 +18,41 @@
 
 package org.eclipse.jetty.fcgi.server;
 
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.fcgi.FCGI;
+import org.eclipse.jetty.http.HostPortHttpField;
 import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpInput;
 import org.eclipse.jetty.server.HttpTransport;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-public class HttpChannelOverFCGI extends HttpChannel<ByteBuffer>
+public class HttpChannelOverFCGI extends HttpChannel
 {
     private static final Logger LOG = Log.getLogger(HttpChannelOverFCGI.class);
 
-    private final List<HttpField> fields = new ArrayList<>();
+    private final HttpFields fields = new HttpFields();
     private final Dispatcher dispatcher;
     private String method;
     private String path;
     private String query;
     private String version;
+    private HostPortHttpField hostPort;
 
-    public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input)
+    public HttpChannelOverFCGI(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport)
     {
-        super(connector, configuration, endPoint, transport, input);
+        super(connector, configuration, endPoint, transport);
         this.dispatcher = new Dispatcher(connector.getExecutor(), this);
     }
 
@@ -67,26 +67,27 @@
         else if (FCGI.Headers.SERVER_PROTOCOL.equalsIgnoreCase(field.getName()))
             version = field.getValue();
         else
-            fields.add(field);
+            processField(field);
     }
 
-    @Override
-    public boolean headerComplete()
+    private void processField(HttpField field)
+    {
+        HttpField httpField = convertHeader(field);
+        if (httpField != null)
+        {
+            fields.add(httpField);
+            if (HttpHeader.HOST.is(httpField.getName()))
+                hostPort = (HostPortHttpField)httpField;
+        }
+    }
+
+    public void onRequest()
     {
         String uri = path;
         if (query != null && query.length() > 0)
             uri += "?" + query;
-        startRequest(HttpMethod.fromString(method), method, ByteBuffer.wrap(uri.getBytes(StandardCharsets.UTF_8)),
-                HttpVersion.fromString(version));
-
-        for (HttpField fcgiField : fields)
-        {
-            HttpField httpField = convertHeader(fcgiField);
-            if (httpField != null)
-                parsedHeader(httpField);
-        }
-
-        return super.headerComplete();
+        // TODO https?
+        onRequest(new MetaData.Request(method, HttpScheme.HTTP.asString(), hostPort, uri, HttpVersion.fromString(version), fields,Long.MIN_VALUE));
     }
 
     private HttpField convertHeader(HttpField field)
@@ -105,7 +106,11 @@
                 httpName.append(Character.toUpperCase(part.charAt(0)));
                 httpName.append(part.substring(1).toLowerCase(Locale.ENGLISH));
             }
-            return new HttpField(httpName.toString(), field.getValue());
+            String headerName = httpName.toString();
+            if (HttpHeader.HOST.is(headerName))
+                return new HostPortHttpField(field.getValue());
+            else
+                return new HttpField(httpName.toString(), field.getValue());
         }
         return null;
     }
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java
index 9b50961..5856081 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/HttpTransportOverFCGI.java
@@ -23,9 +23,9 @@
 import org.eclipse.jetty.fcgi.generator.Flusher;
 import org.eclipse.jetty.fcgi.generator.Generator;
 import org.eclipse.jetty.fcgi.generator.ServerGenerator;
-import org.eclipse.jetty.http.HttpGenerator;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.server.HttpTransport;
 import org.eclipse.jetty.util.BufferUtil;
@@ -48,16 +48,64 @@
     }
 
     @Override
-    public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
+    public boolean isOptimizedForDirectBuffers()
     {
-        boolean head = this.head = info.isHead();
-        boolean shutdown = this.shutdown = info.getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
+        return false;
+    }
+    
+    @Override
+    public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
+    {
+        if (info!=null)
+            commit(info,head,content,lastContent,callback);
+        else
+        {
+            if (head)
+            {
+                if (lastContent)
+                {
+                    Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback);
+                    flusher.flush(result);
+                }
+                else
+                {
+                    // Skip content generation
+                    callback.succeeded();
+                }
+            }
+            else
+            {
+                Generator.Result result = generateResponseContent(content, lastContent, callback);
+                flusher.flush(result);
+            }
+
+            if (lastContent && shutdown)
+                flusher.shutdown();
+        }
+    }
+
+    @Override
+    public boolean isPushSupported()
+    {
+        return false;
+    }
+    
+    @Override
+    public void push(org.eclipse.jetty.http.MetaData.Request request)
+    {   
+        // LOG.debug("ignore push in {}",this);
+    }
+    
+    private void commit(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
+    {
+        this.head = head;
+        boolean shutdown = this.shutdown = info.getFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
 
         if (head)
         {
             if (lastContent)
             {
-                Generator.Result headersResult = generateResponseHeaders(info, Callback.Adapter.INSTANCE);
+                Generator.Result headersResult = generateResponseHeaders(info, Callback.NOOP);
                 Generator.Result contentResult = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback);
                 flusher.flush(headersResult, contentResult);
             }
@@ -69,7 +117,7 @@
         }
         else
         {
-            Generator.Result headersResult = generateResponseHeaders(info, Callback.Adapter.INSTANCE);
+            Generator.Result headersResult = generateResponseHeaders(info, Callback.NOOP);
             Generator.Result contentResult = generateResponseContent(content, lastContent, callback);
             flusher.flush(headersResult, contentResult);
         }
@@ -78,35 +126,9 @@
             flusher.shutdown();
     }
 
-    @Override
-    public void send(ByteBuffer content, boolean lastContent, Callback callback)
+    protected Generator.Result generateResponseHeaders(MetaData.Response info, Callback callback)
     {
-        if (head)
-        {
-            if (lastContent)
-            {
-                Generator.Result result = generateResponseContent(BufferUtil.EMPTY_BUFFER, true, callback);
-                flusher.flush(result);
-            }
-            else
-            {
-                // Skip content generation
-                callback.succeeded();
-            }
-        }
-        else
-        {
-            Generator.Result result = generateResponseContent(content, lastContent, callback);
-            flusher.flush(result);
-        }
-
-        if (lastContent && shutdown)
-            flusher.shutdown();
-    }
-
-    protected Generator.Result generateResponseHeaders(HttpGenerator.ResponseInfo info, Callback callback)
-    {
-        return generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getHttpFields(), callback);
+        return generator.generateResponseHeaders(request, info.getStatus(), info.getReason(), info.getFields(), callback);
     }
 
     protected Generator.Result generateResponseContent(ByteBuffer buffer, boolean lastContent, Callback callback)
@@ -115,13 +137,13 @@
     }
 
     @Override
-    public void abort()
+    public void abort(Throwable failure)
     {
         aborted = true;
     }
 
     @Override
-    public void completed()
+    public void onCompleted()
     {
     }
 }
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java
index ee196e7..c0af8c5 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/ServerFCGIConnection.java
@@ -29,9 +29,9 @@
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.ByteBufferQueuedHttpInput;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpInput;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
@@ -82,11 +82,13 @@
                 }
                 else if (read == 0)
                 {
+                    bufferPool.release(buffer);
                     fillInterested();
                     break;
                 }
                 else
                 {
+                    bufferPool.release(buffer);
                     shutdown();
                     break;
                 }
@@ -96,11 +98,8 @@
         {
             if (LOG.isDebugEnabled())
                 LOG.debug(x);
-            // TODO: fail and close ?
-        }
-        finally
-        {
             bufferPool.release(buffer);
+            // TODO: fail and close ?
         }
     }
 
@@ -122,8 +121,7 @@
         {
             // TODO: handle flags
             HttpChannelOverFCGI channel = new HttpChannelOverFCGI(connector, configuration, getEndPoint(),
-                    new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request, sendStatus200),
-                    new ByteBufferQueuedHttpInput());
+                    new HttpTransportOverFCGI(connector.getByteBufferPool(), flusher, request, sendStatus200));
             HttpChannelOverFCGI existing = channels.putIfAbsent(request, channel);
             if (existing != null)
                 throw new IllegalStateException();
@@ -149,8 +147,8 @@
                 LOG.debug("Request {} headers on {}", request, channel);
             if (channel != null)
             {
-                if (channel.headerComplete())
-                    channel.dispatch();
+                channel.onRequest();
+                channel.dispatch();
             }
         }
 
@@ -162,8 +160,9 @@
                 LOG.debug("Request {} {} content {} on {}", request, stream, buffer, channel);
             if (channel != null)
             {
-                if (channel.content(buffer))
-                    channel.dispatch();
+                ByteBuffer copy = ByteBuffer.allocate(buffer.remaining());
+                copy.put(buffer).flip();
+                channel.onContent(new HttpInput.Content(copy));
             }
             return false;
         }
@@ -176,8 +175,7 @@
                 LOG.debug("Request {} end on {}", request, channel);
             if (channel != null)
             {
-                if (channel.messageComplete())
-                    channel.dispatch();
+                channel.onRequestComplete();
             }
         }
 
@@ -189,7 +187,7 @@
                 LOG.debug("Request {} failure on {}: {}", request, channel, failure);
             if (channel != null)
             {
-                channel.badMessage(400, failure.toString());
+                channel.onBadMessage(400, failure.toString());
             }
         }
     }
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
index 38e1766..9fb85f9 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServlet.java
@@ -19,29 +19,35 @@
 package org.eclipse.jetty.fcgi.server.proxy;
 
 import java.net.URI;
+import java.util.List;
+import java.util.TreeMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.fcgi.FCGI;
 import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI;
+import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.proxy.AsyncProxyServlet;
-import org.eclipse.jetty.proxy.ProxyServlet;
 
 /**
- * Specific implementation of {@link ProxyServlet.Transparent} for FastCGI.
- * <p />
+ * Specific implementation of {@link org.eclipse.jetty.proxy.AsyncProxyServlet.Transparent} for FastCGI.
+ * <p>
  * This servlet accepts a HTTP request and transforms it into a FastCGI request
  * that is sent to the FastCGI server specified in the <code>proxyTo</code>
  * init-param.
- * <p />
+ * <p>
  * This servlet accepts two additional init-params:
  * <ul>
  *     <li><code>scriptRoot</code>, mandatory, that must be set to the directory where
@@ -64,6 +70,7 @@
 {
     public static final String SCRIPT_ROOT_INIT_PARAM = "scriptRoot";
     public static final String SCRIPT_PATTERN_INIT_PARAM = "scriptPattern";
+    public static final String ORIGINAL_URI_ATTRIBUTE_INIT_PARAM = "originalURIAttribute";
     public static final String FASTCGI_HTTPS_INIT_PARAM = "fastCGI.HTTPS";
 
     private static final String REMOTE_ADDR_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".remoteAddr";
@@ -75,6 +82,7 @@
     private static final String REQUEST_URI_ATTRIBUTE = FastCGIProxyServlet.class.getName() + ".requestURI";
 
     private Pattern scriptPattern;
+    private String originalURIAttribute;
     private boolean fcgiHTTPS;
 
     @Override
@@ -87,6 +95,8 @@
             value = "(.+?\\.php)";
         scriptPattern = Pattern.compile(value);
 
+        originalURIAttribute = getInitParameter(ORIGINAL_URI_ATTRIBUTE_INIT_PARAM);
+
         fcgiHTTPS = Boolean.parseBoolean(getInitParameter(FASTCGI_HTTPS_INIT_PARAM));
     }
 
@@ -101,33 +111,69 @@
     }
 
     @Override
-    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request)
+    protected void sendProxyRequest(HttpServletRequest request, HttpServletResponse proxyResponse, Request proxyRequest)
     {
         proxyRequest.attribute(REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr());
         proxyRequest.attribute(REMOTE_PORT_ATTRIBUTE, String.valueOf(request.getRemotePort()));
         proxyRequest.attribute(SERVER_NAME_ATTRIBUTE, request.getServerName());
         proxyRequest.attribute(SERVER_ADDR_ATTRIBUTE, request.getLocalAddr());
         proxyRequest.attribute(SERVER_PORT_ATTRIBUTE, String.valueOf(request.getLocalPort()));
-
         proxyRequest.attribute(SCHEME_ATTRIBUTE, request.getScheme());
 
-        // If we are forwarded or included, retain the original request URI.
-        String originalPath = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
-        String originalQuery = (String)request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING);
-        if (originalPath == null)
+        // Has the original URI been rewritten ?
+        String originalURI = null;
+        if (originalURIAttribute != null)
+            originalURI = (String)request.getAttribute(originalURIAttribute);
+
+        if (originalURI == null)
         {
-            originalPath = (String)request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
-            originalQuery = (String)request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING);
-        }
-        if (originalPath != null)
-        {
-            String originalURI = originalPath;
-            if (originalQuery != null)
-                originalURI += "?" + originalQuery;
-            proxyRequest.attribute(REQUEST_URI_ATTRIBUTE, originalURI);
+            // If we are forwarded or included, retain the original request URI.
+            String originalPath = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
+            String originalQuery = (String)request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING);
+            if (originalPath == null)
+            {
+                originalPath = (String)request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
+                originalQuery = (String)request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING);
+            }
+            if (originalPath != null)
+            {
+                originalURI = originalPath;
+                if (originalQuery != null)
+                    originalURI += "?" + originalQuery;
+            }
         }
 
-        super.customizeProxyRequest(proxyRequest, request);
+        if (originalURI != null)
+            proxyRequest.attribute(REQUEST_URI_ATTRIBUTE, originalURI);
+
+        // If the Host header is missing, add it.
+        if (!proxyRequest.getHeaders().containsKey(HttpHeader.HOST.asString()))
+        {
+            String host = request.getServerName();
+            int port = request.getServerPort();
+            if (!getHttpClient().isDefaultPort(request.getScheme(), port))
+                host += ":" + port;
+            proxyRequest.header(HttpHeader.HOST, host);
+            proxyRequest.header(HttpHeader.X_FORWARDED_HOST, host);
+        }
+
+        // PHP does not like multiple Cookie headers, coalesce into one.
+        List<String> cookies = proxyRequest.getHeaders().getValuesList(HttpHeader.COOKIE.asString());
+        if (cookies.size() > 1)
+        {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < cookies.size(); ++i)
+            {
+                if (i > 0)
+                    builder.append("; ");
+                String cookie = cookies.get(i);
+                builder.append(cookie);
+            }
+            proxyRequest.header(HttpHeader.COOKIE, null);
+            proxyRequest.header(HttpHeader.COOKIE, builder.toString());
+        }
+
+        super.sendProxyRequest(request, proxyResponse, proxyRequest);
     }
 
     protected void customizeFastCGIHeaders(Request proxyRequest, HttpFields fastCGIHeaders)
@@ -183,6 +229,16 @@
         {
             super.customize(request, fastCGIHeaders);
             customizeFastCGIHeaders(request, fastCGIHeaders);
+            if (_log.isDebugEnabled())
+            {
+                TreeMap<String, String> fcgi = new TreeMap<>();
+                for (HttpField field : fastCGIHeaders)
+                    fcgi.put(field.getName(), field.getValue());
+                String eol = System.lineSeparator();
+                _log.debug("FastCGI variables{}{}", eol, fcgi.entrySet().stream()
+                        .map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue()))
+                        .collect(Collectors.joining(eol)));
+            }
         }
     }
 }
diff --git a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java
index 1ebb1f0..92b77b7 100644
--- a/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java
+++ b/jetty-fcgi/fcgi-server/src/main/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilter.java
@@ -24,6 +24,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -36,11 +37,11 @@
 
 /**
  * Inspired by nginx's try_files functionality.
- * <p />
+ * <p>
  * This filter accepts the <code>files</code> init-param as a list of space-separated
  * file URIs. The special token <code>$path</code> represents the current request URL's
  * path (the portion after the context path).
- * <p />
+ * <p>
  * Typical example of how this filter can be configured is the following:
  * <pre>
  * &lt;filter&gt;
@@ -58,7 +59,7 @@
  * failing that it will forward the request to <code>index.php?p=/path/to/resource.ext</code>.
  * The last file URI specified in the list is therefore the "fallback" to which the request
  * is forwarded to in case no previous files can be found.
- * <p />
+ * <p>
  * The files are resolved using {@link ServletContext#getResource(String)} to make sure
  * that only files visible to the application are served.
  *
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java
index a65f6ab..400e3b7 100644
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/AbstractHttpClientServerTest.java
@@ -20,7 +20,7 @@
 
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.eclipse.jetty.client.ConnectionPool;
+import org.eclipse.jetty.client.DuplexConnectionPool;
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.HttpDestination;
 import org.eclipse.jetty.client.LeakTrackingConnectionPool;
@@ -37,10 +37,10 @@
 import org.eclipse.jetty.toolchain.test.TestTracker;
 import org.eclipse.jetty.util.LeakDetector;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Rule;
 
-import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
 
 public abstract class AbstractHttpClientServerTest
@@ -71,7 +71,7 @@
 
         QueuedThreadPool executor = new QueuedThreadPool();
         executor.setName(executor.getName() + "-client");
-        
+
         client = new HttpClient(new HttpClientTransportOverFCGI(1, false, "")
         {
             @Override
@@ -80,7 +80,7 @@
                 return new HttpDestinationOverFCGI(client, origin)
                 {
                     @Override
-                    protected ConnectionPool newConnectionPool(HttpClient client)
+                    protected DuplexConnectionPool newConnectionPool(HttpClient client)
                     {
                         return new LeakTrackingConnectionPool(this, client.getMaxConnectionsPerDestination(), this)
                         {
@@ -105,15 +105,15 @@
     {
         System.gc();
 
-        assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), is(0L));
-        
-        assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), is(0L));
-        
-        assertThat("Connection Leaks", connectionLeaks.get(), is(0L));
+        assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), Matchers.is(0L));
+        assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), Matchers.is(0L));
+        assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), Matchers.is(0L));
+
+        assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), Matchers.is(0L));
+        assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), Matchers.is(0L));
+        assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), Matchers.is(0L));
+
+        assertThat("Connection Leaks", connectionLeaks.get(), Matchers.is(0L));
 
         if (client != null)
             client.stop();
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java
index 7d36be3..a437648 100644
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/EmptyServerHandler.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.fcgi.server;
 
 import java.io.IOException;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java
index f5ce336..2ae8514 100644
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/HttpClientTest.java
@@ -32,6 +32,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.zip.GZIPOutputStream;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
@@ -95,6 +96,35 @@
     }
 
     @Test
+    public void testGETResponseWithBigContent() throws Exception
+    {
+        final byte[] data = new byte[16 * 1024 * 1024];
+        new Random().nextBytes(data);
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                // Setting the Content-Length triggers the HTTP
+                // content mode for response content parsing,
+                // otherwise the RAW content mode is used.
+                response.setContentLength(data.length);
+                response.getOutputStream().write(data);
+                baseRequest.setHandled(true);
+            }
+        });
+
+        Request request = client.newRequest(scheme + "://localhost:" + connector.getLocalPort());
+        FutureResponseListener listener = new FutureResponseListener(request, data.length);
+        request.send(listener);
+        ContentResponse response = listener.get(15, TimeUnit.SECONDS);
+        Assert.assertNotNull(response);
+        Assert.assertEquals(200, response.getStatus());
+        byte[] content = response.getContent();
+        Assert.assertArrayEquals(data, content);
+    }
+
+    @Test
     public void testGETWithParametersResponseWithContent() throws Exception
     {
         final String paramName1 = "a";
@@ -419,7 +449,7 @@
         Assert.assertNotNull(response);
         Assert.assertEquals(200, response.getStatus());
     }
-    
+
     @Test
     public void testConnectionIdleTimeout() throws Exception
     {
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java
new file mode 100644
index 0000000..7dad0ee
--- /dev/null
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalHTTP2FastCGIProxyServer.java
@@ -0,0 +1,95 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.fcgi.server.proxy;
+
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+public class DrupalHTTP2FastCGIProxyServer
+{
+    public static void main(String[] args) throws Exception
+    {
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setEndpointIdentificationAlgorithm("");
+        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
+        sslContextFactory.setTrustStorePassword("storepwd");
+        sslContextFactory.setCipherComparator(new HTTP2Cipher.CipherComparator());
+
+        Server server = new Server();
+
+        // HTTP(S) Configuration
+        HttpConfiguration config = new HttpConfiguration();
+        HttpConfiguration https_config = new HttpConfiguration(config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
+        
+        // HTTP2 factory
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
+        NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(h2.getProtocol());
+        
+        // SSL Factory
+        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol());
+        
+        // HTTP2 Connector
+        ServerConnector http2Connector = 
+            new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config));
+        http2Connector.setPort(8443);
+        http2Connector.setIdleTimeout(15000);
+        server.addConnector(http2Connector);
+
+        // Drupal seems to only work on the root context,
+        // at least out of the box without additional plugins
+
+        String root = "/home/simon/programs/drupal-7.23";
+
+        ServletContextHandler context = new ServletContextHandler(server, "/");
+        context.setResourceBase(root);
+        context.setWelcomeFiles(new String[]{"index.php"});
+
+        // Serve static resources
+        ServletHolder defaultServlet = new ServletHolder(DefaultServlet.class);
+        defaultServlet.setName("default");
+        context.addServlet(defaultServlet, "/");
+
+        // FastCGI
+        ServletHolder fcgiServlet = new ServletHolder(FastCGIProxyServlet.class);
+        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root);
+        fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000");
+        fcgiServlet.setInitParameter("prefix", "/");
+        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+\\.php)");
+        context.addServlet(fcgiServlet, "*.php");
+
+        server.start();
+    }
+}
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalSPDYFastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalSPDYFastCGIProxyServer.java
deleted file mode 100644
index 5b2bc4b..0000000
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/DrupalSPDYFastCGIProxyServer.java
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.fcgi.server.proxy;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnector;
-import org.eclipse.jetty.spdy.server.http.PushStrategy;
-import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class DrupalSPDYFastCGIProxyServer
-{
-    public static void main(String[] args) throws Exception
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setEndpointIdentificationAlgorithm("");
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-
-        Server server = new Server();
-
-        Map<Short, PushStrategy> pushStrategies = new HashMap<>();
-        pushStrategies.put(SPDY.V3, new ReferrerPushStrategy());
-        HTTPSPDYServerConnector connector = new HTTPSPDYServerConnector(server, sslContextFactory, pushStrategies);
-        connector.setPort(8443);
-        server.addConnector(connector);
-
-        // Drupal seems to only work on the root context,
-        // at least out of the box without additional plugins
-
-        String root = "/home/simon/programs/drupal-7.23";
-
-        ServletContextHandler context = new ServletContextHandler(server, "/");
-        context.setResourceBase(root);
-        context.setWelcomeFiles(new String[]{"index.php"});
-
-        // Serve static resources
-        ServletHolder defaultServlet = new ServletHolder(DefaultServlet.class);
-        defaultServlet.setName("default");
-        context.addServlet(defaultServlet, "/");
-
-        // FastCGI
-        ServletHolder fcgiServlet = new ServletHolder(FastCGIProxyServlet.class);
-        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root);
-        fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000");
-        fcgiServlet.setInitParameter("prefix", "/");
-        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+\\.php)");
-        context.addServlet(fcgiServlet, "*.php");
-
-        server.start();
-    }
-}
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java
index 64b0543..182bf68 100644
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/FastCGIProxyServletTest.java
@@ -19,12 +19,9 @@
 package org.eclipse.jetty.fcgi.server.proxy;
 
 import java.io.IOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -33,7 +30,6 @@
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.client.util.FutureResponseListener;
 import org.eclipse.jetty.fcgi.server.ServerFCGIConnectionFactory;
 import org.eclipse.jetty.server.HttpConfiguration;
@@ -41,7 +37,7 @@
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
@@ -52,9 +48,9 @@
 public class FastCGIProxyServletTest
 {
     @Parameterized.Parameters
-    public static Collection<Object[]> parameters()
+    public static Object[] parameters()
     {
-        return Arrays.asList(new Object[]{true}, new Object[]{false});
+        return new Object[]{true, false};
     }
 
     private final boolean sendStatus200;
@@ -70,7 +66,9 @@
 
     public void prepare(HttpServlet servlet) throws Exception
     {
-        server = new Server();
+        QueuedThreadPool serverThreads = new QueuedThreadPool();
+        serverThreads.setName("server");
+        server = new Server(serverThreads);
         httpConnector = new ServerConnector(server);
         server.addConnector(httpConnector);
 
@@ -84,20 +82,24 @@
         FastCGIProxyServlet fcgiServlet = new FastCGIProxyServlet()
         {
             @Override
-            protected URI rewriteURI(HttpServletRequest request)
+            protected String rewriteTarget(HttpServletRequest request)
             {
-                return URI.create("http://localhost:" + fcgiConnector.getLocalPort() + servletPath + request.getServletPath());
+                return "http://localhost:" + fcgiConnector.getLocalPort() + servletPath + request.getServletPath();
             }
         };
         ServletHolder fcgiServletHolder = new ServletHolder(fcgiServlet);
-        context.addServlet(fcgiServletHolder, "*.php");
+        fcgiServletHolder.setName("fcgi");
         fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, "/scriptRoot");
         fcgiServletHolder.setInitParameter("proxyTo", "http://localhost");
         fcgiServletHolder.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+?\\.php)");
+        context.addServlet(fcgiServletHolder, "*.php");
 
         context.addServlet(new ServletHolder(servlet), servletPath + "/*");
 
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
         client = new HttpClient();
+        client.setExecutor(clientThreads);
         server.addBean(client);
 
         server.start();
@@ -145,21 +147,17 @@
         });
 
         Request request = client.newRequest("localhost", httpConnector.getLocalPort())
-                .onResponseContentAsync(new Response.AsyncContentListener()
+                .onResponseContentAsync((response, content, callback) ->
                 {
-                    @Override
-                    public void onContent(Response response, ByteBuffer content, Callback callback)
+                    try
                     {
-                        try
-                        {
-                            if (delay > 0)
-                                TimeUnit.MILLISECONDS.sleep(delay);
-                            callback.succeeded();
-                        }
-                        catch (InterruptedException x)
-                        {
-                            callback.failed(x);
-                        }
+                        if (delay > 0)
+                            TimeUnit.MILLISECONDS.sleep(delay);
+                        callback.succeeded();
+                    }
+                    catch (InterruptedException x)
+                    {
+                        callback.failed(x);
                     }
                 })
                 .path(path);
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java
index be506a0..5c025754 100644
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/TryFilesFilterTest.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.util.EnumSet;
+
 import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java
new file mode 100644
index 0000000..b8c14dd
--- /dev/null
+++ b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressHTTP2FastCGIProxyServer.java
@@ -0,0 +1,101 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.fcgi.server.proxy;
+
+import java.util.EnumSet;
+
+import javax.servlet.DispatcherType;
+
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+public class WordPressHTTP2FastCGIProxyServer
+{
+    public static void main(String[] args) throws Exception
+    {
+        int tlsPort = 8443;
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setEndpointIdentificationAlgorithm("");
+        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
+        sslContextFactory.setTrustStorePassword("storepwd");
+        sslContextFactory.setCipherComparator(new HTTP2Cipher.CipherComparator());
+
+        Server server = new Server();
+
+        // HTTP(S) Configuration
+        HttpConfiguration config = new HttpConfiguration();
+        HttpConfiguration https_config = new HttpConfiguration(config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
+        
+        // HTTP2 factory
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
+        NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(h2.getProtocol());
+        
+        // SSL Factory
+        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol());
+        
+        // HTTP2 Connector
+        ServerConnector http2Connector = 
+            new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config));
+        http2Connector.setPort(tlsPort);
+        http2Connector.setIdleTimeout(15000);
+        server.addConnector(http2Connector);
+
+        String root = "/home/simon/programs/wordpress-3.7.1";
+
+        ServletContextHandler context = new ServletContextHandler(server, "/wp");
+        context.setResourceBase(root);
+        context.setWelcomeFiles(new String[]{"index.php"});
+
+        // Serve static resources
+        ServletHolder defaultServlet = new ServletHolder("default", DefaultServlet.class);
+        context.addServlet(defaultServlet, "/");
+
+        FilterHolder tryFilesFilter = context.addFilter(TryFilesFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
+//        tryFilesFilter.setInitParameter(TryFilesFilter.FILES_INIT_PARAM, "$path $path/index.php"); // Permalink /?p=123
+        tryFilesFilter.setInitParameter(TryFilesFilter.FILES_INIT_PARAM, "$path /index.php?p=$path"); // Permalink /%year%/%monthnum%/%postname%
+
+        // FastCGI
+        ServletHolder fcgiServlet = context.addServlet(FastCGIProxyServlet.class, "*.php");
+        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root);
+        fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000");
+        fcgiServlet.setInitParameter("prefix", "/");
+        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+?\\.php)");
+
+        server.start();
+    }
+}
diff --git a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java b/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java
deleted file mode 100644
index efba7a8..0000000
--- a/jetty-fcgi/fcgi-server/src/test/java/org/eclipse/jetty/fcgi/server/proxy/WordPressSPDYFastCGIProxyServer.java
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.fcgi.server.proxy;
-
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import javax.servlet.DispatcherType;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnector;
-import org.eclipse.jetty.spdy.server.http.PushStrategy;
-import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class WordPressSPDYFastCGIProxyServer
-{
-    public static void main(String[] args) throws Exception
-    {
-        int port = 8080;
-        int tlsPort = 8443;
-
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setEndpointIdentificationAlgorithm("");
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-
-        Server server = new Server();
-
-        Map<Short, PushStrategy> pushStrategies = new HashMap<>();
-        pushStrategies.put(SPDY.V3, new ReferrerPushStrategy());
-        HTTPSPDYServerConnector tlsConnector = new HTTPSPDYServerConnector(server, sslContextFactory, pushStrategies);
-        tlsConnector.setPort(tlsPort);
-        server.addConnector(tlsConnector);
-        HTTPSPDYServerConnector connector = new HTTPSPDYServerConnector(server, null, pushStrategies);
-        connector.setPort(port);
-        server.addConnector(connector);
-
-        String root = "/home/simon/programs/wordpress-3.7.1";
-
-        ServletContextHandler context = new ServletContextHandler(server, "/wp");
-        context.setResourceBase(root);
-        context.setWelcomeFiles(new String[]{"index.php"});
-
-        // Serve static resources
-        ServletHolder defaultServlet = new ServletHolder("default", DefaultServlet.class);
-        context.addServlet(defaultServlet, "/");
-
-        FilterHolder tryFilesFilter = context.addFilter(TryFilesFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
-//        tryFilesFilter.setInitParameter(TryFilesFilter.FILES_INIT_PARAM, "$path $path/index.php"); // Permalink /?p=123
-        tryFilesFilter.setInitParameter(TryFilesFilter.FILES_INIT_PARAM, "$path /index.php?p=$path"); // Permalink /%year%/%monthnum%/%postname%
-
-        // FastCGI
-        ServletHolder fcgiServlet = context.addServlet(FastCGIProxyServlet.class, "*.php");
-        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_ROOT_INIT_PARAM, root);
-        fcgiServlet.setInitParameter("proxyTo", "http://localhost:9000");
-        fcgiServlet.setInitParameter("prefix", "/");
-        fcgiServlet.setInitParameter(FastCGIProxyServlet.SCRIPT_PATTERN_INIT_PARAM, "(.+?\\.php)");
-
-        server.start();
-    }
-}
diff --git a/jetty-fcgi/pom.xml b/jetty-fcgi/pom.xml
index ec065cb..db17bbe 100644
--- a/jetty-fcgi/pom.xml
+++ b/jetty-fcgi/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty</groupId>
         <artifactId>jetty-project</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-gcloud/gcloud-session-manager/pom.xml b/jetty-gcloud/gcloud-session-manager/pom.xml
new file mode 100644
index 0000000..c25002b
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.gcloud</groupId>
+    <artifactId>gcloud-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>gcloud-session-manager</artifactId>
+  <name>Jetty :: GCloud :: Session Manager</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.gcloud</groupId>
+      <artifactId>gcloud-java-datastore</artifactId>
+      <version>${gcloud.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+ <properties>
+   <bundle-symbolic-name>${project.groupId}.session</bundle-symbolic-name>
+ </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <extensions>true</extensions>
+          <executions>
+              <execution>
+                  <goals>
+                      <goal>manifest</goal>
+                  </goals>
+                  <configuration>
+                      <instructions>
+                          <Export-Package>org.eclipse.jetty.gcloud.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";</Export-Package>
+                      </instructions>
+                    </configuration>
+                 </execution>
+            </executions>
+      </plugin>
+   </plugins>
+  </build>
+
+</project>
diff --git a/jetty-gcloud/gcloud-session-manager/src/main/config/etc/jetty-gcloud-sessions.xml b/jetty-gcloud/gcloud-session-manager/src/main/config/etc/jetty-gcloud-sessions.xml
new file mode 100644
index 0000000..72f9da6
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/main/config/etc/jetty-gcloud-sessions.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- ============================================================================================== -->
+  <!-- GCloud configuration.                                                                          -->
+  <!-- Note: passwords can use jetty obfuscation.  See                                                -->
+  <!-- https://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html -->
+  <!-- ============================================================================================== -->
+  <New id="gconf" class="org.eclipse.jetty.gcloud.session.GCloudConfiguration">
+    <!-- To contact remote gclouddatastore set the following properties in start.ini -->
+    <!-- Either set jetty.gcloudSession.projectId or use system property/env var DATASTORE_DATASET-->
+    <Set name="projectId"><Property name="jetty.gcloudSession.projectId"/></Set>
+    <Set name="p12File"><Property name="jetty.gcloudSession.p12File"/></Set>
+    <Set name="serviceAccount"><Property name="jetty.gcloudSession.serviceAccount"/></Set>
+    <Set name="password"><Property name="jetty.gcloudSession.password"/></Set>
+  </New>
+
+
+  <!-- ===================================================================== -->
+  <!-- Configure a GCloudSessionIdManager                                    -->
+  <!-- ===================================================================== -->
+  <Set name="sessionIdManager">
+    <New id="idMgr" class="org.eclipse.jetty.gcloud.session.GCloudSessionIdManager">
+      <Arg>
+        <Ref id="Server"/>
+      </Arg>
+      <Set name="workerName"><Property name="jetty.gcloudSession.workerName" default="node1"/></Set>
+      <Set name="config"><Ref id="gconf"/></Set>
+    </New>
+  </Set>
+
+</Configure>
diff --git a/jetty-gcloud/gcloud-session-manager/src/main/config/modules/gcloud-sessions.mod b/jetty-gcloud/gcloud-session-manager/src/main/config/modules/gcloud-sessions.mod
new file mode 100644
index 0000000..0780a60
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/main/config/modules/gcloud-sessions.mod
@@ -0,0 +1,91 @@
+#
+# Jetty GCloudDatastore Session Manager module
+#
+
+[depend]
+annotations
+webapp
+
+[files]
+
+maven://com.google.gcloud/gcloud-java-datastore/0.0.7|lib/gcloud/gcloud-java-datastore-0.0.7.jar
+maven://com.google.gcloud/gcloud-java-core/0.0.7|lib/gcloud/gcloud-java-core-0.0.7.jar
+maven://com.google.auth/google-auth-library-credentials/0.1.0|lib/gcloud/google-auth-library-credentials-0.1.0.jar
+maven://com.google.auth/google-auth-library-oauth2-http/0.1.0|lib/gcloud/google-auth-library-oauth2-http-0.1.0.jar
+maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
+maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
+maven://com.google.http-client/google-http-client/1.20.0|lib/gcloud/google-http-client-1.20.0.jar
+maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
+maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
+maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
+maven://commons-logging/commons-logging/1.1.1|lib/gcloud/commons-logging-1.1.1.jar
+maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
+maven://com.google.oauth-client/google-oauth-client/1.20.0|lib/gcloud//google-oauth-client-1.20.0.jar
+maven://com.google.guava/guava/18.0|lib/gcloud/guava-18.0.jar
+maven://com.google.api-client/google-api-client-appengine/1.20.0|lib/gcloud/google-api-client-appengine-1.20.0.jar
+maven://com.google.oauth-client/google-oauth-client-appengine/1.20.0|lib/gcloud/google-oauth-client-appengine-1.20.0.jar
+maven://com.google.oauth-client/google-oauth-client-servlet/1.20.0|lib/gcloud/google-oauth-client-servlet-1.20.0.jar
+maven://com.google.http-client/google-http-client-jdo/1.20.0|lib/gcloud/google-http-client-jdo-1.20.0.jar
+maven://com.google.api-client/google-api-client-servlet/1.20.0|lib/gcloud/google-api-client-servlet-1.20.0.jar
+maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
+maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
+maven://com.google.http-client/google-http-client-appengine/1.20.0|lib/gcloud/google-http-client-appengine-1.20.0.jar
+maven://com.google.http-client/google-http-client-jackson/1.20.0|lib/gcloud/google-http-client-jackson-1.20.0.jar
+maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
+maven://joda-time/joda-time/2.8.2|lib/gcloud/joda-time-2.8.2.jar
+maven://org.json/json/20090211|lib/gcloud/json-20090211.jar
+maven://com.google.apis/google-api-services-datastore-protobuf/v1beta2-rev1-2.1.2|lib/gcloud/google-api-services-datastore-protobuf-v1beta2-rev1-2.1.2.jar
+maven://com.google.protobuf/protobuf-java/2.5.0|lib/gcloud/protobuf-java-2.5.0.jar
+maven://com.google.http-client/google-http-client-protobuf/1.15.0-rc|lib/gcloud/google-http-client-protobuf-1.15.0-rc.jar
+maven://com.google.api-client/google-api-client/1.15.0-rc|lib/gcloud/google-api-client-1.15.0-rc.jar
+maven://com.google.apis/google-api-services-datastore/v1beta2-rev23-1.19.0|lib/gcloud/google-api-services-datastore-v1beta2-rev23-1.19.0.jar
+
+[lib]
+lib/gcloud-session-manager-${jetty.version}.jar
+lib/gcloud/*.jar
+
+[xml]
+etc/jetty-gcloud-sessions.xml
+
+[license]
+GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
+https://github.com/GoogleCloudPlatform/gcloud-java
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini-template]
+## Unique identifier for this node in the cluster
+# jetty.gcloudSession.workerName=node1
+
+
+## GCloudDatastore Session config
+## If running inside Google cloud all configuration is provided by
+## environment variables and you do not need to set anything in this file.
+##    
+## If running externally to Google:
+##   To contact the remote gcloud datastore:
+##   1. set the DATASTORE_DATASET System property/environment variable to the name of your project
+##      or alternatively set the jetty.gcloudSession.projectId property below.
+##   2. set the jetty.gcloudSession.p12File, jetty.gcloudSession.serviceAccount and 
+##      jetty.gcloudSession.password (supports obfuscation) below.
+##
+##   To contact a local dev gcloud datastore server:
+##   1. set the DATASTORE_DATASET System property/environment variable to the name of your project.
+##   2. set the DATASTORE_HOST System property/environment variable to the url of the dev server
+##      as described at https://cloud.google.com/datastore/docs/tools/devserver#setting_environment_variables
+
+## The gcloud projectId
+## Set this property to connect to remote gcloud datastore. 
+## Or, set the DATASTORE_DATASET System property/env variable instead.
+#jetty.gcloudSession.projectId=
+
+## The p12 file associated with the project.
+## Set this property to connect to remote gcloud datastore
+#jetty.gcloudSession.p12File=
+
+## The serviceAccount for the Datastore.
+## Set this property to connect to to remote gcloud datastore
+#jetty.gcloudSession.serviceAccount=
+
+## The password (can be obfuscated).
+## Set this property to connect to remote gcloud datastore
+#jetty.gcloudSession.password=
diff --git a/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudConfiguration.java b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudConfiguration.java
new file mode 100644
index 0000000..9dc1035
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudConfiguration.java
@@ -0,0 +1,201 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.util.Properties;
+
+import org.eclipse.jetty.util.security.Password;
+
+import com.google.gcloud.AuthCredentials;
+import com.google.gcloud.datastore.DatastoreOptions;
+
+
+
+/**
+ * GCloudConfiguration
+ *
+ *
+ */
+public class GCloudConfiguration
+{
+    public static final String PROJECT_ID = "projectId";
+    public static final String P12 = "p12";
+    public static final String PASSWORD = "password";
+    public static final String SERVICE_ACCOUNT = "serviceAccount";
+    
+    private String _projectId;
+    private String _p12Filename;
+    private File _p12File;
+    private String _serviceAccount;
+    private String _passwordSet;
+    private String _password;
+    private AuthCredentials _authCredentials;
+    private DatastoreOptions _options;
+    
+    /**
+     * Generate a configuration from a properties file
+     * 
+     * @param propsFile
+     * @return
+     * @throws IOException
+     */
+    public static GCloudConfiguration fromFile(String propsFile)
+    throws IOException
+    {
+        if (propsFile == null)
+            throw new IllegalArgumentException ("Null properties file");
+        
+        File f = new File(propsFile);
+        if (!f.exists())
+            throw new IllegalArgumentException("No such file "+f.getAbsolutePath());
+        Properties props = new Properties();
+        try (FileInputStream is=new FileInputStream(f))
+        {
+            props.load(is);
+        }
+        
+        GCloudConfiguration config = new GCloudConfiguration();
+        config.setProjectId(props.getProperty(PROJECT_ID));
+        config.setP12File(props.getProperty(P12));
+        config.setPassword(props.getProperty(PASSWORD));
+        config.setServiceAccount(props.getProperty(SERVICE_ACCOUNT));
+        return config;
+    }
+    
+    
+    
+    public String getProjectId()
+    {
+        return _projectId;
+    }
+
+    public File getP12File()
+    {
+        return _p12File;
+    }
+
+    public String getServiceAccount()
+    {
+        return _serviceAccount;
+    }
+
+
+    public void setProjectId(String projectId)
+    {
+        checkForModification();
+        _projectId = projectId;
+    }
+
+    public void setP12File (String file)
+    {
+        checkForModification();
+        _p12Filename = file;
+
+    }
+    
+    
+    public void setServiceAccount (String serviceAccount)
+    {
+        checkForModification();
+        _serviceAccount = serviceAccount;
+    }
+    
+
+    public void setPassword (String pwd)
+    {
+        checkForModification();
+        _passwordSet = pwd;
+
+    }
+
+
+    public DatastoreOptions getDatastoreOptions ()
+            throws Exception
+    {
+        if (_options == null)
+        {
+            if (_passwordSet == null && _p12Filename == null && _serviceAccount == null)
+            {
+                //When no values are explicitly presented for auth info, we are either running
+                //1. inside GCE environment, in which case all auth info is derived from the environment
+                //2. outside the GCE environment, but using a local gce dev server, in which case you
+                //   need to set the following 2 environment/system properties
+                //          DATASTORE_HOST: eg http://localhost:9999 - this is the host and port of a local development server
+                //          DATASTORE_DATASET: eg myProj - this is the name of your project          
+                _options = DatastoreOptions.defaultInstance();
+            }
+            else
+            {
+                //When running externally to GCE, you need to provide
+                //explicit auth info. You can either set the projectId explicitly, or you can set the
+                //DATASTORE_DATASET env/system property
+                _p12File = new File(_p12Filename);
+                Password p = new Password(_passwordSet);
+                _password = p.toString();
+                _options = DatastoreOptions.builder()
+                        .projectId(_projectId)
+                        .authCredentials(getAuthCredentials())
+                        .build();
+            }
+        }
+        return _options;
+    }
+
+    /**
+     * @return
+     * @throws Exception
+     */
+    public AuthCredentials getAuthCredentials()
+    throws Exception
+    {
+        if (_authCredentials == null)
+        {
+            if (_password == null)
+                throw new IllegalStateException("No password");
+
+            if (_p12File == null || !_p12File.exists())
+                throw new IllegalStateException("No p12 file: "+(_p12File==null?"null":_p12File.getAbsolutePath()));
+
+            if (_serviceAccount == null)
+                throw new IllegalStateException("No service account");
+
+            char[] pwdChars = _password.toCharArray();
+            KeyStore keystore = KeyStore.getInstance("PKCS12");
+            keystore.load(new FileInputStream(getP12File()), pwdChars);
+            PrivateKey privateKey = (PrivateKey) keystore.getKey("privatekey", pwdChars);
+            _authCredentials = AuthCredentials.createFor(getServiceAccount(), privateKey);
+        }
+        return _authCredentials;
+    }
+    
+    /**
+     * @throws IllegalStateException
+     */
+    protected void checkForModification () throws IllegalStateException
+    {
+        if (_authCredentials != null || _options != null)
+            throw new IllegalStateException("Cannot modify auth configuration after datastore initialized");     
+    }
+}
diff --git a/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionIdManager.java b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionIdManager.java
new file mode 100644
index 0000000..7c2a81e
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionIdManager.java
@@ -0,0 +1,323 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import java.util.Random;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.AbstractSession;
+import org.eclipse.jetty.server.session.AbstractSessionIdManager;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.KeyFactory;
+
+
+
+/**
+ * GCloudSessionIdManager
+ *
+ * 
+ * 
+ */
+public class GCloudSessionIdManager extends AbstractSessionIdManager
+{
+    private  final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
+    public static final int DEFAULT_IDLE_EXPIRY_MULTIPLE = 2;
+    public static final String KIND = "GCloudSessionId";
+    private Server _server;
+    private Datastore _datastore;
+    private KeyFactory _keyFactory;
+    private GCloudConfiguration _config;
+    
+    
+    
+ 
+    /**
+     * @param server
+     */
+    public GCloudSessionIdManager(Server server)
+    {
+        super();
+        _server = server;
+    }
+
+    /**
+     * @param server
+     * @param random
+     */
+    public GCloudSessionIdManager(Server server, Random random)
+    {
+       super(random);
+       _server = server;
+    }
+
+
+
+    /** 
+     * Start the id manager.
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStart()
+     */
+    @Override
+    protected void doStart() throws Exception
+    {
+        if (_config == null)
+            throw new IllegalStateException("No gcloud configuration specified");       
+        
+
+        _datastore = DatastoreFactory.instance().get(_config.getDatastoreOptions());
+        _keyFactory = _datastore.newKeyFactory().kind(KIND);
+  
+        super.doStart();
+    }
+
+
+    
+    /** 
+     * Stop the id manager
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStop()
+     */
+    @Override
+    protected void doStop() throws Exception
+    {
+        super.doStop();
+    }
+
+    
+   
+
+    
+    /** 
+     * Check to see if the given session id is being
+     * used by a session in any context.
+     * 
+     * This method will consult the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#idInUse(java.lang.String)
+     */
+    @Override
+    public boolean idInUse(String id)
+    {
+        if (id == null)
+            return false;
+        
+        String clusterId = getClusterId(id);
+        
+        //ask the cluster - this should also tickle the idle expiration timer on the sessionid entry
+        //keeping it valid
+        try
+        {
+            return exists(clusterId);
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Problem checking inUse for id="+clusterId, e);
+            return false;
+        }
+        
+    }
+
+    /** 
+     * Remember a new in-use session id.
+     * 
+     * This will save the in-use session id to the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#addSession(javax.servlet.http.HttpSession)
+     */
+    @Override
+    public void addSession(HttpSession session)
+    {
+        if (session == null)
+            return;
+
+        //insert into the store
+        insert (((AbstractSession)session).getClusterId());
+    }
+
+  
+
+    
+    public GCloudConfiguration getConfig()
+    {
+        return _config;
+    }
+
+    public void setConfig(GCloudConfiguration config)
+    {
+        _config = config;
+    }
+
+    
+    
+    /** 
+     * Remove a session id from the list of in-use ids.
+     * 
+     * This will remvove the corresponding session id from the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#removeSession(javax.servlet.http.HttpSession)
+     */
+    @Override
+    public void removeSession(HttpSession session)
+    {
+        if (session == null)
+            return;
+
+        //delete from the cache
+        delete (((AbstractSession)session).getClusterId());
+    }
+
+    /** 
+     * Remove a session id. This compels all other contexts who have a session
+     * with the same id to also remove it.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#invalidateAll(java.lang.String)
+     */
+    @Override
+    public void invalidateAll(String id)
+    {
+        //delete the session id from list of in-use sessions
+        delete (id);
+
+
+        //tell all contexts that may have a session object with this id to
+        //get rid of them
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
+        {
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null)
+            {
+                SessionManager manager = sessionHandler.getSessionManager();
+
+                if (manager != null && manager instanceof GCloudSessionManager)
+                {
+                    ((GCloudSessionManager)manager).invalidateSession(id);
+                }
+            }
+        }
+
+    }
+
+    /** 
+     * Change a session id. 
+     * 
+     * Typically this occurs when a previously existing session has passed through authentication.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#renewSessionId(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest)
+     */
+    @Override
+    public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request)
+    {
+        //generate a new id
+        String newClusterId = newSessionId(request.hashCode());
+
+        delete(oldClusterId);
+        insert(newClusterId);
+
+
+        //tell all contexts to update the id 
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
+        {
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null) 
+            {
+                SessionManager manager = sessionHandler.getSessionManager();
+
+                if (manager != null && manager instanceof GCloudSessionManager)
+                {
+                    ((GCloudSessionManager)manager).renewSessionId(oldClusterId, oldNodeId, newClusterId, getNodeId(newClusterId, request));
+                }
+            }
+        }
+
+    }
+
+    
+    
+    /**
+     * Ask the datastore if a particular id exists.
+     * 
+     * @param id
+     * @return
+     */
+    protected boolean exists (String id)
+    {
+        if (_datastore == null)
+            throw new IllegalStateException ("No DataStore");
+        Key key = _keyFactory.newKey(id);
+        return _datastore.get(key) != null;
+    }
+    
+
+    /**
+     * Put a session id into the cluster.
+     * 
+     * @param id
+     */
+    protected void insert (String id)
+    {        
+        if (_datastore == null)
+            throw new IllegalStateException ("No DataStore");
+
+        Entity entity = Entity.builder(makeKey(id))
+                        .set("id", id).build();
+        _datastore.put(entity);
+    }
+
+   
+   
+    
+    /**
+     * Remove a session id from the cluster.
+     * 
+     * @param id
+     */
+    protected void delete (String id)
+    {
+        if (_datastore == null)
+            throw new IllegalStateException ("No DataStore");
+        
+        _datastore.delete(makeKey(id));
+    }
+    
+    
+
+    /**
+     * Generate a unique key from the session id.
+     * 
+     * @param id
+     * @return
+     */
+    protected Key makeKey (String id)
+    {
+        return _keyFactory.newKey(id);
+    }
+}
diff --git a/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java
new file mode 100644
index 0000000..640aec5
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java
@@ -0,0 +1,1298 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandler.Context;
+import org.eclipse.jetty.server.session.AbstractSession;
+import org.eclipse.jetty.server.session.AbstractSessionManager;
+import org.eclipse.jetty.server.session.MemSession;
+import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+import com.google.gcloud.datastore.Blob;
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.GqlQuery;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.KeyFactory;
+import com.google.gcloud.datastore.Query;
+import com.google.gcloud.datastore.Query.ResultType;
+import com.google.gcloud.datastore.QueryResults;
+
+
+
+/**
+ * GCloudSessionManager
+ * 
+ * 
+ */
+public class GCloudSessionManager extends AbstractSessionManager
+{
+    private  final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
+    
+    
+    public static final String KIND = "GCloudSession";
+    public static final int DEFAULT_MAX_QUERY_RESULTS = 100;
+    public static final long DEFAULT_SCAVENGE_SEC = 600; 
+    
+    /**
+     * Sessions known to this node held in memory
+     */
+    private ConcurrentHashMap<String, GCloudSessionManager.Session> _sessions;
+
+    
+    /**
+     * The length of time a session can be in memory without being checked against
+     * the cluster. A value of 0 indicates that the session is never checked against
+     * the cluster - the current node is considered to be the master for the session.
+     *
+     */
+    private long _staleIntervalSec = 0;
+    
+    protected Scheduler.Task _task; //scavenge task
+    protected Scheduler _scheduler;
+    protected Scavenger _scavenger;
+    protected long _scavengeIntervalMs = 1000L * DEFAULT_SCAVENGE_SEC; //10mins
+    protected boolean _ownScheduler;
+    
+    private Datastore _datastore;
+    private KeyFactory _keyFactory;
+
+
+    private SessionEntityConverter _converter;
+
+
+    private int _maxResults = DEFAULT_MAX_QUERY_RESULTS;
+
+
+    /**
+     * Scavenger
+     *
+     */
+    protected class Scavenger implements Runnable
+    {
+
+        @Override
+        public void run()
+        {
+           try
+           {
+               scavenge();
+           }
+           finally
+           {
+               if (_scheduler != null && _scheduler.isRunning())
+                   _task = _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS);
+           }
+        }
+    }
+
+    /**
+     * SessionEntityConverter
+     *
+     *
+     */
+    public class SessionEntityConverter
+    {
+        public  final String CLUSTERID = "clusterId";
+        public  final String CONTEXTPATH = "contextPath";
+        public  final String VHOST = "vhost";
+        public  final String ACCESSED = "accessed";
+        public  final String LASTACCESSED = "lastAccessed";
+        public  final String CREATETIME = "createTime";
+        public  final  String COOKIESETTIME = "cookieSetTime";
+        public  final String LASTNODE = "lastNode";
+        public  final String EXPIRY = "expiry";
+        public  final  String MAXINACTIVE = "maxInactive";
+        public  final  String ATTRIBUTES = "attributes";
+
+      
+        
+        public Entity entityFromSession (Session session, Key key) throws Exception
+        {
+            if (session == null)
+                return null;
+            
+            Entity entity = null;
+            
+            //serialize the attribute map
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(session.getAttributeMap());
+            oos.flush();
+            
+            //turn a session into an entity
+            entity = Entity.builder(key)
+                    .set(CLUSTERID, session.getId())
+                    .set(CONTEXTPATH, session.getContextPath())
+                    .set(VHOST, session.getVHost())
+                    .set(ACCESSED, session.getAccessed())
+                    .set(LASTACCESSED, session.getLastAccessedTime())
+                    .set(CREATETIME, session.getCreationTime())
+                    .set(COOKIESETTIME, session.getCookieSetTime())
+                    .set(LASTNODE,session.getLastNode())
+                    .set(EXPIRY, session.getExpiry())
+                    .set(MAXINACTIVE, session.getMaxInactiveInterval())
+                    .set(ATTRIBUTES, Blob.copyFrom(baos.toByteArray())).build();
+                     
+            return entity;
+        }
+        
+        public Session sessionFromEntity (Entity entity) throws Exception
+        {
+            if (entity == null)
+                return null;
+
+            final AtomicReference<Session> reference = new AtomicReference<Session>();
+            final AtomicReference<Exception> exception = new AtomicReference<Exception>();
+            Runnable load = new Runnable()
+            {
+                public void run ()
+                {
+                    try
+                    {
+                        //turn an entity into a Session
+                        String clusterId = entity.getString(CLUSTERID);
+                        String contextPath = entity.getString(CONTEXTPATH);
+                        String vhost = entity.getString(VHOST);
+                        long accessed = entity.getLong(ACCESSED);
+                        long lastAccessed = entity.getLong(LASTACCESSED);
+                        long createTime = entity.getLong(CREATETIME);
+                        long cookieSetTime = entity.getLong(COOKIESETTIME);
+                        String lastNode = entity.getString(LASTNODE);
+                        long expiry = entity.getLong(EXPIRY);
+                        long maxInactive = entity.getLong(MAXINACTIVE);
+                        Blob blob = (Blob) entity.getBlob(ATTRIBUTES);
+
+                        Session session = new Session (clusterId, createTime, accessed, maxInactive);
+                        session.setLastNode(lastNode);
+                        session.setContextPath(contextPath);
+                        session.setVHost(vhost);
+                        session.setCookieSetTime(cookieSetTime);
+                        session.setLastAccessedTime(lastAccessed);
+                        session.setLastNode(lastNode);
+                        session.setExpiry(expiry);
+                        try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream()))
+                        {
+                            Object o = ois.readObject();
+                            session.addAttributes((Map<String,Object>)o);
+                        }
+                        reference.set(session);
+                    }
+                    catch (Exception e)
+                    {
+                        exception.set(e);
+                    }
+                }
+            };
+            
+            if (_context==null)
+                load.run();
+            else
+                _context.getContextHandler().handle(null,load);
+   
+           
+            if (exception.get() != null)
+            {
+                exception.get().printStackTrace();
+                throw exception.get();
+            }
+            
+            return reference.get();
+        }
+    }
+    
+    /*
+     * Every time a Session is put into the cache one of these objects
+     * is created to copy the data out of the in-memory session, and 
+     * every time an object is read from the cache one of these objects
+     * a fresh Session object is created based on the data held by this
+     * object.
+     */
+    public class SerializableSessionData implements Serializable
+    {
+        /**
+         * 
+         */
+        private static final long serialVersionUID = -7779120106058533486L;
+        String clusterId;
+        String contextPath;
+        String vhost;
+        long accessed;
+        long lastAccessed;
+        long createTime;
+        long cookieSetTime;
+        String lastNode;
+        long expiry;
+        long maxInactive;
+        Map<String, Object> attributes;
+
+        public SerializableSessionData()
+        {
+
+        }
+
+       
+       public SerializableSessionData(Session s)
+       {
+           clusterId = s.getClusterId();
+           contextPath = s.getContextPath();
+           vhost = s.getVHost();
+           accessed = s.getAccessed();
+           lastAccessed = s.getLastAccessedTime();
+           createTime = s.getCreationTime();
+           cookieSetTime = s.getCookieSetTime();
+           lastNode = s.getLastNode();
+           expiry = s.getExpiry();
+           maxInactive = s.getMaxInactiveInterval();
+           attributes = s.getAttributeMap(); // TODO pointer, not a copy
+       }
+        
+        private void writeObject(java.io.ObjectOutputStream out) throws IOException
+        {  
+            out.writeUTF(clusterId); //session id
+            out.writeUTF(contextPath); //context path
+            out.writeUTF(vhost); //first vhost
+
+            out.writeLong(accessed);//accessTime
+            out.writeLong(lastAccessed); //lastAccessTime
+            out.writeLong(createTime); //time created
+            out.writeLong(cookieSetTime);//time cookie was set
+            out.writeUTF(lastNode); //name of last node managing
+      
+            out.writeLong(expiry); 
+            out.writeLong(maxInactive);
+            out.writeObject(attributes);
+        }
+        
+        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+            clusterId = in.readUTF();
+            contextPath = in.readUTF();
+            vhost = in.readUTF();
+            
+            accessed = in.readLong();//accessTime
+            lastAccessed = in.readLong(); //lastAccessTime
+            createTime = in.readLong(); //time created
+            cookieSetTime = in.readLong();//time cookie was set
+            lastNode = in.readUTF(); //last managing node
+            expiry = in.readLong(); 
+            maxInactive = in.readLong();
+            attributes = (HashMap<String,Object>)in.readObject();
+        }
+        
+    }
+    
+
+    
+    /**
+     * Session
+     *
+     * Representation of a session in local memory.
+     */
+    public class Session extends MemSession
+    {
+        
+        private ReentrantLock _lock = new ReentrantLock();
+        
+        /**
+         * The (canonical) context path for with which this session is associated
+         */
+        private String _contextPath;
+        
+        
+        
+        /**
+         * The time in msec since the epoch at which this session should expire
+         */
+        private long _expiryTime; 
+        
+        
+        /**
+         * Time in msec since the epoch at which this session was last read from cluster
+         */
+        private long _lastSyncTime;
+        
+        
+        /**
+         * The workername of last node known to be managing the session
+         */
+        private String _lastNode;
+        
+        
+        /**
+         * If dirty, session needs to be (re)sent to cluster
+         */
+        protected boolean _dirty=false;
+        
+        
+     
+
+        /**
+         * Any virtual hosts for the context with which this session is associated
+         */
+        private String _vhost;
+
+        
+        /**
+         * Count of how many threads are active in this session
+         */
+        private AtomicInteger _activeThreads = new AtomicInteger(0);
+        
+        
+        
+        
+        /**
+         * A new session.
+         * 
+         * @param request
+         */
+        protected Session (HttpServletRequest request)
+        {
+            super(GCloudSessionManager.this,request);
+            long maxInterval = getMaxInactiveInterval();
+            _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L));
+            _lastNode = getSessionIdManager().getWorkerName();
+           setVHost(GCloudSessionManager.getVirtualHost(_context));
+           setContextPath(GCloudSessionManager.getContextPath(_context));
+           _activeThreads.incrementAndGet(); //access will not be called on a freshly created session so increment here
+        }
+        
+        
+    
+        
+        /**
+         * A restored session.
+         * 
+         * @param sessionId
+         * @param created
+         * @param accessed
+         * @param maxInterval
+         */
+        protected Session (String sessionId, long created, long accessed, long maxInterval)
+        {
+            super(GCloudSessionManager.this, created, accessed, sessionId);
+            _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L));
+        }
+        
+        /** 
+         * Called on entry to the session.
+         * 
+         * @see org.eclipse.jetty.server.session.AbstractSession#access(long)
+         */
+        @Override
+        protected boolean access(long time)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Access session({}) for context {} on worker {}", getId(), getContextPath(), getSessionIdManager().getWorkerName());
+            try
+            {
+
+                long now = System.currentTimeMillis();
+                //lock so that no other thread can call access or complete until the first one has refreshed the session object if necessary
+                _lock.lock();
+                //a request thread is entering
+                if (_activeThreads.incrementAndGet() == 1)
+                {
+                    //if the first thread, check that the session in memory is not stale, if we're checking for stale sessions
+                    if (getStaleIntervalSec() > 0  && (now - getLastSyncTime()) >= (getStaleIntervalSec() * 1000L))
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Acess session({}) for context {} on worker {} stale session. Reloading.", getId(), getContextPath(), getSessionIdManager().getWorkerName());
+                        refresh();
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+            }
+            finally
+            {            
+                _lock.unlock();
+            }
+
+            if (super.access(time))
+            {
+                int maxInterval=getMaxInactiveInterval();
+                _expiryTime = (maxInterval <= 0 ? 0 : (time + maxInterval*1000L));
+                return true;
+            }
+            return false;
+        }
+
+
+        /**
+         * Exit from session
+         * @see org.eclipse.jetty.server.session.AbstractSession#complete()
+         */
+        @Override
+        protected void complete()
+        {
+            super.complete();
+
+            //lock so that no other thread that might be calling access can proceed until this complete is done
+            _lock.lock();
+
+            try
+            {
+                //if this is the last request thread to be in the session
+                if (_activeThreads.decrementAndGet() == 0)
+                {
+                    try
+                    {
+                        //an invalid session will already have been removed from the
+                        //local session map and deleted from the cluster. If its valid save
+                        //it to the cluster.
+                        //TODO consider doing only periodic saves if only the last access
+                        //time to the session changes
+                        if (isValid())
+                        {
+                            //if session still valid && its dirty or stale or never been synced, write it to the cluster
+                            //otherwise, we just keep the updated last access time in memory
+                            if (_dirty || getLastSyncTime() == 0 || isStale(System.currentTimeMillis()))
+                            {
+                                willPassivate();
+                                save(this);
+                                didActivate();
+                            }
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        LOG.warn("Problem saving session({})",getId(), e);
+                    } 
+                    finally
+                    {
+                        _dirty = false;
+                    }
+                }
+            }
+            finally
+            {
+                _lock.unlock();
+            }
+        }
+        
+        /** Test if the session is stale
+         * @param atTime
+         * @return
+         */
+        protected boolean isStale (long atTime)
+        {
+            return (getStaleIntervalSec() > 0) && (atTime - getLastSyncTime() >= (getStaleIntervalSec()*1000L));
+        }
+        
+        
+        /** Test if the session is dirty
+         * @return
+         */
+        protected boolean isDirty ()
+        {
+            return _dirty;
+        }
+
+        /** 
+         * Expire the session.
+         * 
+         * @see org.eclipse.jetty.server.session.AbstractSession#timeout()
+         */
+        @Override
+        protected void timeout()
+        {
+            if (LOG.isDebugEnabled()) LOG.debug("Timing out session {}", getId());
+            super.timeout();
+        }
+        
+      
+        
+        /**
+         * Reload the session from the cluster. If the node that
+         * last managed the session from the cluster is ourself,
+         * then the session does not need refreshing.
+         * NOTE: this method MUST be called with sufficient locks
+         * in place to prevent 2 or more concurrent threads from
+         * simultaneously updating the session.
+         */
+        private void refresh () 
+        throws Exception
+        {
+            //get fresh copy from the cluster
+            Session fresh = load(makeKey(getClusterId(), _context));
+
+            //if the session no longer exists, invalidate
+            if (fresh == null)
+            {
+                invalidate();
+                return;
+            }
+
+            //cluster copy assumed to be the same as we were the last
+            //node to manage it
+            if (fresh.getLastNode().equals(getLastNode()))
+                return;
+
+            setLastNode(getSessionIdManager().getWorkerName());
+            
+            //prepare for refresh
+            willPassivate();
+
+            //if fresh has no attributes, remove them
+            if (fresh.getAttributes() == 0)
+                this.clearAttributes();
+            else
+            {
+                //reconcile attributes
+                for (String key:fresh.getAttributeMap().keySet())
+                {
+                    Object freshvalue = fresh.getAttribute(key);
+
+                    //session does not already contain this attribute, so bind it
+                    if (getAttribute(key) == null)
+                    { 
+                        doPutOrRemove(key,freshvalue);
+                        bindValue(key,freshvalue);
+                    }
+                    else //session already contains this attribute, update its value
+                    {
+                        doPutOrRemove(key,freshvalue);
+                    }
+
+                }
+                // cleanup, remove values from session, that don't exist in data anymore:
+                for (String key : getNames())
+                {
+                    if (fresh.getAttribute(key) == null)
+                    {
+                        Object oldvalue = getAttribute(key);
+                        doPutOrRemove(key,null);
+                        unbindValue(key,oldvalue);
+                    }
+                }
+            }
+            //finish refresh
+            didActivate();
+        }
+
+
+        public void setExpiry (long expiry)
+        {
+            _expiryTime = expiry;
+        }
+        
+
+        public long getExpiry ()
+        {
+            return _expiryTime;
+        }
+        
+        public boolean isExpiredAt (long time)
+        {
+            if (_expiryTime <= 0)
+                return false; //never expires
+            
+            return  (_expiryTime <= time);
+        }
+        
+        public void swapId (String newId, String newNodeId)
+        {
+            //TODO probably synchronize rather than use the access/complete lock?
+            _lock.lock();
+            setClusterId(newId);
+            setNodeId(newNodeId);
+            _lock.unlock();
+        }
+        
+        @Override
+        public void setAttribute (String name, Object value)
+        {
+            Object old = changeAttribute(name, value);
+            if (value == null && old == null)
+                return; //if same as remove attribute but attribute was already removed, no change
+            
+           _dirty = true;
+        }
+        
+        
+        public String getContextPath()
+        {
+            return _contextPath;
+        }
+
+
+        public void setContextPath(String contextPath)
+        {
+            this._contextPath = contextPath;
+        }
+
+
+        public String getVHost()
+        {
+            return _vhost;
+        }
+
+
+        public void setVHost(String vhost)
+        {
+            this._vhost = vhost;
+        }
+        
+        public String getLastNode()
+        {
+            return _lastNode;
+        }
+
+
+        public void setLastNode(String lastNode)
+        {
+            _lastNode = lastNode;
+        }
+
+
+        public long getLastSyncTime()
+        {
+            return _lastSyncTime;
+        }
+
+
+        public void setLastSyncTime(long lastSyncTime)
+        {
+            _lastSyncTime = lastSyncTime;
+        }
+
+    }
+
+
+
+    
+    /**
+     * Start the session manager.
+     *
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#doStart()
+     */
+    @Override
+    public void doStart() throws Exception
+    {
+        if (_sessionIdManager == null)
+            throw new IllegalStateException("No session id manager defined");
+        
+        GCloudConfiguration config = ((GCloudSessionIdManager)_sessionIdManager).getConfig();
+        if (config == null)
+            throw new IllegalStateException("No gcloud configuration");
+        
+        
+        _datastore = DatastoreFactory.instance().get(config.getDatastoreOptions());
+        _keyFactory = _datastore.newKeyFactory().kind(KIND);
+        _converter = new SessionEntityConverter();       
+        _sessions = new ConcurrentHashMap<String, Session>();
+
+        //try and use a common scheduler, fallback to own
+        _scheduler = getSessionHandler().getServer().getBean(Scheduler.class);
+        if (_scheduler == null)
+        {
+            _scheduler = new ScheduledExecutorScheduler();
+            _ownScheduler = true;
+            _scheduler.start();
+        }
+        else if (!_scheduler.isStarted())
+            throw new IllegalStateException("Shared scheduler not started");
+ 
+        setScavengeIntervalSec(getScavengeIntervalSec());
+        
+        super.doStart();
+    }
+
+
+    /**
+     * Stop the session manager.
+     *
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#doStop()
+     */
+    @Override
+    public void doStop() throws Exception
+    {
+        super.doStop();
+
+        if (_task!=null)
+            _task.cancel();
+        _task=null;
+        if (_ownScheduler && _scheduler !=null)
+            _scheduler.stop();
+        _scheduler = null;
+
+        _sessions.clear();
+        _sessions = null;
+    }
+
+
+
+    /**
+     * Look for sessions in local memory that have expired.
+     */
+    public void scavenge ()
+    {
+        try
+        {
+            //scavenge in the database every so often
+            scavengeGCloudDataStore();
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Problem scavenging", e);
+        }
+    }
+
+ 
+    
+    protected void scavengeGCloudDataStore()
+    throws Exception
+    {
+       
+        //query the datastore for sessions that have expired
+        long now = System.currentTimeMillis();
+        
+        //give a bit of leeway so we don't immediately something that has only just expired a nanosecond ago
+        now = now - (_scavengeIntervalMs/2);
+        
+        if (LOG.isDebugEnabled())
+            LOG.debug("Scavenging for sessions expired before "+now);
+
+
+        GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+KIND+" where expiry < @1 limit "+_maxResults);
+        builder.allowLiteral(true);
+        builder.addBinding(now);
+        Query<Entity> query = builder.build();
+        QueryResults<Entity> results = _datastore.run(query);
+        
+        while (results.hasNext())
+        {          
+            Entity sessionEntity = results.next();
+            scavengeSession(sessionEntity);        
+        }
+
+    }
+
+    /**
+     * Scavenge a session that has expired
+     * @param e
+     * @throws Exception
+     */
+    protected void scavengeSession (Entity e)
+            throws Exception
+    {
+        long now = System.currentTimeMillis();
+        Session session = _converter.sessionFromEntity(e);
+        if (session == null)
+            return;
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Scavenging session: {}",session.getId());
+        //if the session isn't in memory already, put it there so we can do a normal timeout call
+         Session memSession =  _sessions.putIfAbsent(session.getId(), session);
+         if (memSession == null)
+         {
+             memSession = session;
+         }
+
+        //final check
+        if (memSession.isExpiredAt(now))
+        {
+            if (LOG.isDebugEnabled()) LOG.debug("Session {} is definitely expired", memSession.getId());
+            memSession.timeout();   
+        }
+    }
+
+    public long getScavengeIntervalSec ()
+    {
+        return _scavengeIntervalMs/1000;
+    }
+
+    
+    
+    /**
+     * Set the interval between runs of the scavenger. It should not be run too
+     * often.
+     * 
+     * 
+     * @param sec
+     */
+    public void setScavengeIntervalSec (long sec)
+    {
+
+        long old_period=_scavengeIntervalMs;
+        long period=sec*1000L;
+
+        _scavengeIntervalMs=period;
+
+        if (_scavengeIntervalMs > 0)
+        {
+            //add a bit of variability into the scavenge time so that not all
+            //nodes with the same scavenge time sync up
+            long tenPercent = _scavengeIntervalMs/10;
+            if ((System.currentTimeMillis()%2) == 0)
+                _scavengeIntervalMs += tenPercent;
+            if (LOG.isDebugEnabled())
+                LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms");
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Scavenging disabled"); 
+        }
+
+ 
+        
+        synchronized (this)
+        {
+            if (_scheduler != null && (period!=old_period || _task==null))
+            {
+                //clean up any previously scheduled scavenger
+                if (_task!=null)
+                    _task.cancel();
+
+                //start a new one
+                if (_scavengeIntervalMs > 0)
+                {
+                    if (_scavenger == null)
+                        _scavenger = new Scavenger();
+
+                    _task = _scheduler.schedule(_scavenger,_scavengeIntervalMs,TimeUnit.MILLISECONDS);
+                }
+            }
+        }
+    }
+    
+    
+    public long getStaleIntervalSec()
+    {
+        return _staleIntervalSec;
+    }
+
+
+    public void setStaleIntervalSec(long staleIntervalSec)
+    {
+        _staleIntervalSec = staleIntervalSec;
+    }
+    
+    
+    public int getMaxResults()
+    {
+        return _maxResults;
+    }
+
+
+    public void setMaxResults(int maxResults)
+    {
+        if (_maxResults <= 0)
+            _maxResults = DEFAULT_MAX_QUERY_RESULTS;
+        else
+            _maxResults = maxResults;
+    }
+
+
+    /** 
+     * Add a new session for the context related to this session manager
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#addSession(org.eclipse.jetty.server.session.AbstractSession)
+     */
+    @Override
+    protected void addSession(AbstractSession session)
+    {
+        if (session==null)
+            return;
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Adding session({}) to session manager for context {} on worker {}",session.getClusterId(), getContextPath(getContext()),getSessionIdManager().getWorkerName() + " with lastnode="+((Session)session).getLastNode());
+        _sessions.put(session.getClusterId(), (Session)session);
+        
+        try
+        {     
+                session.willPassivate();
+                save(((GCloudSessionManager.Session)session));
+                session.didActivate();
+            
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Unable to store new session id="+session.getId() , e);
+        }
+    }
+
+    /** 
+     * Ask the cluster for the session.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#getSession(java.lang.String)
+     */
+    @Override
+    public AbstractSession getSession(String idInCluster)
+    {
+        Session session = null;
+
+        //try and find the session in this node's memory
+        Session memSession = (Session)_sessions.get(idInCluster);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("getSession({}) {} in session map",idInCluster,(memSession==null?"not":""));
+
+        long now = System.currentTimeMillis();
+        try
+        {
+            //if the session is not in this node's memory, then load it from the datastore
+            if (memSession == null)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("getSession({}): loading session data from cluster", idInCluster);
+
+                session = load(makeKey(idInCluster, _context));
+                if (session != null)
+                {
+                    //Check that it wasn't expired
+                    if (session.getExpiry() > 0 && session.getExpiry() <= now)
+                    {
+                        if (LOG.isDebugEnabled()) LOG.debug("getSession ({}): Session expired", idInCluster);
+                        //ensure that the session id for the expired session is deleted so that a new session with the 
+                        //same id cannot be created (because the idInUse() test would succeed)
+                        ((GCloudSessionIdManager)getSessionIdManager()).removeSession(session);
+                        return null;  
+                    }
+
+                    //Update the last worker node to me
+                    session.setLastNode(getSessionIdManager().getWorkerName());                            
+                    //TODO consider saving session here if lastNode was not this node
+
+                    //Check that another thread hasn't loaded the same session
+                    Session existingSession = _sessions.putIfAbsent(idInCluster, session);
+                    if (existingSession != null)
+                    {
+                        //use the one that the other thread inserted
+                        session = existingSession;
+                        LOG.debug("getSession({}): using session loaded by another request thread ", idInCluster);
+                    }
+                    else
+                    {
+                        //indicate that the session was reinflated
+                        session.didActivate();
+                        LOG.debug("getSession({}): loaded session from cluster", idInCluster);
+                    }
+                    return session;
+                }
+                else
+                {
+                    //The requested session does not exist anywhere in the cluster
+                    LOG.debug("getSession({}): No session in cluster matching",idInCluster);
+                    return null;
+                }
+            }
+            else
+            {
+               //The session exists in this node's memory
+               LOG.debug("getSession({}): returning session from local memory ", memSession.getClusterId());
+                return memSession;
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Unable to load session="+idInCluster, e);
+            return null;
+        }
+    }
+    
+    
+
+    /** 
+     * The session manager is stopping.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#shutdownSessions()
+     */
+    @Override
+    protected void shutdownSessions() throws Exception
+    {
+        Set<String> keys = new HashSet<String>(_sessions.keySet());
+        for (String key:keys)
+        {
+            Session session = _sessions.remove(key); //take the session out of the session list
+            //If the session is dirty, then write it to the cluster.
+            //If the session is simply stale do NOT write it to the cluster, as some other node
+            //may have started managing that session - this means that the last accessed/expiry time
+            //will not be updated, meaning it may look like it can expire sooner than it should.
+            try
+            {
+                if (session.isDirty())
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Saving dirty session {} before exiting ", session.getId());
+                    save(session);
+                }
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+            }
+        }
+    }
+
+
+    @Override
+    protected AbstractSession newSession(HttpServletRequest request)
+    {
+        return new Session(request);
+    }
+
+    /** 
+     * Remove a session from local memory, and delete it from
+     * the cluster cache.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#removeSession(java.lang.String)
+     */
+    @Override
+    protected boolean removeSession(String idInCluster)
+    {
+        Session session = (Session)_sessions.remove(idInCluster);
+        try
+        {
+            if (session != null)
+            {
+                delete(session);
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Problem deleting session id="+idInCluster, e);
+        }
+        return session!=null;
+    }
+    
+    
+    
+    
+    @Override
+    public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId)
+    {
+        Session session = null;
+        try
+        {
+            //take the session with that id out of our managed list
+            session = (Session)_sessions.remove(oldClusterId);
+            if (session != null)
+            {
+                //TODO consider transactionality and ramifications if the session is live on another node
+                delete(session); //delete the old session from the cluster  
+                session.swapId(newClusterId, newNodeId); //update the session
+                _sessions.put(newClusterId, session); //put it into managed list under new key
+                save(session); //put the session under the new id into the cluster
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+
+        super.renewSessionId(oldClusterId, oldNodeId, newClusterId, newNodeId);
+    }
+
+
+    /**
+     * Load a session from the clustered cache.
+     * 
+     * @param key
+     * @return
+     */
+    protected Session load (Key key)
+    throws Exception
+    {
+        if (_datastore == null)
+            throw new IllegalStateException("No DataStore");
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from DataStore", key);
+
+        Entity entity = _datastore.get(key);
+        if (entity == null)
+        {
+            if (LOG.isDebugEnabled()) LOG.debug("No session {} in DataStore ",key);
+            return null;
+        }
+        else
+        {
+            Session session = _converter.sessionFromEntity(entity);
+            session.setLastSyncTime(System.currentTimeMillis());
+            return session;
+        }
+    }
+    
+    
+    
+    /**
+     * Save or update the session to the cluster cache
+     * 
+     * @param session
+     * @throws Exception
+     */
+    protected void save (GCloudSessionManager.Session session)
+    throws Exception
+    {
+        if (_datastore == null)
+            throw new IllegalStateException("No DataStore");
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to DataStore", session.getId());
+    
+        Entity entity = _converter.entityFromSession(session, makeKey(session, _context));
+        _datastore.put(entity);
+        session.setLastSyncTime(System.currentTimeMillis());
+    }
+    
+    
+    
+    /**
+     * Remove the session from the cluster cache.
+     * 
+     * @param session
+     */
+    protected void delete (GCloudSessionManager.Session session)
+    {  
+        if (_datastore == null)
+            throw new IllegalStateException("No DataStore");
+        if (LOG.isDebugEnabled()) LOG.debug("Removing session {} from DataStore", session.getId());
+        _datastore.delete(makeKey(session, _context));
+    }
+
+    
+    /**
+     * Invalidate a session for this context with the given id
+     * 
+     * @param idInCluster
+     */
+    public void invalidateSession (String idInCluster)
+    {
+        Session session = (Session)_sessions.get(idInCluster);
+
+        if (session != null)
+        {
+            session.invalidate();
+        }
+    }
+
+    
+    /**
+     * Make a unique key for this session.
+     * As the same session id can be used across multiple contexts, to
+     * make it unique, the key must be composed of:
+     * <ol>
+     * <li>the id</li>
+     * <li>the context path</li>
+     * <li>the virtual hosts</li>
+     * </ol>
+     * 
+     *TODO consider the difference between getClusterId and getId
+     * @param session
+     * @return
+     */
+    private Key makeKey (Session session, Context context)
+    {
+       return makeKey(session.getId(), context);
+    }
+    
+    /**
+     * Make a unique key for this session.
+     * As the same session id can be used across multiple contexts, to
+     * make it unique, the key must be composed of:
+     * <ol>
+     * <li>the id</li>
+     * <li>the context path</li>
+     * <li>the virtual hosts</li>
+     * </ol>
+     * 
+     *TODO consider the difference between getClusterId and getId
+     * @param session
+     * @return
+     */
+    private Key makeKey (String id, Context context)
+    {
+        String key = getContextPath(context);
+        key = key + "_" + getVirtualHost(context);
+        key = key+"_"+id;
+        return _keyFactory.newKey(key);
+    }
+    
+    /**
+     * Turn the context path into an acceptable string
+     * 
+     * @param context
+     * @return
+     */
+    private static String getContextPath (ContextHandler.Context context)
+    {
+        return canonicalize (context.getContextPath());
+    }
+
+    /**
+     * Get the first virtual host for the context.
+     *
+     * Used to help identify the exact session/contextPath.
+     *
+     * @return 0.0.0.0 if no virtual host is defined
+     */
+    private static String getVirtualHost (ContextHandler.Context context)
+    {
+        String vhost = "0.0.0.0";
+
+        if (context==null)
+            return vhost;
+
+        String [] vhosts = context.getContextHandler().getVirtualHosts();
+        if (vhosts==null || vhosts.length==0 || vhosts[0]==null)
+            return vhost;
+
+        return vhosts[0];
+    }
+
+    /**
+     * Make an acceptable name from a context path.
+     *
+     * @param path
+     * @return
+     */
+    private static String canonicalize (String path)
+    {
+        if (path==null)
+            return "";
+
+        return path.replace('/', '_').replace('.','_').replace('\\','_');
+    }
+
+}
diff --git a/jetty-gcloud/gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java b/jetty-gcloud/gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java
new file mode 100644
index 0000000..ac58dd4
--- /dev/null
+++ b/jetty-gcloud/gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java
@@ -0,0 +1,75 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.gcloud.session;
+
+
+
+
+import org.eclipse.jetty.security.HashLoginService;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+public class GCloudSessionTester
+{
+    public static void main( String[] args ) throws Exception
+    {
+        if (args.length < 4)
+            System.err.println("Usage: GCloudSessionTester projectid p12file password serviceaccount");
+        
+        System.setProperty("org.eclipse.jetty.server.session.LEVEL", "DEBUG");
+        
+        Server server = new Server(8080);
+        HashLoginService loginService = new HashLoginService();
+        loginService.setName( "Test Realm" );
+        loginService.setConfig( "../../jetty-distribution/target/distribution/demo-base/resources/realm.properties" );
+        server.addBean( loginService );
+
+        GCloudConfiguration config = new GCloudConfiguration();
+        config.setProjectId(args[0]);
+        config.setP12File(args[1]);
+        config.setPassword(args[2]);
+        config.setServiceAccount(args[3]);
+
+        GCloudSessionIdManager idmgr = new GCloudSessionIdManager(server);
+        idmgr.setConfig(config);
+        idmgr.setWorkerName("w1");
+        server.setSessionIdManager(idmgr);
+
+ 
+        WebAppContext webapp = new WebAppContext();
+        webapp.setContextPath("/");
+        webapp.setWar("../../jetty-distribution/target/distribution/demo-base/webapps/test.war");
+        webapp.addAliasCheck(new AllowSymLinkAliasChecker());
+        GCloudSessionManager mgr = new GCloudSessionManager();
+        mgr.setSessionIdManager(idmgr);
+        webapp.setSessionHandler(new SessionHandler(mgr));
+
+        // A WebAppContext is a ContextHandler as well so it needs to be set to
+        // the server so it is aware of where to send the appropriate requests.
+        server.setHandler(webapp);
+
+        // Start things up! 
+        server.start();
+
+    
+        server.join();
+    }
+}
diff --git a/jetty-gcloud/pom.xml b/jetty-gcloud/pom.xml
new file mode 100644
index 0000000..252416e
--- /dev/null
+++ b/jetty-gcloud/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>jetty-project</artifactId>
+    <groupId>org.eclipse.jetty</groupId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty.gcloud</groupId>
+  <artifactId>gcloud-parent</artifactId>
+  <packaging>pom</packaging>
+  <name>Jetty :: GCloud</name>
+
+  <properties>
+    <gcloud.version>0.0.8</gcloud.version>
+  </properties>
+
+  <modules>
+    <module>gcloud-session-manager</module>
+  </modules>
+
+</project>
diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml
index 3eee107..2c959b1 100644
--- a/jetty-http-spi/pom.xml
+++ b/jetty-http-spi/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-http-spi</artifactId>
@@ -33,35 +33,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java
index 4a24245..ef119aa 100644
--- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java
+++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/DelegatingThreadPool.java
@@ -20,7 +20,6 @@
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
index e9136da..465fa75 100644
--- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
+++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/HttpSpiContextHandler.java
@@ -46,7 +46,7 @@
 public class HttpSpiContextHandler extends ContextHandler

 {

     public static final Logger LOG = Log.getLogger(HttpSpiContextHandler.class);

-    

+

     private HttpContext _httpContext;

 

     private HttpHandler _httpHandler;

@@ -106,7 +106,7 @@
                 writer.println("</pre>");

             }

             

-            writer.println("<p><i><small><a href=\"http://eclipse.org/jetty\">Powered by jetty://</a></small></i></p>");

+            baseRequest.getHttpChannel().getHttpConfiguration().writePoweredBy(writer,"<p>","</p>");

 

             writer.close();

         }

diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java
index 492cfa0..826755e 100644
--- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java
+++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpExchange.java
@@ -32,9 +32,6 @@
 import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpPrincipal;
 
-/* ------------------------------------------------------------ */
-/**
- */
 public class JettyHttpExchange extends HttpExchange implements JettyExchange
 {
     private JettyHttpExchangeDelegate _delegate;
@@ -46,9 +43,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.http.spi.JettyExchange#hashCode()
-     */
     @Override
     public int hashCode()
     {
@@ -56,9 +50,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getRequestHeaders()
-     */
     @Override
     public Headers getRequestHeaders()
     {
@@ -66,9 +57,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getResponseHeaders()
-     */
     @Override
     public Headers getResponseHeaders()
     {
@@ -76,9 +64,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getRequestURI()
-     */
     @Override
     public URI getRequestURI()
     {
@@ -86,9 +71,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getRequestMethod()
-     */
     @Override
     public String getRequestMethod()
     {
@@ -96,9 +78,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getHttpContext()
-     */
     @Override
     public HttpContext getHttpContext()
     {
@@ -106,9 +85,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#close()
-     */
     @Override
     public void close()
     {
@@ -116,9 +92,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.http.spi.JettyExchange#equals(java.lang.Object)
-     */
     @Override
     public boolean equals(Object obj)
     {
@@ -126,9 +99,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getRequestBody()
-     */
     @Override
     public InputStream getRequestBody()
     {
@@ -136,9 +106,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getResponseBody()
-     */
     @Override
     public OutputStream getResponseBody()
     {
@@ -146,9 +113,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#sendResponseHeaders(int, long)
-     */
     @Override
     public void sendResponseHeaders(int rCode, long responseLength) throws IOException
     {
@@ -156,9 +120,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getRemoteAddress()
-     */
     @Override
     public InetSocketAddress getRemoteAddress()
     {
@@ -166,9 +127,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getResponseCode()
-     */
     @Override
     public int getResponseCode()
     {
@@ -176,9 +134,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getLocalAddress()
-     */
     @Override
     public InetSocketAddress getLocalAddress()
     {
@@ -186,9 +141,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getProtocol()
-     */
     @Override
     public String getProtocol()
     {
@@ -196,9 +148,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#getAttribute(java.lang.String)
-     */
     @Override
     public Object getAttribute(String name)
     {
@@ -206,9 +155,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#setAttribute(java.lang.String, java.lang.Object)
-     */
     @Override
     public void setAttribute(String name, Object value)
     {
@@ -216,9 +162,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see JettyHttpExchangeDelegate#setStreams(java.io.InputStream, java.io.OutputStream)
-     */
     @Override
     public void setStreams(InputStream i, OutputStream o)
     {
@@ -226,9 +169,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.http.spi.JettyExchange#getPrincipal()
-     */
     @Override
     public HttpPrincipal getPrincipal()
     {
@@ -236,18 +176,12 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.http.spi.JettyExchange#setPrincipal(com.sun.net.httpserver.HttpPrincipal)
-     */
     public void setPrincipal(HttpPrincipal principal)
     {
         _delegate.setPrincipal(principal);
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.http.spi.JettyExchange#toString()
-     */
     @Override
     public String toString()
     {
diff --git a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java
index e002081..c623d18 100644
--- a/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java
+++ b/jetty-http-spi/src/main/java/org/eclipse/jetty/http/spi/JettyHttpServer.java
@@ -28,6 +28,8 @@
 
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.NetworkConnector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
@@ -48,24 +50,35 @@
 {
     private static final Logger LOG = Log.getLogger(JettyHttpServer.class);
 
+    private final HttpConfiguration _httpConfiguration;
 
-    private Server _server;
-    
+    private final Server _server;
+
     private boolean _serverShared;
 
     private InetSocketAddress _addr;
 
-    private ThreadPoolExecutor _executor;
 
     private Map<String, JettyHttpContext> _contexts = new HashMap<String, JettyHttpContext>();
-    
+
     private Map<String, Connector> _connectors = new HashMap<String, Connector>();
 
-    
+
     public JettyHttpServer(Server server, boolean shared)
     {
+        this(server,shared,new HttpConfiguration());
+    }
+
+    public JettyHttpServer(Server server, boolean shared, HttpConfiguration configuration)
+    {
         this._server = server;
         this._serverShared = shared;
+        this._httpConfiguration = configuration;
+    }
+
+    public HttpConfiguration getHttpConfiguration()
+    {
+        return _httpConfiguration;
     }
 
     @Override
@@ -83,10 +96,10 @@
                 }
             }
         }
-        
+
         if (_serverShared)
-                throw new IOException("jetty server is not bound to port " + addr.getPort());
-        
+            throw new IOException("jetty server is not bound to port " + addr.getPort());
+
         this._addr = addr;
 
         if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort());
@@ -94,10 +107,18 @@
         connector.setPort(addr.getPort());
         connector.setHost(addr.getHostName());
         _server.addConnector(connector);
-        
+
         _connectors.put(addr.getHostName() + addr.getPort(), connector);
     }
 
+    protected ServerConnector newServerConnector(InetSocketAddress addr,int backlog)
+    {
+        ServerConnector connector = new ServerConnector(_server,new HttpConnectionFactory(_httpConfiguration));
+        connector.setPort(addr.getPort());
+        connector.setHost(addr.getHostName());
+        return connector;
+    }
+
     @Override
     public InetSocketAddress getAddress()
     {
@@ -108,7 +129,7 @@
     public void start()
     {
         if (_serverShared) return;
-        
+
         try
         {
             _server.start();
@@ -145,7 +166,7 @@
     {
         cleanUpContexts();
         cleanUpConnectors();
-        
+
         if (_serverShared) return;
 
         try
@@ -158,15 +179,15 @@
         }
     }
 
-        private void cleanUpContexts()
-        {
+    private void cleanUpContexts()
+    {
         for (Map.Entry<String, JettyHttpContext> stringJettyHttpContextEntry : _contexts.entrySet())
         {
             JettyHttpContext context = stringJettyHttpContextEntry.getValue();
             _server.removeBean(context.getJettyContextHandler());
         }
-                _contexts.clear();
-        }
+        _contexts.clear();
+    }
 
     private void cleanUpConnectors()
     {
@@ -176,15 +197,17 @@
             try
             {
                 connector.stop();
-            } catch (Exception ex) {
+            } 
+            catch (Exception ex) 
+            {
                 LOG.warn(ex);
             }
             _server.removeConnector(connector);
         }
-                _connectors.clear();
-        }
+        _connectors.clear();
+    }
 
-        @Override
+    @Override
     public HttpContext createContext(String path, HttpHandler httpHandler)
     {
         checkIfContextIsFree(path);
@@ -194,7 +217,7 @@
 
         ContextHandlerCollection chc = findContextHandlerCollection(_server.getHandlers());
         if (chc == null)
-                throw new RuntimeException("could not find ContextHandlerCollection, you must configure one");
+            throw new RuntimeException("could not find ContextHandlerCollection, you must configure one");
 
         chc.addHandler(jettyContextHandler);
         _contexts.put(path, context);
@@ -228,13 +251,13 @@
     private void checkIfContextIsFree(String path)
     {
         Handler serverHandler = _server.getHandler();
-                if (serverHandler instanceof ContextHandler)
-                {
-                        ContextHandler ctx = (ContextHandler) serverHandler;
-                        if (ctx.getContextPath().equals(path))
-                        throw new RuntimeException("another context already bound to path " + path);
-                }
-        
+        if (serverHandler instanceof ContextHandler)
+        {
+            ContextHandler ctx = (ContextHandler) serverHandler;
+            if (ctx.getContextPath().equals(path))
+                throw new RuntimeException("another context already bound to path " + path);
+        }
+
         Handler[] handlers = _server.getHandlers();
         if (handlers == null) return;
 
@@ -246,9 +269,9 @@
                     throw new RuntimeException("another context already bound to path " + path);
             }
         }
-        }
+    }
 
-        @Override
+    @Override
     public HttpContext createContext(String path)
     {
         return createContext(path, null);
diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml
index adc09cd..494e675 100644
--- a/jetty-http/pom.xml
+++ b/jetty-http/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>jetty-project</artifactId>
     <groupId>org.eclipse.jetty</groupId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-http</artifactId>
@@ -27,44 +27,16 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.net.*,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <executions>
           <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-          <execution>
             <id>test-jar</id>
             <goals>
               <goal>test-jar</goal>
             </goals>
           </execution>
         </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java
new file mode 100644
index 0000000..0ef7fa6
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/BadMessageException.java
@@ -0,0 +1,65 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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;
+
+/* ------------------------------------------------------------------------------- */
+public class BadMessageException extends RuntimeException
+{
+    final int _code;
+    final String _reason;
+
+    public BadMessageException()
+    {
+        this(400,null);
+    }
+    
+    public BadMessageException(int code)
+    {
+        this(code,null);
+    }
+    
+    public BadMessageException(String reason)
+    {
+        this(400,reason);
+    }
+    
+    public BadMessageException(int code, String reason)
+    {
+        super(code+": "+reason);
+        _code=code;
+        _reason=reason;
+    }
+    
+    public BadMessageException(int code, String reason, Throwable cause)
+    {
+        super(code+": "+reason, cause);
+        _code=code;
+        _reason=reason;
+    }
+    
+    public int getCode()
+    {
+        return _code;
+    }
+    
+    public String getReason()
+    {
+        return _reason;
+    }
+}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java
index e38d3c6..183b29f 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/DateGenerator.java
@@ -26,7 +26,6 @@
 
 /**
  * ThreadLocal Date formatters for HTTP style dates.
- *
  */
 public class DateGenerator
 {
@@ -56,6 +55,8 @@
     
     /**
      * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
+     * @param date the date in milliseconds
+     * @return the formatted date
      */
     public static String formatDate(long date)
     {
@@ -64,6 +65,8 @@
 
     /**
      * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies
+     * @param buf the buffer to put the formatted date into
+     * @param date the date in milliseconds
      */
     public static void formatCookieDate(StringBuilder buf, long date)
     {
@@ -72,6 +75,8 @@
 
     /**
      * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies
+     * @param date the date in milliseconds 
+     * @return the formatted date
      */
     public static String formatCookieDate(long date)
     {
@@ -85,6 +90,8 @@
 
     /**
      * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
+     * @param date the date in milliseconds
+     * @return the formatted date
      */
     public String doFormatDate(long date)
     {
@@ -125,6 +132,8 @@
 
     /**
      * Format "EEE, dd-MMM-yy HH:mm:ss 'GMT'" for cookies
+     * @param buf the buffer to format the date into
+     * @param date the date in milliseconds
      */
     public void doFormatCookieDate(StringBuilder buf, long date)
     {
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java
index f181ce1..8c95694 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/DateParser.java
@@ -27,7 +27,7 @@
  * ThreadLocal data parsers for HTTP style dates
  *
  */
-class DateParser
+public class DateParser
 {
     private static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
     static
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/GzipHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/GzipHttpContent.java
new file mode 100644
index 0000000..3d23734
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/GzipHttpContent.java
@@ -0,0 +1,188 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http.MimeTypes.Type;
+
+import org.eclipse.jetty.util.resource.Resource;
+
+/* ------------------------------------------------------------ */
+public class GzipHttpContent implements HttpContent
+{
+    private final HttpContent _content; 
+    private final HttpContent _contentGz;
+    public final static String ETAG_GZIP="--gzip";
+    public final static String ETAG_GZIP_QUOTE="--gzip\"";
+    public final static PreEncodedHttpField CONTENT_ENCODING_GZIP=new PreEncodedHttpField(HttpHeader.CONTENT_ENCODING,"gzip");
+    
+    public static String removeGzipFromETag(String etag)
+    {
+        if (etag==null)
+            return null;
+        int i = etag.indexOf(ETAG_GZIP_QUOTE);
+        if (i<0)
+            return etag;
+        return etag.substring(0,i)+'"';
+    }
+    
+    public GzipHttpContent(HttpContent content, HttpContent contentGz)
+    {  
+        _content=content;
+        _contentGz=contentGz;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return _content.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return _content.equals(obj);
+    }
+
+    @Override
+    public Resource getResource()
+    {
+        return _content.getResource();
+    }
+
+    @Override
+    public HttpField getETag()
+    {
+        return new HttpField(HttpHeader.ETAG,getETagValue());
+    }
+
+    @Override
+    public String getETagValue()
+    {
+        return _content.getResource().getWeakETag(ETAG_GZIP);
+    }
+
+    @Override
+    public HttpField getLastModified()
+    {
+        return _content.getLastModified();
+    }
+
+    @Override
+    public String getLastModifiedValue()
+    {
+        return _content.getLastModifiedValue();
+    }
+
+    @Override
+    public HttpField getContentType()
+    {
+        return _content.getContentType();
+    }
+
+    @Override
+    public String getContentTypeValue()
+    {
+        return _content.getContentTypeValue();
+    }
+
+    @Override
+    public HttpField getContentEncoding()
+    {
+        return CONTENT_ENCODING_GZIP;
+    }
+
+    @Override
+    public String getContentEncodingValue()
+    {
+        return CONTENT_ENCODING_GZIP.getValue();
+    }
+
+    @Override
+    public String getCharacterEncoding()
+    {
+        return _content.getCharacterEncoding();
+    }
+
+    @Override
+    public Type getMimeType()
+    {
+        return _content.getMimeType();
+    }
+
+    @Override
+    public void release()
+    {
+        _content.release();
+    }
+
+    @Override
+    public ByteBuffer getIndirectBuffer()
+    {
+        return _contentGz.getIndirectBuffer();
+    }
+
+    @Override
+    public ByteBuffer getDirectBuffer()
+    {
+        return _contentGz.getDirectBuffer();
+    }
+
+    @Override
+    public HttpField getContentLength()
+    {
+        return _contentGz.getContentLength();
+    }
+
+    @Override
+    public long getContentLengthValue()
+    {
+        return _contentGz.getContentLengthValue();
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException
+    {
+        return _contentGz.getInputStream();
+    }
+
+    @Override
+    public ReadableByteChannel getReadableByteChannel() throws IOException
+    {
+        return _contentGz.getReadableByteChannel();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("GzipHttpContent@%x{r=%s|%s,lm=%s|%s,ct=%s}",hashCode(),
+                _content.getResource(),_contentGz.getResource(),
+                _content.getResource().lastModified(),_contentGz.getResource().lastModified(),
+                getContentType());
+    }
+
+    @Override
+    public HttpContent getGzipContent()
+    {
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
new file mode 100644
index 0000000..5818e13
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
@@ -0,0 +1,106 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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 org.eclipse.jetty.util.StringUtil;
+
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class HostPortHttpField extends HttpField
+{
+    private final String _host;
+    private final int _port;
+
+    public HostPortHttpField(String authority)
+    {
+        this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority);
+    }
+    
+    public HostPortHttpField(HttpHeader header, String name, String authority)
+    {
+        super(header,name,authority);
+        if (authority==null || authority.length()==0)
+            throw new IllegalArgumentException("No Authority");
+        try
+        {
+            if (authority.charAt(0)=='[')
+            {
+                // ipv6reference
+                int close=authority.lastIndexOf(']');
+                if (close<0)
+                    throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6");
+                _host=authority.substring(0,close+1);
+
+                if (authority.length()>close+1)
+                {
+                    if (authority.charAt(close+1)!=':')
+                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port");
+                    _port=StringUtil.toInt(authority,close+2);
+                }
+                else
+                    _port=0;
+            }
+            else
+            {
+                // ipv4address or hostname
+                int c = authority.lastIndexOf(':');
+                if (c>=0)
+                {
+                    _host=authority.substring(0,c);
+                    _port=StringUtil.toInt(authority,c+1);
+                }
+                else
+                {
+                    _host=authority;
+                    _port=0;
+                }
+            }
+        }
+        catch (BadMessageException bm)
+        {
+            throw bm;
+        }
+        catch(Exception e)
+        {
+            throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad HostPort",e);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the host.
+     * @return the host
+     */
+    public String getHost()
+    {
+        return _host;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the port.
+     * @return the port
+     */
+    public int getPort()
+    {
+        return _port;
+    }
+}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java
new file mode 100644
index 0000000..aefb281
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/Http1FieldPreEncoder.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.http;
+
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+import java.util.Arrays;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class Http1FieldPreEncoder implements HttpFieldPreEncoder
+{
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion()
+     */
+    @Override
+    public HttpVersion getHttpVersion()
+    {
+        return HttpVersion.HTTP_1_0;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String)
+     */
+    @Override
+    public byte[] getEncodedField(HttpHeader header, String headerString, String value)
+    {
+        if (header!=null)
+        {
+            int cbl=header.getBytesColonSpace().length;
+            byte[] bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2);
+            System.arraycopy(value.getBytes(ISO_8859_1),0,bytes,cbl,value.length());
+            bytes[bytes.length-2]=(byte)'\r';
+            bytes[bytes.length-1]=(byte)'\n';
+            return bytes;
+        }
+
+        byte[] n=headerString.getBytes(ISO_8859_1);
+        byte[] v=value.getBytes(ISO_8859_1);
+        byte[] bytes=Arrays.copyOf(n,n.length+2+v.length+2);
+        bytes[n.length]=(byte)':';
+        bytes[n.length]=(byte)' ';
+        bytes[bytes.length-2]=(byte)'\r';
+        bytes[bytes.length-1]=(byte)'\n';
+
+        return bytes;
+    }
+}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java
index ba09880..50871af 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java
@@ -23,156 +23,58 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 
-import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.http.MimeTypes.Type;
 import org.eclipse.jetty.util.resource.Resource;
 
 /* ------------------------------------------------------------ */
-/** HttpContent.
- * 
+/** HttpContent interface.
+ * <p>This information represents all the information about a 
+ * static resource that is needed to evaluate conditional headers
+ * and to serve the content if need be.     It can be implemented
+ * either transiently (values and fields generated on demand) or 
+ * persistently (values and fields pre-generated in anticipation of
+ * reuse in from a cache).
+ * </p> 
  *
  */
 public interface HttpContent
 {
-    String getContentType();
-    String getLastModified();
+    HttpField getContentType();
+    String getContentTypeValue();
+    String getCharacterEncoding();
+    Type getMimeType();
+
+    HttpField getContentEncoding();
+    String getContentEncodingValue();
+    
+    HttpField getContentLength();
+    long getContentLengthValue();
+    
+    HttpField getLastModified();
+    String getLastModifiedValue();
+    
+    HttpField getETag();
+    String getETagValue();
+    
     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
+    HttpContent getGzipContent();
+    
+    
+    public interface Factory
     {
-        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();
-        }
-        
-        @Override
-        public String toString()
-        {
-            return String.format("%s@%x{r=%s}",this.getClass().getSimpleName(),hashCode(),_resource);
-        }
+        /**
+         * @param path The path within the context to the resource
+         * @param maxBuffer The maximum buffer to allocated for this request.  For cached content, a larger buffer may have
+         * previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls.
+         * @return A {@link HttpContent}
+         * @throws IOException
+         */
+        HttpContent getContent(String path,int maxBuffer) throws IOException;
     }
 }
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
index 55ab65c..584ed74 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
@@ -18,33 +18,39 @@
 
 package org.eclipse.jetty.http;
 
+import java.util.ArrayList;
+import java.util.Objects;
 
-/* ------------------------------------------------------------ */
+import org.eclipse.jetty.util.StringUtil;
+
 /** A HTTP Field
  */
 public class HttpField
 {
+    private final static String __zeroquality="q=0";
     private final HttpHeader _header;
     private final String _name;
     private final String _value;
-        
+    // cached hashcode for case insensitive name
+    private int hash = 0;
+
     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);
@@ -64,7 +70,303 @@
     {
         return _value;
     }
-    
+
+    public int getIntValue()
+    {
+        return Integer.valueOf(_value);
+    }
+
+    public long getLongValue()
+    {
+        return Long.valueOf(_value);
+    }
+
+    public String[] getValues()
+    {
+        ArrayList<String> list = new ArrayList<>();
+        int state = 0;
+        int start=0;
+        int end=0;
+        StringBuilder builder = new StringBuilder();
+
+        for (int i=0;i<_value.length();i++)
+        {
+            char c = _value.charAt(i);
+            switch(state)
+            {
+                case 0: // initial white space
+                    switch(c)
+                    {
+                        case '"': // open quote
+                            state=2;
+                            break;
+
+                        case ',': // ignore leading empty field
+                            break;
+
+                        case ' ': // more white space
+                        case '\t':
+                            break;
+
+                        default: // character
+                            start=i;
+                            end=i;
+                            state=1;
+                    }
+                    break;
+
+                case 1: // In token
+                    switch(c)
+                    {
+                        case ',': // next field
+                            list.add(_value.substring(start,end+1));
+                            state=0;
+                            break;
+
+                        case ' ': // more white space
+                        case '\t':
+                            break;
+
+                        default:
+                            end=i;
+                    }
+                    break;
+
+                case 2: // In Quoted
+                    switch(c)
+                    {
+                        case '\\': // next field
+                            state=3;
+                            break;
+
+                        case '"': // end quote
+                            list.add(builder.toString());
+                            builder.setLength(0);
+                            state=4;
+                            break;
+
+                        default:
+                            builder.append(c);
+                    }
+                    break;
+
+                case 3: // In Quoted Quoted
+                    builder.append(c);
+                    state=2;
+                    break;
+
+                case 4: // WS after end quote
+                    switch(c)
+                    {
+                        case ' ': // white space
+                        case '\t': // white space
+                            break;
+
+                        case ',': // white space
+                            state=0;
+                            break;
+
+                        default:
+                            throw new IllegalArgumentException("c="+(int)c);
+
+                    }
+                    break;
+            }
+        }
+
+        switch(state)
+        {
+            case 0:
+                break;
+            case 1:
+                list.add(_value.substring(start,end+1));
+                break;
+            case 4:
+                break;
+
+            default:
+                throw new IllegalArgumentException("state="+state);
+        }
+
+        return list.toArray(new String[list.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Look for a value in a possible multi valued field
+     * @param search Values to search for (case insensitive)
+     * @return True iff the value is contained in the field value entirely or
+     * as an element of a quoted comma separated list. List element parameters (eg qualities) are ignored,
+     * except if they are q=0, in which case the item itself is ignored.
+     */
+    public boolean contains(String search)
+    {
+        if (search==null)
+            return _value==null;
+        if (search.length()==0)
+            return false;
+        if (_value==null)
+            return false;
+        
+        search = StringUtil.asciiToLowerCase(search);
+
+        int state=0;
+        int match=0;
+        int param=0;
+
+        for (int i=0;i<_value.length();i++)
+        {
+            char c = _value.charAt(i);
+            switch(state)
+            {
+                case 0: // initial white space
+                    switch(c)
+                    {
+                        case '"': // open quote
+                            match=0;
+                            state=2;
+                            break;
+
+                        case ',': // ignore leading empty field
+                            break;
+
+                        case ';': // ignore leading empty field parameter
+                            param=-1;
+                            match=-1;
+                            state=5;
+                            break;
+
+                        case ' ': // more white space
+                        case '\t':
+                            break;
+
+                        default: // character
+                            match = Character.toLowerCase(c)==search.charAt(0)?1:-1;
+                            state=1;
+                            break;
+                    }
+                    break;
+
+                case 1: // In token
+                    switch(c)
+                    {
+                        case ',': // next field
+                            // Have we matched the token?
+                            if (match==search.length())
+                                return true;
+                            state=0;
+                            break;
+
+                        case ';':
+                            param=match>=0?0:-1;
+                            state=5; // parameter
+                            break;
+
+                        default:
+                            if (match>0)
+                            {
+                                if (match<search.length())
+                                    match=Character.toLowerCase(c)==search.charAt(match)?(match+1):-1;
+                                else if (c!=' ' && c!= '\t')
+                                    match=-1;
+                            }
+                            break;
+
+                    }
+                    break;
+
+                case 2: // In Quoted token
+                    switch(c)
+                    {
+                        case '\\': // quoted character
+                            state=3;
+                            break;
+
+                        case '"': // end quote
+                            state=4;
+                            break;
+
+                        default:
+                            if (match>=0)
+                            {
+                                if (match<search.length())
+                                    match=Character.toLowerCase(c)==search.charAt(match)?(match+1):-1;
+                                else
+                                    match=-1;
+                            }
+                    }
+                    break;
+
+                case 3: // In Quoted character in quoted token
+                    if (match>=0)
+                    {
+                        if (match<search.length())
+                            match=Character.toLowerCase(c)==search.charAt(match)?(match+1):-1;
+                        else
+                            match=-1;
+                    }
+                    state=2;
+                    break;
+
+                case 4: // WS after end quote
+                    switch(c)
+                    {
+                        case ' ': // white space
+                        case '\t': // white space
+                            break;
+
+                        case ';':
+                            state=5; // parameter
+                            break;
+
+                        case ',': // end token
+                            // Have we matched the token?
+                            if (match==search.length())
+                                return true;
+                            state=0;
+                            break;
+
+                        default:
+                            // This is an illegal token, just ignore
+                            match=-1;
+                    }
+                    break;
+
+                case 5:  // parameter
+                    switch(c)
+                    {
+                        case ',': // end token
+                            // Have we matched the token and not q=0?
+                            if (param!=__zeroquality.length() && match==search.length())
+                                return true;
+                            param=0;
+                            state=0;
+                            break;
+
+                        case ' ': // white space
+                        case '\t': // white space
+                            break;
+
+                        default:
+                            if (param>=0)
+                            {
+                                if (param<__zeroquality.length())
+                                    param=Character.toLowerCase(c)==__zeroquality.charAt(param)?(param+1):-1;
+                                else if (c!='0'&&c!='.')
+                                    param=-1;
+                            }
+
+                    }
+                    break;
+
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+
+        return param!=__zeroquality.length() && match==search.length();
+    }
+
+
     @Override
     public String toString()
     {
@@ -72,7 +374,7 @@
         return getName() + ": " + (v==null?"":v);
     }
 
-    public boolean isSame(HttpField field)
+    public boolean isSameName(HttpField field)
     {
         if (field==null)
             return false;
@@ -84,6 +386,125 @@
             return true;
         return false;
     }
-    
-    
+
+    private int nameHashCode()
+    {
+        int h = this.hash;
+        int len = _name.length();
+        if (h == 0 && len > 0)
+        {
+            for (int i = 0; i < len; i++)
+            {
+                // simple case insensitive hash
+                char c = _name.charAt(i);
+                // assuming us-ascii (per last paragraph on http://tools.ietf.org/html/rfc7230#section-3.2.4)
+                if ((c >= 'a' && c <= 'z'))
+                    c -= 0x20;
+                h = 31 * h + c;
+            }
+            this.hash = h;
+        }
+        return h;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        if (_header==null)
+            return _value.hashCode() ^ nameHashCode();
+        return _value.hashCode() ^ _header.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (o==this)
+            return true;
+        if (!(o instanceof HttpField))
+            return false;
+        HttpField field=(HttpField)o;
+        if (_header!=field.getHeader())
+            return false;
+        if (!_name.equalsIgnoreCase(field.getName()))
+            return false;
+        if (_value==null && field.getValue()!=null)
+            return false;
+        return Objects.equals(_value,field.getValue());
+    }
+
+    public static class IntValueHttpField extends HttpField
+    {
+        private final int _int;
+
+        public IntValueHttpField(HttpHeader header, String name, String value, int intValue)
+        {
+            super(header,name,value);
+            _int=intValue;
+        }
+
+        public IntValueHttpField(HttpHeader header, String name, String value)
+        {
+            this(header,name,value,Integer.valueOf(value));
+        }
+
+        public IntValueHttpField(HttpHeader header, String name, int intValue)
+        {
+            this(header,name,Integer.toString(intValue),intValue);
+        }
+
+        public IntValueHttpField(HttpHeader header, int value)
+        {
+            this(header,header.asString(),value);
+        }
+
+        @Override
+        public int getIntValue()
+        {
+            return _int;
+        }
+
+        @Override
+        public long getLongValue()
+        {
+            return _int;
+        }
+    }
+
+    public static class LongValueHttpField extends HttpField
+    {
+        private final long _long;
+
+        public LongValueHttpField(HttpHeader header, String name, String value, long longValue)
+        {
+            super(header,name,value);
+            _long=longValue;
+        }
+
+        public LongValueHttpField(HttpHeader header, String name, String value)
+        {
+            this(header,name,value,Long.valueOf(value));
+        }
+
+        public LongValueHttpField(HttpHeader header, String name, long value)
+        {
+            this(header,name,Long.toString(value),value);
+        }
+
+        public LongValueHttpField(HttpHeader header,long value)
+        {
+            this(header,header.asString(),value);
+        }
+
+        @Override
+        public int getIntValue()
+        {
+            return (int)_long;
+        }
+
+        @Override
+        public long getLongValue()
+        {
+            return _long;
+        }
+    }
 }
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java
new file mode 100644
index 0000000..0b1e4d4
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFieldPreEncoder.java
@@ -0,0 +1,36 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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;
+
+
+/* ------------------------------------------------------------ */
+/** Interface to pre-encode HttpFields.  Used by {@link PreEncodedHttpField}
+ */
+public interface HttpFieldPreEncoder
+{
+    /* ------------------------------------------------------------ */
+    /** The major version this encoder is for.  Both HTTP/1.0 and HTTP/1.1
+     * use the same field encoding, so the {@link HttpVersion#HTTP_1_0} should
+     * be return for all HTTP/1.x encodings.
+     * @return The major version this encoder is for.
+     */
+    HttpVersion getHttpVersion();
+    byte[] getEncodedField(HttpHeader header, String headerString, String value);
+}
\ No newline at end of file
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
index 6bec4d9..40ffd55 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
@@ -19,7 +19,7 @@
 package org.eclipse.jetty.http;
 
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -30,12 +30,10 @@
 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;
@@ -52,68 +50,95 @@
  */
 public class HttpFields implements Iterable<HttpField>
 {
+    public static final String __separators = ", \t";
+
     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);
-
+    private HttpField[] _fields;
+    private int _size;
+    
     /**
-     * Constructor.
+     * Initialize an empty HttpFields.
      */
     public HttpFields()
     {
+        _fields=new HttpField[20];
+    }
+    
+    /**
+     * Initialize an empty HttpFields.
+     * 
+     * @param capacity the capacity of the http fields
+     */
+    public HttpFields(int capacity)
+    {
+        _fields=new HttpField[capacity];
+    }
+    
+    /**
+     * Initialize HttpFields from copy.
+     * 
+     * @param fields the fields to copy data from
+     */
+    public HttpFields(HttpFields fields)
+    {
+        _fields=Arrays.copyOf(fields._fields,fields._fields.length+10);
+        _size=fields._size;
+    }
+
+    public int size()
+    {
+        return _size;
+    }
+    
+    @Override
+    public Iterator<HttpField> iterator()
+    {
+        return new Itr();
     }
 
     /**
      * Get Collection of header names.
+     * @return the unique set of field names.
      */
-    public Collection<String> getFieldNamesCollection()
+    public Set<String> getFieldNamesCollection()
     {
-        final Set<String> list = new HashSet<>(_fields.size());
-        for (HttpField f : _fields)
+        final Set<String> set = new HashSet<>(_size);
+        for (HttpField f : this)
         {
             if (f!=null)
-                list.add(f.getName());
+                set.add(f.getName());
         }
-        return list;
+        return set;
     }
 
     /**
      * Get enumeration of header _names. Returns an enumeration of strings representing the header
      * _names for this request.
+     * @return an enumeration of field names
      */
     public Enumeration<String> getFieldNames()
     {
         return Collections.enumeration(getFieldNamesCollection());
     }
 
-    public int size()
-    {
-        return _fields.size();
-    }
-
     /**
      * Get a Field by index.
+     * @param index the field index 
      * @return A Field value or null if the Field value has not been set
-     *
      */
-    public HttpField getField(int i)
+    public HttpField getField(int index)
     {
-        return _fields.get(i);
-    }
-
-    @Override
-    public Iterator<HttpField> iterator()
-    {
-        return _fields.iterator();
+        if (index>=_size)
+            throw new NoSuchElementException();
+        return _fields[index];
     }
 
     public HttpField getField(HttpHeader header)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=0;i<_size;i++)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getHeader()==header)
                 return f;
         }
@@ -122,21 +147,32 @@
 
     public HttpField getField(String name)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=0;i<_size;i++)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getName().equalsIgnoreCase(name))
                 return f;
         }
         return null;
     }
-    
+
+    public boolean contains(HttpField field)
+    {
+        for (int i=_size;i-->0;)
+        {
+            HttpField f=_fields[i];
+            if (f.isSameName(field) && f.contains(field.getValue()))
+                return true;
+        }
+        return false;
+    }
+
     public boolean contains(HttpHeader header, String value)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
-            if (f.getHeader()==header && contains(f,value))
+            HttpField f=_fields[i];
+            if (f.getHeader()==header && f.contains(value))
                 return true;
         }
         return false;
@@ -144,39 +180,20 @@
     
     public boolean contains(String name, String value)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
-            if (f.getName().equalsIgnoreCase(name) && contains(f,value))
+            HttpField f=_fields[i];
+            if (f.getName().equalsIgnoreCase(name) && f.contains(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 contains(HttpHeader header)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getHeader()==header)
                 return true;
         }
@@ -185,42 +202,49 @@
     
     public boolean containsKey(String name)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getName().equalsIgnoreCase(name))
                 return true;
         }
         return false;
     }
-    
-    
+
+    @Deprecated
     public String getStringField(HttpHeader header)
     {
-        return getStringField(header.asString());
+        return get(header);
     }
-
+    
     public String get(HttpHeader header)
     {
-        return getStringField(header.asString());
+        for (int i=0;i<_size;i++)
+        {
+            HttpField f=_fields[i];
+            if (f.getHeader()==header)
+                return f.getValue();
+        }
+        return null;
     }
 
-    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
-     */
+    @Deprecated
     public String getStringField(String name)
     {
-        HttpField field = getField(name);
-        return field==null?null:field.getValue();
+        return get(name);
     }
-
+    
+    public String get(String header)
+    {
+        for (int i=0;i<_size;i++)
+        {
+            HttpField f=_fields[i];
+            if (f.getName().equalsIgnoreCase(header))
+                return f.getValue();
+        }
+        return null;
+    }
+    
     /**
      * Get multi headers
      *
@@ -230,7 +254,7 @@
     public List<String> getValuesList(String name)
     {
         final List<String> list = new ArrayList<>();
-        for (HttpField f : _fields)
+        for (HttpField f : this)
             if (f.getName().equalsIgnoreCase(name))
                 list.add(f.getValue());
         return list;
@@ -244,9 +268,9 @@
      */
     public Enumeration<String> getValues(final String name)
     {
-        for (int i=0;i<_fields.size();i++)
+        for (int i=0;i<_size;i++)
         {
-            final HttpField f = _fields.get(i);
+            final HttpField f = _fields[i];
             
             if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null)
             {
@@ -261,9 +285,9 @@
                     {
                         if (field==null)
                         {
-                            while (i<_fields.size()) 
+                            while (i<_size) 
                             {
-                                field=_fields.get(i++);
+                                field=_fields[i++];
                                 if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null)
                                     return true;
                             }
@@ -284,7 +308,6 @@
                         }
                         throw new NoSuchElementException();
                     }
-
                 };
             }
         }
@@ -342,22 +365,24 @@
     public void put(HttpField field)
     {
         boolean put=false;
-        for (int i=_fields.size();i-->0;)
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
-            if (f.isSame(field))
+            HttpField f=_fields[i];
+            if (f.isSameName(field))
             {
                 if (put)
-                    _fields.remove(i);
+                {
+                    System.arraycopy(_fields,i+1,_fields,i,--_size-i);
+                }
                 else
                 {
-                    _fields.set(i,field);
+                    _fields[i]=field;
                     put=true;
                 }
             }
         }
         if (!put)
-            _fields.add(field);
+            add(field);
     }
     
     /**
@@ -413,19 +438,17 @@
      *
      * @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
+    public void add(String name, String value)
     {
         if (value == null)
             return;
 
         HttpField field = new HttpField(name, value);
-        _fields.add(field);
+        add(field);
     }
 
-    public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
+    public void add(HttpHeader header, HttpHeaderValue value)
     {
         add(header,value.toString());
     }
@@ -436,46 +459,55 @@
      *
      * @param header the header
      * @param value the value of the field.
-     * @exception IllegalArgumentException 
      */
-    public void add(HttpHeader header, String value) throws IllegalArgumentException
+    public void add(HttpHeader header, String value)
     {
         if (value == null) throw new IllegalArgumentException("null value");
 
         HttpField field = new HttpField(header, value);
-        _fields.add(field);
+        add(field);
     }
 
     /**
      * Remove a field.
      *
      * @param name the field to remove
+     * @return the header that was removed
      */
     public HttpField remove(HttpHeader name)
     {
-        for (int i=_fields.size();i-->0;)
+        HttpField removed=null;
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getHeader()==name)
-                return _fields.remove(i);
+            {
+                removed=f;
+                System.arraycopy(_fields,i+1,_fields,i,--_size-i);
+            }
         }
-        return null;
+        return removed;
     }
 
     /**
      * Remove a field.
      *
      * @param name the field to remove
+     * @return the header that was removed
      */
     public HttpField remove(String name)
     {
-        for (int i=_fields.size();i-->0;)
+        HttpField removed=null;
+        for (int i=_size;i-->0;)
         {
-            HttpField f=_fields.get(i);
+            HttpField f=_fields[i];
             if (f.getName().equalsIgnoreCase(name))
-                return _fields.remove(i);
+            {
+                removed=f;
+                System.arraycopy(_fields,i+1,_fields,i,--_size-i);
+            }
         }
-        return null;
+        return removed;
     }
 
     /**
@@ -483,12 +515,13 @@
      * case of the field name is ignored.
      *
      * @param name the case-insensitive field name
+     * @return the value of the field as a long
      * @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());
+        return field==null?-1L:field.getLongValue();
     }
 
     /**
@@ -496,6 +529,7 @@
      * of the field name is ignored.
      *
      * @param name the case-insensitive field name
+     * @return the value of the field as a number of milliseconds since unix epoch
      */
     public long getDateField(String name)
     {
@@ -576,13 +610,47 @@
     }
 
     @Override
-    public String
-    toString()
+    public int hashCode()
+    {
+        int hash=0;
+        for (HttpField field:_fields)
+            hash+=field.hashCode();
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+            return true;
+        if (!(o instanceof HttpFields))
+            return false;
+
+        HttpFields that = (HttpFields)o;
+
+        // Order is not important, so we cannot rely on List.equals().
+        if (size() != that.size())
+            return false;
+
+        loop: for (HttpField fi : this)
+        {
+            for (HttpField fa : that)
+            {
+                if (fi.equals(fa))
+                    continue loop;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
     {
         try
         {
             StringBuilder buffer = new StringBuilder();
-            for (HttpField field : _fields)
+            for (HttpField field : this)
             {
                 if (field != null)
                 {
@@ -604,21 +672,27 @@
         }
     }
 
-    /**
-     * Clear the header.
-     */
     public void clear()
     {
-        _fields.clear();
+        _size=0;
     }
-
+    
     public void add(HttpField field)
     {
-        _fields.add(field);
+        if (field!=null)
+        {
+            if (_size==_fields.length)
+                _fields=Arrays.copyOf(_fields,_size*2);
+            _fields[_size++]=field;
+        }
     }
 
-    
-    
+    public void addAll(HttpFields fields)
+    {
+        for (int i=0;i<fields._size;i++)
+            add(fields._fields[i]);
+    }
+
     /**
      * Add fields from another HttpFields instance. Single valued fields are replaced, while all
      * others are added.
@@ -792,5 +866,34 @@
     }
 
 
+    private class Itr implements Iterator<HttpField> 
+    {
+        int _cursor;       // index of next element to return
+        int _last=-1;
+
+        public boolean hasNext() 
+        {
+            return _cursor != _size;
+        }
+
+        public HttpField next() 
+        {
+            int i = _cursor;
+            if (i >= _size)
+                throw new NoSuchElementException();
+            _cursor = i + 1;
+            return _fields[_last=i];
+        }
+
+        public void remove() 
+        {
+            if (_last<0)
+                throw new IllegalStateException();
+
+            System.arraycopy(_fields,_last+1,_fields,_last,--_size-_last);
+            _cursor=_last;
+            _last=-1;
+        }
+    }
 
 }
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
index 6f7ead3..79e5a89 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
@@ -32,28 +31,26 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* ------------------------------------------------------------ */
 /**
  * HttpGenerator. Builds HTTP Messages.
- *
+ * <p>
  * 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"); 
+    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);
+    public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,100,null,null,-1);
+    public static final MetaData.Response PROGRESS_102_INFO = new MetaData.Response(HttpVersion.HTTP_1_1,102,null,null,-1);
+    public final static MetaData.Response RESPONSE_500_INFO =
+        new MetaData.Response(HttpVersion.HTTP_1_1,HttpStatus.INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0);
 
     // states
     public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
@@ -92,7 +89,7 @@
     {
         this(false,false);
     }
-    
+
     /* ------------------------------------------------------------------------------- */
     public HttpGenerator(boolean sendServerVersion,boolean sendXPoweredBy)
     {
@@ -165,7 +162,7 @@
     {
         return _noContent;
     }
-    
+
     /* ------------------------------------------------------------ */
     public void setPersistent(boolean persistent)
     {
@@ -202,7 +199,7 @@
     }
 
     /* ------------------------------------------------------------ */
-    public Result generateRequest(RequestInfo info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
+    public Result generateRequest(MetaData.Request info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
     {
         switch(_state)
         {
@@ -211,13 +208,16 @@
                 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());
+                {
+                    _persistent=info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal();
+                    if (!_persistent && HttpMethod.CONNECT.is(info.getMethod()))
+                        _persistent=true;
+                }
 
                 // prepare the header
                 int pos=BufferUtil.flipToFill(header);
@@ -226,12 +226,12 @@
                     // generate ResponseLine
                     generateRequestLine(info,header);
 
-                    if (info.getHttpVersion()==HttpVersion.HTTP_0_9)
-                        _noContent=true;
-                    else
-                        generateHeaders(info,header,content,last);
+                    if (info.getVersion()==HttpVersion.HTTP_0_9)
+                        throw new IllegalArgumentException("HTTP/0.9 not supported");
+                    
+                    generateHeaders(info,header,content,last);
 
-                    boolean expect100 = info.getHttpFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
+                    boolean expect100 = info.getFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
 
                     if (expect100)
                     {
@@ -254,7 +254,7 @@
                 }
                 catch(Exception e)
                 {
-                    String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage();
+                    String message= (e instanceof BufferOverflowException)?"Request header too large":e.getMessage();
                     throw new IOException(message,e);
                 }
                 finally
@@ -283,12 +283,9 @@
                 }
 
                 if (last)
-                {
                     _state=State.COMPLETING;
-                    return len>0?Result.FLUSH:Result.CONTINUE;
-                }
 
-                return Result.FLUSH;
+                return len>0?Result.FLUSH:Result.CONTINUE;
             }
 
             case COMPLETING:
@@ -331,7 +328,13 @@
     }
 
     /* ------------------------------------------------------------ */
-    public Result generateResponse(ResponseInfo info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
+    public Result generateResponse(MetaData.Response info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
+    {
+        return generateResponse(info,false,header,chunk,content,last);
+    }
+
+    /* ------------------------------------------------------------ */
+    public Result generateResponse(MetaData.Response info, boolean head, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
     {
         switch(_state)
         {
@@ -339,26 +342,27 @@
             {
                 if (info==null)
                     return Result.NEED_INFO;
-
-                // Handle 0.9
-                if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
+                
+                switch(info.getVersion())
                 {
-                    _persistent = false;
-                    _endOfContent=EndOfContent.EOF_CONTENT;
-                    if (BufferUtil.hasContent(content))
-                        _contentPrepared+=content.remaining();
-                    _state = last?State.COMPLETING:State.COMMITTED;
-                    return Result.FLUSH;
+                    case HTTP_1_0:
+                        if (_persistent==null)
+                            _persistent=Boolean.FALSE;
+                        break;
+                        
+                    case HTTP_1_1:
+                        if (_persistent==null)
+                            _persistent=Boolean.TRUE;
+                        break;
+                        
+                    default:
+                        throw new IllegalArgumentException(info.getVersion()+" not supported");
                 }
-
+                
                 // 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
@@ -391,7 +395,7 @@
                     if (len>0)
                     {
                         _contentPrepared+=len;
-                        if (isChunking() && !info.isHead())
+                        if (isChunking() && !head)
                             prepareChunk(header,len);
                     }
                     _state = last?State.COMPLETING:State.COMMITTED;
@@ -506,26 +510,18 @@
     }
 
     /* ------------------------------------------------------------ */
-    private void generateRequestLine(RequestInfo request,ByteBuffer header)
+    private void generateRequestLine(MetaData.Request 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(StringUtil.getBytes(request.getURIString()));
+        header.put((byte)' ');
+        header.put(request.getVersion().toBytes());
         header.put(HttpTokens.CRLF);
     }
 
     /* ------------------------------------------------------------ */
-    private void generateResponseLine(ResponseInfo response, ByteBuffer header)
+    private void generateResponseLine(MetaData.Response response, ByteBuffer header)
     {
         // Look for prepared response line
         int status=response.getStatus();
@@ -575,10 +571,10 @@
     }
 
     /* ------------------------------------------------------------ */
-    private void generateHeaders(Info _info,ByteBuffer header,ByteBuffer content,boolean last)
+    private void generateHeaders(MetaData _info,ByteBuffer header,ByteBuffer content,boolean last)
     {
-        final RequestInfo request=(_info instanceof RequestInfo)?(RequestInfo)_info:null;
-        final ResponseInfo response=(_info instanceof ResponseInfo)?(ResponseInfo)_info:null;
+        final MetaData.Request request=(_info instanceof MetaData.Request)?(MetaData.Request)_info:null;
+        final MetaData.Response response=(_info instanceof MetaData.Response)?(MetaData.Response)_info:null;
 
         // default field values
         int send=_send;
@@ -587,122 +583,132 @@
         boolean close=false;
         boolean content_type=false;
         StringBuilder connection = null;
+        long content_length = _info.getContentLength();
 
         // Generate fields
-        if (_info.getHttpFields() != null)
+        HttpFields fields = _info.getFields();
+        if (fields != null)
         {
-            for (HttpField field : _info.getHttpFields())
+            int n=fields.size();
+            for (int f=0;f<n;f++)
             {
+                HttpField field = fields.getField(f);
+                String v = field.getValue();
+                if (v==null || v.length()==0)
+                    continue; // rfc7230 does not allow no value
+
                 HttpHeader h = field.getHeader();
-
-                switch (h==null?HttpHeader.UNKNOWN:h)
+                if (h==null)
+                    putTo(field,header);
+                else
                 {
-                    case CONTENT_LENGTH:
-                        // handle specially below
-                        if (_info.getContentLength()>=0)
+                    switch (h)
+                    {
+                        case CONTENT_LENGTH:
                             _endOfContent=EndOfContent.CONTENT_LENGTH;
-                        break;
+                            if (content_length<0)
+                                content_length=Long.valueOf(field.getValue());
+                            // handle setting the field specially below
+                            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)
+                        case CONTENT_TYPE:
+                        {
+                            // write the field to the header
+                            content_type=true;
                             putTo(field,header);
+                            break;
+                        }
 
-                        // 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)
+                        case TRANSFER_ENCODING:
                         {
+                            if (_info.getVersion() == 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 = StringUtil.csvSplit(field.getValue());
-                            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:
+                                if (split.length>0)
                                 {
-                                    // special case for websocket connection ordering
-                                    header.put(HttpHeader.CONNECTION.getBytesColonSpace()).put(HttpHeader.UPGRADE.getBytes());
-                                    header.put(CRLF);
-                                    break;
+                                    values=new HttpHeaderValue[split.length];
+                                    for (int i=0;i<split.length;i++)
+                                        values[i]=HttpHeaderValue.CACHE.get(split[i]);
                                 }
+                            }
 
-                                case CLOSE:
+                            // Handle connection values
+                            for (int i=0;i<values.length;i++)
+                            {
+                                HttpHeaderValue value=values[i];
+                                switch (value==null?HttpHeaderValue.UNKNOWN:value)
                                 {
-                                    close=true;
-                                    if (response!=null)
+                                    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;
                                         _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;
+                                        {
+                                            if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
+                                                _endOfContent=EndOfContent.EOF_CONTENT;
+                                        }
+                                        break;
                                     }
-                                    break;
-                                }
 
-                                default:
-                                {
-                                    if (connection==null)
-                                        connection=new StringBuilder();
-                                    else
-                                        connection.append(',');
-                                    connection.append(split==null?field.getValue():split[i]);
+                                    case KEEP_ALIVE:
+                                    {
+                                        if (_info.getVersion() == 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;
                         }
 
-                        // Do NOT add yet!
-                        break;
-                    }
+                        case SERVER:
+                        {
+                            send=send&~SEND_SERVER;
+                            putTo(field,header);
+                            break;
+                        }
 
-                    case SERVER:
-                    {
-                        send=send&~SEND_SERVER;
-                        putTo(field,header);
-                        break;
+                        default:
+                            putTo(field,header);
                     }
-
-                    default:
-                        putTo(field,header);
                 }
             }
         }
@@ -710,13 +716,15 @@
 
         // Calculate how to end _content and connection, _content length and transfer encoding
         // settings.
+        // From http://tools.ietf.org/html/rfc7230#section-3.3.3
         // 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
+        // 3. If Transfer-Encoding==(.*,)?chunked && HTTP/1.1 && !HttpConnection==close then chunk
+        // 5. Content-Length without Transfer-Encoding
+        // 6. Request and none over the above, then Content-Length=0 if POST/PUT
+        // 7. close
+        
+        
         int status=response!=null?response.getStatus():-1;
         switch (_endOfContent)
         {
@@ -725,13 +733,12 @@
                 // written yet?
 
                 // Response known not to have a body
-                if (_contentPrepared == 0 && response!=null && (status < 200 || status == 204 || status == 304))
+                if (_contentPrepared == 0 && response!=null && _noContent)
                     _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.
@@ -744,20 +751,13 @@
                 {
                     // 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);
+                    long actual_length = _contentPrepared+BufferUtil.length(content);
 
+                    if (content_length>=0 && content_length!=actual_length)
+                        throw new IllegalArgumentException("Content-Length header("+content_length+") != actual("+actual_length+")");
+                    
                     // Do we need to tell the headers about it
-                    if (content_length>0)
-                    {
-                        header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
-                        BufferUtil.putDecLong(header, content_length);
-                        header.put(HttpTokens.CRLF);
-                    }
-                    else if (!_noContent)
-                    {
-                        if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
-                            header.put(CONTENT_LENGTH_0);
-                    }
+                    putContentLength(header,actual_length,content_type,request,response);
                 }
                 else
                 {
@@ -767,25 +767,16 @@
                     // 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())
+                    if (!isPersistent() || _info.getVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal())
                         _endOfContent = EndOfContent.EOF_CONTENT;
                 }
                 break;
 
             case CONTENT_LENGTH:
-                long content_length = _info.getContentLength();
-                if (content_length>0)
-                {
-                    header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
-                    BufferUtil.putDecLong(header, content_length);
-                    header.put(HttpTokens.CRLF);
-                }
-                else if (!_noContent)
-                {
-                    if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
-                        header.put(CONTENT_LENGTH_0);
-                }
+            {
+                putContentLength(header,content_length,content_type,request,response);
                 break;
+            }
 
             case NO_CONTENT:
                 throw new IllegalStateException();
@@ -827,7 +818,7 @@
         // If this is a response, work out persistence
         if (response!=null)
         {
-            if (!isPersistent() && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
+            if (!isPersistent() && (close || _info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
             {
                 if (connection==null)
                     header.put(CONNECTION_CLOSE);
@@ -867,6 +858,22 @@
     }
 
     /* ------------------------------------------------------------------------------- */
+    private void putContentLength(ByteBuffer header, long contentLength, boolean contentType, MetaData.Request request, MetaData.Response response)
+    {
+        if (contentLength>0)
+        {
+            header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
+            BufferUtil.putDecLong(header, contentLength);
+            header.put(HttpTokens.CRLF);
+        }
+        else if (!_noContent)
+        {
+            if (contentType || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
+                header.put(CONTENT_LENGTH_0);
+        }
+    }
+
+    /* ------------------------------------------------------------------------------- */
     public static byte[] getReasonBuffer(int code)
     {
         PreparedResponse status = code<__preprepared.length?__preprepared[code]:null;
@@ -879,8 +886,9 @@
     @Override
     public String toString()
     {
-        return String.format("%s{s=%s}",
+        return String.format("%s@%x{s=%s}",
                 getClass().getSimpleName(),
+                hashCode(),
                 _state);
     }
 
@@ -942,110 +950,13 @@
         }
     }
 
-    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
@@ -1059,7 +970,7 @@
         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
@@ -1069,9 +980,9 @@
 
     public static void putTo(HttpField field, ByteBuffer bufferInFillMode)
     {
-        if (field instanceof CachedHttpField)
+        if (field instanceof PreEncodedHttpField)
         {
-            ((CachedHttpField)field).putTo(bufferInFillMode);
+            ((PreEncodedHttpField)field).putTo(bufferInFillMode,HttpVersion.HTTP_1_0);
         }
         else
         {
@@ -1092,7 +1003,7 @@
         }
     }
 
-    public static void putTo(HttpFields fields, ByteBuffer bufferInFillMode) 
+    public static void putTo(HttpFields fields, ByteBuffer bufferInFillMode)
     {
         for (HttpField field : fields)
         {
@@ -1101,23 +1012,4 @@
         }
         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/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
index a62f5f2..b57a5fa 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
@@ -110,17 +110,30 @@
     IDENTITY("identity"),
     
     X_POWERED_BY("X-Powered-By"),
+    HTTP2_SETTINGS("HTTP2-Settings"),
 
+    STRICT_TRANSPORT_SECURITY("Strict-Transport-Security"),
+    
+    /* ------------------------------------------------------------ */
+    /** HTTP2 Fields.
+     */
+    C_METHOD(":method"),
+    C_SCHEME(":scheme"),
+    C_AUTHORITY(":authority"),
+    C_PATH(":path"),
+    C_STATUS(":status"),
+    
     UNKNOWN("::UNKNOWN::");
 
 
     /* ------------------------------------------------------------ */
-    public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(512);
+    public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(560);
     static
     {
         for (HttpHeader header : HttpHeader.values())
             if (header!=UNKNOWN)
-                CACHE.put(header.toString(),header);
+                if (!CACHE.put(header.toString(),header))
+                    throw new IllegalStateException();
     }
     
     private final String _string;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index e1ddee8..ad03a37 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -18,24 +18,29 @@
 
 package org.eclipse.jetty.http;
 
-import static org.eclipse.jetty.http.HttpTokens.*;
+import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
+import static org.eclipse.jetty.http.HttpTokens.LINE_FEED;
+import static org.eclipse.jetty.http.HttpTokens.SPACE;
+import static org.eclipse.jetty.http.HttpTokens.TAB;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.EnumSet;
 
 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.Utf8StringBuilder;
 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
+/** A Parser for 1.0 and 1.1 as defined by RFC7230
  * <p>
  * This parser parses HTTP client and server messages from buffers
  * passed in the {@link #parseNext(ByteBuffer)} method.  The parsed
@@ -73,6 +78,8 @@
  * fields.  Otherwise a fast case insensitive string lookup is used that may alter the
  * case of the method and/or headers
  * </p>
+ * <p>
+ * @see <a href="http://tools.ietf.org/html/rfc7230">RFC 7230</a>
  */
 public class HttpParser
 {
@@ -119,13 +126,17 @@
         CHUNK,
         CHUNK_END,
         END,
-        CLOSED
+        CLOSE,  // The associated stream/endpoint should be closed
+        CLOSED  // The associated stream/endpoint is at EOF
     }
 
+    private final static EnumSet<State> __idleStates = EnumSet.of(State.START,State.END,State.CLOSE,State.CLOSED);
+    private final static EnumSet<State> __completeStates = EnumSet.of(State.END,State.CLOSE,State.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 HttpHandler _handler;
+    private final RequestHandler _requestHandler;
+    private final ResponseHandler _responseHandler;
     private final int _maxHeaderBytes;
     private final boolean _strict;
     private HttpField _field;
@@ -140,11 +151,10 @@
     /* ------------------------------------------------------------------------------- */
     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 Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune?
     private EndOfContent _endOfContent;
     private long _contentLength;
     private long _contentPosition;
@@ -184,13 +194,15 @@
         // 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);
+            HttpField field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type);
             CACHE.put(field);
             
-            for (String charset : new String[]{"UTF-8","ISO-8859-1"})
+            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));
+                CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset));
+                CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset));
+                CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset.toUpperCase()));
+                CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset.toUpperCase()));
             }
         }
     
@@ -207,31 +219,31 @@
     }
 
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(RequestHandler<ByteBuffer> handler)
+    public HttpParser(RequestHandler handler)
     {
         this(handler,-1,__STRICT);
     }
 
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(ResponseHandler<ByteBuffer> handler)
+    public HttpParser(ResponseHandler handler)
     {
         this(handler,-1,__STRICT);
     }
 
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
+    public HttpParser(RequestHandler handler,int maxHeaderBytes)
     {
         this(handler,maxHeaderBytes,__STRICT);
     }
 
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
+    public HttpParser(ResponseHandler handler,int maxHeaderBytes)
     {
         this(handler,maxHeaderBytes,__STRICT);
     }
     
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
+    public HttpParser(RequestHandler handler,int maxHeaderBytes,boolean strict)
     {
         _handler=handler;
         _requestHandler=handler;
@@ -241,7 +253,7 @@
     }
 
     /* ------------------------------------------------------------------------------- */
-    public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
+    public HttpParser(ResponseHandler handler,int maxHeaderBytes,boolean strict)
     {
         _handler=handler;
         _requestHandler=null;
@@ -264,7 +276,7 @@
 
     /* ------------------------------------------------------------ */
     /** Set if a HEAD response is expected
-     * @param head
+     * @param head true if head response is expected
      */
     public void setHeadResponse(boolean head)
     {
@@ -308,6 +320,12 @@
     }
 
     /* ------------------------------------------------------------ */
+    public boolean isClose()
+    {
+        return isState(State.CLOSE);
+    }
+
+    /* ------------------------------------------------------------ */
     public boolean isClosed()
     {
         return isState(State.CLOSED);
@@ -316,13 +334,13 @@
     /* ------------------------------------------------------------ */
     public boolean isIdle()
     {
-        return isState(State.START)||isState(State.END)||isState(State.CLOSED);
+        return __idleStates.contains(_state);
     }
 
     /* ------------------------------------------------------------ */
     public boolean isComplete()
     {
-        return isState(State.END)||isState(State.CLOSED);
+        return __completeStates.contains(_state);
     }
 
     /* ------------------------------------------------------------------------------- */
@@ -332,31 +350,55 @@
     }
 
     /* ------------------------------------------------------------------------------- */
-    @SuppressWarnings("serial")
-    private static class BadMessageException extends RuntimeException
+    enum CharState { ILLEGAL, CR, LF, LEGAL }
+    private final static CharState[] __charState;
+    static
     {
-        private final int _code;
-
-        private BadMessageException()
-        {
-            this(400,null);
-        }
+        // token          = 1*tchar
+        // tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
+        //                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
+        //                / DIGIT / ALPHA
+        //                ; any VCHAR, except delimiters
+        // quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE
+        // qdtext         = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text
+        // obs-text       = %x80-FF
+        // comment        = "(" *( ctext / quoted-pair / comment ) ")"
+        // ctext          = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
+        // quoted-pair    = "\" ( HTAB / SP / VCHAR / obs-text )
+   
+        __charState=new CharState[256];
+        Arrays.fill(__charState,CharState.ILLEGAL);
+        __charState[LINE_FEED]=CharState.LF;
+        __charState[CARRIAGE_RETURN]=CharState.CR;
+        __charState[TAB]=CharState.LEGAL;
+        __charState[SPACE]=CharState.LEGAL;
         
-        private BadMessageException(int code)
-        {
-            this(code,null);
-        }
+        __charState['!']=CharState.LEGAL;
+        __charState['#']=CharState.LEGAL;
+        __charState['$']=CharState.LEGAL;
+        __charState['%']=CharState.LEGAL;
+        __charState['&']=CharState.LEGAL;
+        __charState['\'']=CharState.LEGAL;
+        __charState['*']=CharState.LEGAL;
+        __charState['+']=CharState.LEGAL;
+        __charState['-']=CharState.LEGAL;
+        __charState['.']=CharState.LEGAL;
+        __charState['^']=CharState.LEGAL;
+        __charState['_']=CharState.LEGAL;
+        __charState['`']=CharState.LEGAL;
+        __charState['|']=CharState.LEGAL;
+        __charState['~']=CharState.LEGAL;
         
-        private BadMessageException(String message)
-        {
-            this(400,message);
-        }
+        __charState['"']=CharState.LEGAL;
         
-        private BadMessageException(int code,String message)
-        {
-            super(message);
-            _code=code;
-        }
+        __charState['\\']=CharState.LEGAL;
+        __charState['(']=CharState.LEGAL;
+        __charState[')']=CharState.LEGAL;
+        Arrays.fill(__charState,0x21,0x27+1,CharState.LEGAL);
+        Arrays.fill(__charState,0x2A,0x5B+1,CharState.LEGAL);
+        Arrays.fill(__charState,0x5D,0x7E+1,CharState.LEGAL);
+        Arrays.fill(__charState,0x80,0xFF+1,CharState.LEGAL);
+        
     }
     
     /* ------------------------------------------------------------------------------- */
@@ -364,37 +406,36 @@
     {
         byte ch = buffer.get();
         
-        if (_cr)
+        CharState s = __charState[0xff & ch];
+        switch(s)
         {
-            if (ch!=LINE_FEED)
-                throw new BadMessageException("Bad EOL");
-            _cr=false;
-            return ch;
-        }
+            case ILLEGAL:
+                throw new IllegalCharacterException(_state,ch,buffer);
+                
+            case LF:
+                _cr=false;
+                break;
+                
+            case CR:
+                if (_cr)
+                    throw new BadMessageException("Bad EOL");
 
-        if (ch>=0 && ch<SPACE)
-        {
-            if (ch==CARRIAGE_RETURN)
-            {
+                _cr=true;
                 if (buffer.hasRemaining())
                 {
                     if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
                         _headerBytes++;
-                    ch=buffer.get();
-                    if (ch!=LINE_FEED)
-                        throw new BadMessageException("Bad EOL");
+                    return next(buffer);
                 }
-                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==LINE_FEED || ch==TAB))
-                throw new IllegalCharacterException(_state,ch,buffer);
+                
+                // 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;
+                
+            case LEGAL:
+                if (_cr)
+                    throw new BadMessageException("Bad EOL");
+                
         }
         
         return ch;
@@ -555,7 +596,7 @@
                         }
                         else
                         {
-                            _uri.clear();
+                            _uri.reset();
                             setState(State.URI);
                             // quick scan for space or EoBuffer
                             if (buffer.hasArray())
@@ -575,18 +616,11 @@
                                     LOG.warn("URI is too large >"+_maxHeaderBytes);
                                     throw new BadMessageException(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);
+                                _uri.append(array,p-1,len+1);
                                 buffer.position(i-buffer.arrayOffset());
                             }
                             else
-                                _uri.put(ch);
+                                _uri.append(ch);
                         }
                     }
                     else if (ch < HttpTokens.SPACE)
@@ -623,24 +657,11 @@
                     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;
-                        return handle;
+                        throw new BadMessageException("HTTP/0.9 not supported");
                     }
                     else
                     {
-                        if (!_uri.hasRemaining())
-                        {
-                            ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
-                            _uri.flip();
-                            uri.put(_uri);
-                            _uri=uri;
-                        }
-                        _uri.put(ch);
+                        _uri.append(ch);
                     }
                     break;
 
@@ -664,29 +685,8 @@
                                 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 BadMessageException();
-                                    
-                                    _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
+                            
+                            if (version!=null)
                             {
                                 int pos = buffer.position()+version.asString().length()-1;
                                 if (pos<buffer.limit())
@@ -719,13 +719,7 @@
                         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;
-                            return handle;
+                            throw new BadMessageException("HTTP/0.9 not supported");
                         }
                     }
                     else if (ch<0)
@@ -744,15 +738,15 @@
                             throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
                         
                         // Should we try to cache header fields?
-                        if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
+                        if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0)
                         {
                             int header_cache = _handler.getHeaderCacheSize();
                             _connectionFields=new ArrayTernaryTrie<>(header_cache);                            
                         }
 
                         setState(State.HEADER);
-                        _uri.flip();
-                        handle=_requestHandler.startRequest(_method,_methodString,_uri, _version)||handle;
+                        
+                        handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle;
                         continue;
                     }
                     else if (ch>=HttpTokens.SPACE)
@@ -790,124 +784,94 @@
         return handle;
     }
 
-    private boolean handleKnownHeaders(ByteBuffer buffer)
+    private void parsedHeader()
     {
-        boolean add_to_connection_trie=false;
-        switch (_header)
+        // handler last header if any.  Delayed to here just in case there was a continuation line (above)
+        if (_headerString!=null || _valueString!=null)
         {
-            case CONTENT_LENGTH:
-                if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
+            // Handle known headers
+            if (_header!=null)
+            {
+                boolean add_to_connection_trie=false;
+                switch (_header)
                 {
-                    try
-                    {
-                        _contentLength=Long.parseLong(_valueString);
-                    }
-                    catch(NumberFormatException e)
-                    {
-                        LOG.ignore(e);
-                        throw new BadMessageException(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 BadMessageException(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 BadMessageException(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 ':':
+                    case CONTENT_LENGTH:
+                        if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
+                        {
                             try
                             {
-                                len=i;
-                                port = StringUtil.toInt(host.substring(i+1));
+                                _contentLength=Long.parseLong(_valueString);
                             }
-                            catch (NumberFormatException e)
+                            catch(NumberFormatException e)
                             {
-                                if (DEBUG)
-                                    LOG.debug(e);
-                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Host header");
+                                LOG.ignore(e);
+                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
                             }
-                            break loop;
-                    }
-                }
-                if (host.charAt(0)=='[')
-                {
-                    if (host.charAt(len-1)!=']') 
-                    {
-                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
-                    }
-                    host = host.substring(0,len);
-                }
-                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;
+                            if (_contentLength <= 0)
+                                _endOfContent=EndOfContent.NO_CONTENT;
+                            else
+                                _endOfContent=EndOfContent.CONTENT_LENGTH;
+                        }
+                        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);
+                    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 BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking");
+                            }
+                        }
+                        break;
+
+                    case HOST:
+                        _host=true;
+                        if (!(_field instanceof HostPortHttpField))
+                        {
+                            _field=new HostPortHttpField(_header,_strict?_headerString:_header.asString(),_valueString);
+                            add_to_connection_trie=_connectionFields!=null;
+                        }
+                      break;
+                      
+                    case CONNECTION:
+                        // Don't cache if not persistent
+                        if (_valueString!=null && _valueString.contains("close"))
+                            _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)
+                {
+                    if (_field==null)
+                        _field=new HttpField(_header,_strict?_headerString:_header.asString(),_valueString);
+                    _connectionFields.put(_field);
+                }
+            }
+            _handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString));
         }
         
-        return false;
+        _headerString=_valueString=null;
+        _header=null;
+        _value=null;
+        _field=null;
     }
     
     
@@ -941,194 +905,159 @@
                         case HttpTokens.COLON:
                         case HttpTokens.SPACE:
                         case HttpTokens.TAB:
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Continuation");
+
+                        case HttpTokens.LINE_FEED:
                         {
-                            // header value without name - continuation?
-                            if (_valueString==null)
+                            _contentPosition=0;
+
+                            // End of headers!
+
+                            // Was there a required host header?
+                            if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null)
                             {
-                                _string.setLength(0);
-                                _length=0;
+                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host");
                             }
-                            else
+
+                            // 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)
                             {
-                                setString(_valueString);
-                                _string.append(' ');
-                                _length++;
-                                _valueString=null;
+                                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;
                             }
-                            setState(State.HEADER_VALUE);
-                            break;
+
+                            // How is the message ended?
+                            switch (_endOfContent)
+                            {
+                                case EOF_CONTENT:
+                                    setState(State.EOF_CONTENT);
+                                    handle=_handler.headerComplete()||handle;
+                                    return handle;
+
+                                case CHUNKED_CONTENT:
+                                    setState(State.CHUNKED_CONTENT);
+                                    handle=_handler.headerComplete()||handle;
+                                    return handle;
+
+                                case NO_CONTENT:
+                                    handle=_handler.headerComplete()||handle;
+                                    setState(State.END);
+                                    handle=_handler.messageComplete()||handle;
+                                    return handle;
+
+                                default:
+                                    setState(State.CONTENT);
+                                    handle=_handler.headerComplete()||handle;
+                                    return handle;
+                            }
                         }
 
                         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_1 && _requestHandler!=null)
-                                {
-                                    throw new BadMessageException(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;
-                                        return handle;
-
-                                    case CHUNKED_CONTENT:
-                                        setState(State.CHUNKED_CONTENT);
-                                        handle=_handler.headerComplete()||handle;
-                                        return handle;
-
-                                    case NO_CONTENT:
-                                        handle=_handler.headerComplete()||handle;
-                                        setState(State.END);
-                                        handle=_handler.messageComplete()||handle;
-                                        return handle;
-
-                                    default:
-                                        setState(State.CONTENT);
-                                        handle=_handler.headerComplete()||handle;
-                                        return handle;
-                                }
-                            }
-                            else if (ch<=HttpTokens.SPACE)
+                            if (ch<=HttpTokens.SPACE)
                                 throw new BadMessageException();
-                            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);
-                                            }
-                                        }
+                            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
                                         {
-                                            n=field.getName();
-                                            v=field.getValue(); 
+                                            v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1);
+                                            field=new HttpField(field.getHeader(),n,v);
                                         }
-                                        
-                                        _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);
+                                    }
+                                    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
                                         {
-                                            // 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;
-                                            }
+                                            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;
                             }
+
+                            // 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 (ch==HttpTokens.COLON)
                     {
                         if (_headerString==null)
                         {
@@ -1137,11 +1066,11 @@
                         }
                         _length=-1;
 
-                        setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE);
+                        setState(State.HEADER_VALUE);
                         break;
                     }
                     
-                    if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB)
+                    if (ch>HttpTokens.SPACE)
                     {
                         if (_header!=null)
                         {
@@ -1169,18 +1098,18 @@
                     
                     if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
                         break;
-                    
+
                     if (ch==HttpTokens.LINE_FEED)
                     {
-                        if (_length > 0)
-                        {
-                            _value=null;
-                            _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString());
-                        }
+                        _value=null;
+                        _string.setLength(0);
+                        _valueString=null;
+                        _length=-1;
+                        
+                        parsedHeader();
                         setState(State.HEADER);
-                        break; 
+                        break;
                     }
-                    
                     throw new IllegalCharacterException(_state,ch,buffer);
 
                 case HEADER_IN_VALUE:
@@ -1206,6 +1135,7 @@
                             _valueString=takeString();
                             _length=-1;
                         }
+                        parsedHeader();
                         setState(State.HEADER);
                         break;
                     }
@@ -1224,6 +1154,7 @@
     /* ------------------------------------------------------------------------------- */
     /**
      * Parse until next Event.
+     * @param buffer the buffer to parse
      * @return True if an {@link RequestHandler} method was called and it returned true;
      */
     public boolean parseNext(ByteBuffer buffer)
@@ -1281,8 +1212,9 @@
                 while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE)
                     buffer.get();
             }
-            else if (_state==State.CLOSED)
+            else if (_state==State.CLOSE)
             {
+                // Seeking EOF
                 if (BufferUtil.hasContent(buffer))
                 {
                     // Just ignore data when closed
@@ -1291,10 +1223,14 @@
                     if (_maxHeaderBytes>0 && _headerBytes>_maxHeaderBytes)
                     {
                         // Don't want to waste time reading data of a closed request
-                        throw new IllegalStateException("too much data after closed");
+                        throw new IllegalStateException("too much data seeking EOF");
                     }
                 }
             }
+            else if (_state==State.CLOSED)
+            {
+                BufferUtil.clear(buffer);
+            }
             
             // Handle EOF
             if (_eof && !buffer.hasRemaining())
@@ -1310,6 +1246,7 @@
                         break;
                         
                     case END:
+                    case CLOSE:
                         setState(State.CLOSED);
                         break;
                         
@@ -1334,41 +1271,60 @@
                         break;
                 }
             }
-            
-            return false;
         }
         catch(BadMessageException e)
         {
             BufferUtil.clear(buffer);
 
-            LOG.warn("badMessage: "+e._code+(e.getMessage()!=null?" "+e.getMessage():"")+" for "+_handler);
-            if (DEBUG)
-                LOG.debug(e);
-            setState(State.CLOSED);
-            _handler.badMessage(e._code, e.getMessage());
-            return false;
+            Throwable cause = e.getCause();
+            boolean stack = LOG.isDebugEnabled() || 
+                    (!(cause instanceof NumberFormatException )  && (cause instanceof RuntimeException || cause instanceof Error));
+            
+            if (stack)
+                LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler,e);
+            else
+                LOG.warn("bad HTTP parsed: "+e._code+(e.getReason()!=null?" "+e.getReason():"")+" for "+_handler);
+            setState(State.CLOSE);
+            _handler.badMessage(e.getCode(), e.getReason());
         }
-        catch(Exception e)
+        catch(NumberFormatException|IllegalStateException e)
         {
             BufferUtil.clear(buffer);
-
-            LOG.warn("badMessage: "+e.toString()+" for "+_handler);
+            LOG.warn("parse exception: {} in {} for {}",e.toString(),_state,_handler);
             if (DEBUG)
                 LOG.debug(e);
             
-            if (_state.ordinal()<=State.END.ordinal())
+            switch(_state)
             {
-                setState(State.CLOSED);
-                _handler.badMessage(400,null);
+                case CLOSED:
+                    break;
+                case CLOSE:
+                    _handler.earlyEOF();
+                    break;
+                default:
+                    setState(State.CLOSE);
+                    _handler.badMessage(400,null);
             }
-            else
-            {
-                _handler.earlyEOF();
-                setState(State.CLOSED);
-            }
-
-            return false;
         }
+        catch(Exception|Error e)
+        {
+            BufferUtil.clear(buffer);
+
+            LOG.warn("parse exception: "+e.toString()+" for "+_handler,e);
+
+            switch(_state)
+            {
+                case CLOSED:
+                    break;
+                case CLOSE:
+                    _handler.earlyEOF();
+                    break;
+                default:
+                    setState(State.CLOSE);
+                    _handler.badMessage(400,null);
+            }
+        }
+        return false;
     }
 
     protected boolean parseContent(ByteBuffer buffer)
@@ -1540,8 +1496,9 @@
     }
     
     /* ------------------------------------------------------------------------------- */
+    /** Signal that the associated data source is at EOF
+     */
     public void atEOF()
-
     {        
         if (DEBUG)
             LOG.debug("atEOF {}", this);
@@ -1549,11 +1506,13 @@
     }
 
     /* ------------------------------------------------------------------------------- */
+    /** Request that the associated data source be closed
+     */
     public void close()
     {
         if (DEBUG)
             LOG.debug("close {}", this);
-        setState(State.CLOSED);
+        setState(State.CLOSE);
     }
     
     /* ------------------------------------------------------------------------------- */
@@ -1561,14 +1520,10 @@
     {
         if (DEBUG)
             LOG.debug("reset {}", this);
+
         // reset state
-        if (_state==State.CLOSED)
+        if (_state==State.CLOSE || _state==State.CLOSED)
             return;
-        if (_closed)
-        {
-            setState(State.CLOSED);
-            return;
-        }
         
         setState(State.START);
         _endOfContent=EndOfContent.UNKNOWN_CONTENT;
@@ -1632,9 +1587,9 @@
      * 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 interface HttpHandler
     {
-        public boolean content(T item);
+        public boolean content(ByteBuffer item);
 
         public boolean headerComplete();
 
@@ -1643,10 +1598,9 @@
         /**
          * 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);
-
+        public void parsedHeader(HttpField field);
+        
         /* ------------------------------------------------------------ */
         /** Called to signal that an EOF was received unexpectedly
          * during the parsing of a HTTP message
@@ -1669,43 +1623,32 @@
     /* ------------------------------------------------------------------------------- */
     /* ------------------------------------------------------------------------------- */
     /* ------------------------------------------------------------------------------- */
-    public interface ProxyHandler 
-    {
-        void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort);
-    }
-
-    /* ------------------------------------------------------------------------------- */
-    /* ------------------------------------------------------------------------------- */
-    /* ------------------------------------------------------------------------------- */
-    public interface RequestHandler<T> extends HttpHandler<T>
+    public interface RequestHandler extends HttpHandler
     {
         /**
          * 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 method The method 
          * @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
+         * @param version the http version in use
          * @return true if handling parsing should return.
          */
-        public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
+        public boolean startRequest(String method, String 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>
+    public interface ResponseHandler extends HttpHandler
     {
         /**
          * This is the method called by parser when the HTTP request line is parsed
+         * @param version the http version in use
+         * @param status the response status
+         * @param reason the response reason phrase
+         * @return true if handling parsing should return
          */
-        public abstract boolean startResponse(HttpVersion version, int status, String reason);
+        public boolean startResponse(HttpVersion version, int status, String reason);
     }
 
     /* ------------------------------------------------------------------------------- */
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
index f44bcdd..44ac0c6 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
@@ -61,7 +61,7 @@
     /* ------------------------------------------------------------ */
     public boolean is(String s)
     {
-        return _string.equalsIgnoreCase(s);
+        return s!=null && _string.equalsIgnoreCase(s);
     }
 
     public String asString()
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java
index 8762644..5682889 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpStatus.java
@@ -25,14 +25,17 @@
  * </p>
  *
  * <table border="1" cellpadding="5">
+ * <caption>HTTP Status Codes Table</caption>
  * <tr>
  * <th>Enum</th>
  * <th>Code</th>
  * <th>Message</th>
- * <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/rfc7231">RFC 7231 - HTTP/1.1 Semantics and Content</a></th>
  * <th>
- * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a></th>
+ * <a href="http://tools.ietf.org/html/rfc7238">RFC 7238 - HTTP/1.1 Permanent Redirect</a></th>
  * <th>
  * <a href="http://tools.ietf.org/html/rfc2518">RFC 2518 - WEBDAV</a></th>
  * </tr>
@@ -48,7 +51,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.2.1">Sec. 6.2.1</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -57,7 +60,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.2.2">Sec. 6.2.2</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -82,7 +85,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.1">Sec. 6.3.1</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -92,7 +95,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.2">Sec. 6.3.2</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -102,7 +105,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.3">Sec. 6.3.3</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -111,7 +114,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.4">Sec. 6.3.4</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -121,7 +124,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.5">Sec. 6.3.5</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -130,7 +133,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.6">Sec. 6.3.6</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -139,7 +142,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.3.7">Sec. 6.3.7</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -153,8 +156,8 @@
  * </tr>
  * <tr>
  * <td>&nbsp;</td>
- * <td><strike>207</strike></td>
- * <td><strike>Partial Update OK</strike></td>
+ * <td style="text-decoration: line-through;">207</td>
+ * <td style="text-decoration: line-through;">Partial Update OK</td>
  * <td>&nbsp;</td>
  * <td>
  * <a href=
@@ -175,7 +178,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.1">Sec. 6.4.1</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -185,7 +188,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.2">Sec. 6.4.2</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -203,7 +206,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3">Sec. 6.4.3</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -212,7 +215,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.4">Sec. 6.4.4</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -222,7 +225,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.5">Sec. 6.4.5</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -231,7 +234,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.6">Sec. 6.4.6</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -240,7 +243,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.7">Sec. 6.4.7</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -249,7 +252,17 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.4.8">Sec. 6.4.8</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #PERMANENT_REDIRECT_308}</td>
+ * <td>307</td>
+ * <td>Permanent Redirect</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc7238">RFC7238</a></td>
  * <td>&nbsp;</td>
  * </tr>
  *
@@ -265,7 +278,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.1">Sec. 6.5.1</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -275,7 +288,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.2">Sec. 6.5.2</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -285,7 +298,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.3">Sec. 6.5.3</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -295,7 +308,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.4">Sec. 6.5.4</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -305,7 +318,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.5">Sec. 6.5.5</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -314,7 +327,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.6">Sec. 6.5.6</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -323,7 +336,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.7">Sec. 6.5.7</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -332,7 +345,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.8">Sec. 6.5.8</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -341,7 +354,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.5.9">Sec. 6.5.9</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -350,7 +363,7 @@
  * <td>Conflict</td>
  * <td>&nbsp;</td>
  * <td>
- * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.10">Sec. 10.4.10</a>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.10">Sec. 10.4.10</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -360,7 +373,7 @@
  * <td>Gone</td>
  * <td>&nbsp;</td>
  * <td>
- * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.11">Sec. 10.4.11</a>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.11">Sec. 10.4.11</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -370,7 +383,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.12">Sec. 10.4.12</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -380,7 +393,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.13">Sec. 10.4.13</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -390,7 +403,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.14">Sec. 10.4.14</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -400,7 +413,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.15">Sec. 10.4.15</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -410,7 +423,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.16">Sec. 10.4.16</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -420,7 +433,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-10.4.17">Sec. 10.4.17</a>
  * </td>
  * <td>&nbsp;</td>
  * </tr>
@@ -430,14 +443,14 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#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 style="text-decoration: line-through;">418</td>
+ * <td style="text-decoration: line-through;">Reauthentication Required</td>
  * <td>&nbsp;</td>
  * <td>
  * <a href=
@@ -447,8 +460,8 @@
  * </tr>
  * <tr>
  * <td>&nbsp;</td>
- * <td><strike>418</strike></td>
- * <td><strike>Unprocessable Entity</strike></td>
+ * <td style="text-decoration: line-through;">418</td>
+ * <td style="text-decoration: line-through;">Unprocessable Entity</td>
  * <td>&nbsp;</td>
  * <td>&nbsp;</td>
  * <td>
@@ -458,8 +471,8 @@
  * </tr>
  * <tr>
  * <td>&nbsp;</td>
- * <td><strike>419</strike></td>
- * <td><strike>Proxy Reauthentication Required</stike></td>
+ * <td style="text-decoration: line-through;">419</td>
+ * <td style="text-decoration: line-through;">Proxy Reauthentication Required</td>
  * <td>&nbsp;</td>
  * <td>
  * <a href=
@@ -469,8 +482,8 @@
  * </tr>
  * <tr>
  * <td>&nbsp;</td>
- * <td><strike>419</strike></td>
- * <td><strike>Insufficient Space on Resource</stike></td>
+ * <td style="text-decoration: line-through;">419</td>
+ * <td style="text-decoration: line-through;">Insufficient Space on Resource</td>
  * <td>&nbsp;</td>
  * <td>&nbsp;</td>
  * <td>
@@ -480,8 +493,8 @@
  * </tr>
  * <tr>
  * <td>&nbsp;</td>
- * <td><strike>420</strike></td>
- * <td><strike>Method Failure</strike></td>
+ * <td style="text-decoration: line-through;">420</td>
+ * <td style="text-decoration: line-through;">Method Failure</td>
  * <td>&nbsp;</td>
  * <td>&nbsp;</td>
  * <td>
@@ -537,7 +550,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.1">Sec. 6.6.1</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -547,7 +560,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.2">Sec. 6.6.2</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -557,7 +570,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.3">Sec. 6.6.3</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -567,7 +580,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.4">Sec. 6.6.4</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -576,7 +589,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.5">Sec. 6.6.5</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -585,7 +598,7 @@
  * <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>
+ * <a href="http://tools.ietf.org/html/rfc7231#section-6.6.6">Sec. 6.6.6</a></td>
  * <td>&nbsp;</td>
  * </tr>
  * <tr>
@@ -633,6 +646,7 @@
     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 PERMANENT_REDIRECT_308 = 308;
 
     public final static int BAD_REQUEST_400 = 400;
     public final static int UNAUTHORIZED_401 = 401;
@@ -652,9 +666,11 @@
     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 MISDIRECTED_REQUEST_421 = 421;
     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 UPGRADE_REQUIRED_426 = 426;
 
     public final static int INTERNAL_SERVER_ERROR_500 = 500;
     public final static int NOT_IMPLEMENTED_501 = 501;
@@ -664,8 +680,13 @@
     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;
-
+    // RFC 6585
+    public final static int PRECONDITION_REQUIRED_428 = 428;
+    public final static int TOO_MANY_REQUESTS_429 = 429;
+    public final static int REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431;
+    public final static int NETWORK_AUTHENTICATION_REQUIRED_511 = 511;
+    
+    public static final int MAX_CODE = 511;
 
     private static final Code[] codeMap = new Code[MAX_CODE+1];
 
@@ -683,7 +704,7 @@
         /*
          * --------------------------------------------------------------------
          * Informational messages in 1xx series. As defined by ... RFC 1945 -
-         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV
          */
 
         /** <code>100 Continue</code> */
@@ -696,7 +717,7 @@
         /*
          * --------------------------------------------------------------------
          * Success messages in 2xx series. As defined by ... RFC 1945 - HTTP/1.0
-         * RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         * RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV
          */
 
         /** <code>200 OK</code> */
@@ -719,7 +740,7 @@
         /*
          * --------------------------------------------------------------------
          * Redirection messages in 3xx series. As defined by ... RFC 1945 -
-         * HTTP/1.0 RFC 2616 - HTTP/1.1
+         * HTTP/1.0 RFC 7231 - HTTP/1.1
          */
 
         /** <code>300 Mutliple Choices</code> */
@@ -738,11 +759,13 @@
         USE_PROXY(USE_PROXY_305, "Use Proxy"),
         /** <code>307 Temporary Redirect</code> */
         TEMPORARY_REDIRECT(TEMPORARY_REDIRECT_307, "Temporary Redirect"),
+        /** <code>308 Permanent Redirect</code> */
+        PERMANET_REDIRECT(PERMANENT_REDIRECT_308, "Permanent Redirect"),
 
         /*
          * --------------------------------------------------------------------
          * Client Error messages in 4xx series. As defined by ... RFC 1945 -
-         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV
          */
 
         /** <code>400 Bad Request</code> */
@@ -781,17 +804,29 @@
         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>421 Misdirected Request(RFC7234)y</code> */
+        MISDIRECTED_REQUEST(MISDIRECTED_REQUEST_421, "Misdirected Request"),
         /** <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"),
-
+        
+        /** <code>426 Upgrade Required (RFC7231)</code> */
+        UPGRADE_REQUIRED(UPGRADE_REQUIRED_426, "Upgrade Required"),
+        
+        /** <code>428 Precondition Required (RFC6585)</code> */
+        PRECONDITION_REQUIRED(PRECONDITION_REQUIRED_428, "Precondition Required"),
+        /** <code>429 Too Many Requests (RFC6585)</code> */
+        TOO_MANY_REQUESTS(TOO_MANY_REQUESTS_429, "Too Many Requests"),
+        /** <code>431 Request Header Fields Too Large (RFC6585)</code> */
+        REQUEST_HEADER_FIELDS_TOO_LARGE(REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Request Header Fields Too Large"),
+      
         /*
          * --------------------------------------------------------------------
          * Server Error messages in 5xx series. As defined by ... RFC 1945 -
-         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         * HTTP/1.0 RFC 7231 - HTTP/1.1 RFC 2518 - WebDAV
          */
 
         /** <code>500 Server Error</code> */
@@ -807,8 +842,13 @@
         /** <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");
+        INSUFFICIENT_STORAGE(INSUFFICIENT_STORAGE_507, "Insufficient Storage"),
 
+        /** <code>511 Network Authentication Required (RFC6585)</code> */
+        NETWORK_AUTHENTICATION_REQUIRED(NETWORK_AUTHENTICATION_REQUIRED_511, "Network Authentication Required"),
+        
+        ;
+        
         private final int _code;
         private final String _message;
 
@@ -844,7 +884,7 @@
          * 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 -
+         * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
          * HTTP/1.1</a>.
          *
          * @return true if within range of codes that belongs to
@@ -859,7 +899,7 @@
          * 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 -
+         * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
          * HTTP/1.1</a>.
          *
          * @return true if within range of codes that belongs to
@@ -874,7 +914,7 @@
          * 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 -
+         * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
          * HTTP/1.1</a>.
          *
          * @return true if within range of codes that belongs to
@@ -889,7 +929,7 @@
          * 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 -
+         * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
          * HTTP/1.1</a>.
          *
          * @return true if within range of codes that belongs to
@@ -904,7 +944,7 @@
          * 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 -
+         * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
          * HTTP/1.1</a>.
          *
          * @return true if within range of codes that belongs to
@@ -958,7 +998,7 @@
      * 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>.
+     * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
      *
      * @param code
      *            the code to test.
@@ -974,7 +1014,7 @@
      * 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>.
+     * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
      *
      * @param code
      *            the code to test.
@@ -990,7 +1030,7 @@
      * 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>.
+     * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
      *
      * @param code
      *            the code to test.
@@ -1006,7 +1046,7 @@
      * 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>.
+     * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
      *
      * @param code
      *            the code to test.
@@ -1022,7 +1062,7 @@
      * 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>.
+     * href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
      *
      * @param code
      *            the code to test.
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
deleted file mode 100644
index 0283f9e..0000000
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTester.java
+++ /dev/null
@@ -1,367 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.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/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
index 067a21e..66aabda 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
@@ -32,7 +32,7 @@
     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 }
+    public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT }
 
 }
 
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
index 46a8a5b..3062145 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
@@ -20,15 +20,14 @@
 
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URISyntaxException;
 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;
 
 
 /* ------------------------------------------------------------ */
@@ -45,359 +44,302 @@
  * <li>{@link #getQuery()} - query</li>
  * <li>{@link #getFragment()} - fragment</li>
  * </ul>
- *
+ * 
+ * <p>Any parameters will be returned from {@link #getPath()}, but are excluded from the
+ * return value of {@link #getDecodedPath()}.   If there are multiple parameters, the 
+ * {@link #getParam()} method returns only the last one.
  */
 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;
+    private enum State {
+    START,
+    HOST_OR_PATH,
+    SCHEME_OR_PATH,
+    HOST,
+    IPV6,
+    PORT,
+    PATH,
+    PARAM,
+    QUERY,
+    FRAGMENT,
+    ASTERISK};
 
-    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;
-    }
+    private String _scheme;
+    private String _user;
+    private String _host;
+    private int _port;
+    private String _path;
+    private String _param;
+    private String _query;
+    private String _fragment;
+    
+    String _uri;
+    String _decodedPath;
 
     /* ------------------------------------------------------------ */
     /**
-     * @param parsePartialAuth If True, parse auth without prior scheme, else treat all URIs starting with / as paths
+     * Construct a normalized URI.
+     * Port is not set if it is the default port.
+     * @param scheme the URI scheme
+     * @param host the URI hose
+     * @param port the URI port
+     * @param path the URI path
+     * @param param the URI param
+     * @param query the URI query
+     * @param fragment the URI fragment
+     * @return the normalized URI
      */
-    public HttpURI(boolean parsePartialAuth)
+    public static HttpURI createHttpURI(String scheme, String host, int port, String path, String param, String query, String fragment)
     {
-        _partial=parsePartialAuth;
-        _charset = URIUtil.__CHARSET;
+        if (port==80 && HttpScheme.HTTP.is(scheme))
+            port=0;
+        if (port==443 && HttpScheme.HTTPS.is(scheme))
+            port=0;
+        return new HttpURI(scheme,host,port,path,param,query,fragment);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public HttpURI()
+    {
     }
 
-    public HttpURI(String raw)
+    /* ------------------------------------------------------------ */
+    public HttpURI(String scheme, String host, int port, String path, String param, String query, String fragment)
     {
-        _rawString=raw;
-        byte[] b = raw.getBytes(StandardCharsets.UTF_8);
-        parse(b,0,b.length);
-        _charset = URIUtil.__CHARSET;
+        _scheme = scheme;
+        _host = host;
+        _port = port;
+        _path = path;
+        _param = param;
+        _query = query;
+        _fragment = fragment;
     }
 
-    public HttpURI(byte[] raw,int offset, int length)
+    /* ------------------------------------------------------------ */
+    public HttpURI(HttpURI uri)
     {
-        parse2(raw,offset,length);
-        _charset = URIUtil.__CHARSET;
+        this(uri._scheme,uri._host,uri._port,uri._path,uri._param,uri._query,uri._fragment);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public HttpURI(String uri)
+    {
+        _port=-1;
+        parse(State.START,uri,0,uri.length());
     }
 
+    /* ------------------------------------------------------------ */
     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)
+        _uri=null;
+        
+        _scheme=uri.getScheme();
+        _host=uri.getHost();
+        if (_host==null && uri.getRawSchemeSpecificPart().startsWith("//"))
+            _host="";
+        _port=uri.getPort();
+        _user = uri.getUserInfo();
+        _path=uri.getRawPath();
+        
+        _decodedPath = uri.getPath();
+        if (_decodedPath != null)
         {
-            char c=(char)(0xff&_raw[i]);
-            int s=i++;
+            int p = _decodedPath.lastIndexOf(';');
+            if (p >= 0)
+                _param = _decodedPath.substring(p + 1);
+        }
+        _query=uri.getRawQuery();
+        _fragment=uri.getFragment();
+        
+        _decodedPath=null;
+    }
+
+    /* ------------------------------------------------------------ */
+    public HttpURI(String scheme, String host, int port, String pathQuery)
+    {
+        _uri=null;
+        
+        _scheme=scheme;
+        _host=host;
+        _port=port;
+
+        parse(State.PATH,pathQuery,0,pathQuery.length());
+        
+    }
+
+    /* ------------------------------------------------------------ */
+    public void parse(String uri)
+    {
+        clear();
+        _uri=uri;
+        parse(State.START,uri,0,uri.length());
+    }
+
+    /* ------------------------------------------------------------ */
+    public void parseConnect(String uri)
+    {
+        clear();
+        _uri=uri;
+        _path=uri;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void parse(String uri, int offset, int length)
+    {
+        clear();
+        int end=offset+length;
+        _uri=uri.substring(offset,end);
+        parse(State.START,uri,offset,end);
+    }
+
+    /* ------------------------------------------------------------ */
+    private void parse(State state, final String uri, final int offset, final int end)
+    {
+        boolean encoded=false;
+        int mark=offset;
+        int path_mark=0;
+        
+        for (int i=offset; i<end; i++)
+        {
+            char c=uri.charAt(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;
+                            mark = i;
+                            state = State.HOST_OR_PATH;
                             break;
                         case ';':
-                            _param=s;
-                            state=PARAM;
+                            mark=i+1;
+                            state=State.PARAM;
                             break;
                         case '?':
-                            _param=s;
-                            _query=s;
-                            state=QUERY;
+                            // assume empty path (if seen at start)
+                            _path = "";
+                            mark=i+1;
+                            state=State.QUERY;
                             break;
                         case '#':
-                            _param=s;
-                            _query=s;
-                            _fragment=s;
+                            mark=i+1;
+                            state=State.FRAGMENT;
                             break;
                         case '*':
-                            _path=s;
-                            state=ASTERISK;
+                            _path="*";
+                            state=State.ASTERISK;
                             break;
 
                         default:
-                            state=SCHEME_OR_PATH;
+                            mark=i;
+                            if (_scheme==null)
+                                state=State.SCHEME_OR_PATH;
+                            else
+                            {
+                                path_mark=i;
+                                state=State.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;
-                            }
+                            // must have been a scheme
+                            _scheme=uri.substring(mark,i);
+                            // Start again with scheme set
+                            state=State.START;
                             break;
-                        }
 
                         case '/':
-                        {
-                            state = PATH;
+                            // must have been in a path and still are
+                            state=State.PATH;
                             break;
-                        }
 
                         case ';':
-                        {
-                            _param = s;
-                            state = PARAM;
+                            // must have been in a path 
+                            mark=i+1;
+                            state=State.PARAM;
                             break;
-                        }
 
                         case '?':
-                        {
-                            _param = s;
-                            _query = s;
-                            state = QUERY;
+                            // must have been in a path 
+                            _path=uri.substring(mark,i);
+                            mark=i+1;
+                            state=State.QUERY;
                             break;
-                        }
 
-                        case '#':
-                        {
-                            _param = s;
-                            _query = s;
-                            _fragment = s;
+                        case '%':
+                            // must have be in an encoded path 
+                            encoded=true;
+                            state=State.PATH;
                             break;
-                        }
+                        
+                        case '#':
+                            // must have been in a path 
+                            _path=uri.substring(mark,i);
+                            state=State.FRAGMENT;
+                            break;
+                    }
+                    continue;
+                }
+                
+                case HOST_OR_PATH:
+                {
+                    switch(c)
+                    {
+                        case '/':
+                            _host="";
+                            mark=i+1;
+                            state=State.HOST;
+                            break;
+                            
+                        case '@':
+                        case ';':
+                        case '?':
+                        case '#':
+                            // was a path, look again
+                            i--;
+                            path_mark=mark;
+                            state=State.PATH;
+                            break;
+                        default:
+                            // it is a path
+                            path_mark=mark;
+                            state=State.PATH;
                     }
                     continue;
                 }
 
-                case AUTH:
+                case HOST:
                 {
                     switch (c)
                     {
-
                         case '/':
-                        {
-                            m = s;
-                            _path = m;
-                            _port = _path;
-                            state = PATH;
+                            _host = uri.substring(mark,i);
+                            path_mark=mark=i;
+                            state=State.PATH;
                             break;
-                        }
-                        case '@':
-                        {
-                            _host = i;
-                            break;
-                        }
                         case ':':
-                        {
-                            _port = s;
-                            state = PORT;
+                            if (i > mark)
+                                _host=uri.substring(mark,i);
+                            mark=i+1;
+                            state=State.PORT;
                             break;
-                        }
+                        case '@':
+                            _user=uri.substring(mark,i);
+                            mark=i+1;
+                            break;
+                            
                         case '[':
-                        {
-                            state = IPV6;
+                            state=State.IPV6;
                             break;
-                        }
                     }
                     continue;
                 }
@@ -407,14 +349,21 @@
                     switch (c)
                     {
                         case '/':
-                        {
-                            throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset));
-                        }
+                            throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri);
                         case ']':
-                        {
-                            state = AUTH;
+                            c = uri.charAt(++i);
+                            _host=uri.substring(mark,i);
+                            if (c == ':')
+                            {
+                                mark=i+1;
+                                state=State.PORT;
+                            }
+                            else
+                            {
+                                path_mark=mark=i;
+                                state=State.PATH;
+                            }
                             break;
-                        }
                     }
 
                     continue;
@@ -424,11 +373,9 @@
                 {
                     if (c=='/')
                     {
-                        m=s;
-                        _path=m;
-                        if (_port<=_authority)
-                            _port=_path;
-                        state=PATH;
+                        _port=TypeUtil.parseInt(uri,mark,i-mark,10);
+                        path_mark=mark=i;
+                        state=State.PATH;
                     }
                     continue;
                 }
@@ -438,29 +385,22 @@
                     switch (c)
                     {
                         case ';':
-                        {
-                            _param = s;
-                            state = PARAM;
+                            mark=i+1;
+                            state=State.PARAM;
                             break;
-                        }
                         case '?':
-                        {
-                            _param = s;
-                            _query = s;
-                            state = QUERY;
+                            _path=uri.substring(path_mark,i);
+                            mark=i+1;
+                            state=State.QUERY;
                             break;
-                        }
                         case '#':
-                        {
-                            _param = s;
-                            _query = s;
-                            _fragment = s;
-                            break state;
-                        }
+                            _path=uri.substring(path_mark,i);
+                            mark=i+1;
+                            state=State.FRAGMENT;
+                            break;
                         case '%':
-                        {
-                            _encoded=true;
-                        }
+                            encoded=true;
+                            break;
                     }
                     continue;
                 }
@@ -470,17 +410,26 @@
                     switch (c)
                     {
                         case '?':
-                        {
-                            _query = s;
-                            state = QUERY;
+                            _path=uri.substring(path_mark,i);
+                            _param=uri.substring(mark,i);
+                            mark=i+1;
+                            state=State.QUERY;
                             break;
-                        }
                         case '#':
-                        {
-                            _query = s;
-                            _fragment = s;
-                            break state;
-                        }
+                            _path=uri.substring(path_mark,i);
+                            _param=uri.substring(mark,i);
+                            mark=i+1;
+                            state=State.FRAGMENT;
+                            break;
+                        case '/':
+                            encoded=true;
+                            // ignore internal params
+                            state=State.PATH;
+                            break;
+                        case ';':
+                            // multiple parameters
+                            mark=i+1;
+                            break;
                     }
                     continue;
                 }
@@ -489,8 +438,9 @@
                 {
                     if (c=='#')
                     {
-                        _fragment=s;
-                        break state;
+                        _query=uri.substring(mark,i);
+                        mark=i+1;
+                        state=State.FRAGMENT;
                     }
                     continue;
                 }
@@ -499,284 +449,301 @@
                 {
                     throw new IllegalArgumentException("only '*'");
                 }
+                
+                case FRAGMENT:
+                {
+                    _fragment=uri.substring(mark,end);
+                    i=end;
+                }
             }
         }
 
-        if (_port<_path)
-            _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10);
+        
+        switch(state)
+        {
+            case START:
+                break;
+            case SCHEME_OR_PATH:
+                _path=uri.substring(mark,end);
+                break;
+
+            case HOST_OR_PATH:
+                _path=uri.substring(mark,end);
+                break;
+                
+            case HOST:
+                if(end>mark)
+                    _host=uri.substring(mark,end);
+                break;
+                
+            case IPV6:
+                throw new IllegalArgumentException("No closing ']' for ipv6 in " + uri);
+
+            case PORT:
+                _port=TypeUtil.parseInt(uri,mark,end-mark,10);
+                break;
+                
+            case ASTERISK:
+                break;
+                
+            case FRAGMENT:
+                _fragment=uri.substring(mark,end);
+                break;
+                
+            case PARAM:
+                _path=uri.substring(path_mark,end);
+                _param=uri.substring(mark,end);
+                break;
+                
+            case PATH:
+                _path=uri.substring(path_mark,end);
+                break;
+                
+            case QUERY:
+                _query=uri.substring(mark,end);
+                break;
+        }
+        
+        if (!encoded)
+        {
+            if (_param==null)
+                _decodedPath=_path;
+            else
+                _decodedPath=_path.substring(0,_path.length()-_param.length()-1);
+        }
     }
 
+    /* ------------------------------------------------------------ */
     public String getScheme()
     {
-        if (_scheme==_authority)
-            return null;
-        int l=_authority-_scheme;
-        if (l==5 &&
-                _raw[_scheme]=='h' &&
-                _raw[_scheme+1]=='t' &&
-                _raw[_scheme+2]=='t' &&
-                _raw[_scheme+3]=='p' )
-            return HttpScheme.HTTP.asString();
-        if (l==6 &&
-                _raw[_scheme]=='h' &&
-                _raw[_scheme+1]=='t' &&
-                _raw[_scheme+2]=='t' &&
-                _raw[_scheme+3]=='p' &&
-                _raw[_scheme+4]=='s' )
-            return HttpScheme.HTTPS.asString();
-
-        return new String(_raw,_scheme,_authority-_scheme-1,_charset);
+        return _scheme;
     }
 
-    public String getAuthority()
-    {
-        if (_authority==_path)
-            return null;
-        return new String(_raw,_authority,_path-_authority,_charset);
-    }
-
+    /* ------------------------------------------------------------ */
     public String getHost()
     {
-        if (_host==_port)
+        // Return null for empty host to retain compatibility with java.net.URI
+        if (_host!=null && _host.length()==0)
             return null;
-        return new String(_raw,_host,_port-_host,_charset);
+        return _host;
     }
 
+    /* ------------------------------------------------------------ */
     public int getPort()
     {
-        return _portValue;
+        return _port;
     }
 
+    /* ------------------------------------------------------------ */
+    /**
+     * The parsed Path.
+     * 
+     * @return the path as parsed on valid URI.  null for invalid URI.
+     */
     public String getPath()
     {
-        if (_path==_param)
-            return null;
-        return new String(_raw,_path,_param-_path,_charset);
+        return _path;
     }
 
+    /* ------------------------------------------------------------ */
     public String getDecodedPath()
     {
-        if (_path==_param)
-            return null;
-
-        Utf8StringBuilder utf8b=null;
-
-        for (int i=_path;i<_param;i++)
-        {
-            byte b = _raw[i];
-
-            if (b=='%')
-            {
-                if (utf8b==null)
-                {
-                    utf8b=new Utf8StringBuilder();
-                    utf8b.append(_raw,_path,i-_path);
-                }
-                
-                if ((i+2)>=_param)
-                    throw new IllegalArgumentException("Bad % encoding: "+this);
-                if (_raw[i+1]=='u')
-                {
-                    if ((i+5)>=_param)
-                        throw new IllegalArgumentException("Bad %u encoding: "+this);
-                    try
-                    {
-                        String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16)));
-                        utf8b.getStringBuilder().append(unicode);
-                        i+=5;
-                    }
-                    catch(Exception e)
-                    {
-                        throw new RuntimeException(e);
-                    }
-                }
-                else
-                {
-                    b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
-                    utf8b.append(b);
-                    i+=2;
-                }
-                continue;
-            }
-            else if (utf8b!=null)
-            {
-                utf8b.append(b);
-            }
-        }
-
-        if (utf8b==null)
-            return StringUtil.toUTF8String(_raw, _path, _param-_path);
-        return utf8b.toString();
+        if (_decodedPath==null && _path!=null)
+            _decodedPath=URIUtil.decodePath(_path);
+        return _decodedPath;
     }
 
-    public String getDecodedPath(String encoding)
-    {
-        return getDecodedPath(Charset.forName(encoding));
-    }
-
-    public String getDecodedPath(Charset encoding)
-    {
-        if (_path==_param)
-            return null;
-
-        int length = _param-_path;
-        byte[] bytes=null;
-        int n=0;
-
-        for (int i=_path;i<_param;i++)
-        {
-            byte b = _raw[i];
-
-            if (b=='%')
-            {
-                if (bytes==null)
-                {
-                    bytes=new byte[length];
-                    System.arraycopy(_raw,_path,bytes,0,n);
-                }
-                
-                if ((i+2)>=_param)
-                    throw new IllegalArgumentException("Bad % encoding: "+this);
-                if (_raw[i+1]=='u')
-                {
-                    if ((i+5)>=_param)
-                        throw new IllegalArgumentException("Bad %u encoding: "+this);
-
-                    try
-                    {
-                        String unicode = new String(Character.toChars(TypeUtil.parseInt(_raw,i+2,4,16)));
-                        byte[] encoded = unicode.getBytes(encoding);
-                        System.arraycopy(encoded,0,bytes,n,encoded.length);
-                        n+=encoded.length;
-                        i+=5;
-                    }
-                    catch(Exception e)
-                    {
-                        throw new RuntimeException(e);
-                    }
-                }
-                else
-                {
-                    b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
-                    bytes[n++]=b;
-                    i+=2;
-                }
-                continue;
-            }
-            else if (bytes==null)
-            {
-                n++;
-                continue;
-            }
-
-            bytes[n++]=b;
-        }
-
-
-        if (bytes==null)
-            return new String(_raw,_path,_param-_path,encoding);
-
-        return new String(bytes,0,n,encoding);
-    }
-
-    public String getPathAndParam()
-    {
-        if (_path==_query)
-            return null;
-        return new String(_raw,_path,_query-_path,_charset);
-    }
-
-    public String getCompletePath()
-    {
-        if (_path==_end)
-            return null;
-        return new String(_raw,_path,_end-_path,_charset);
-    }
-
+    /* ------------------------------------------------------------ */
     public String getParam()
     {
-        if (_param==_query)
-            return null;
-        return new String(_raw,_param+1,_query-_param-1,_charset);
+        return _param;
     }
 
+    /* ------------------------------------------------------------ */
     public String getQuery()
     {
-        if (_query==_fragment)
-            return null;
-        return new String(_raw,_query+1,_fragment-_query-1,_charset);
+        return _query;
     }
 
-    public String getQuery(String encoding)
-    {
-        if (_query==_fragment)
-            return null;
-        return StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding);
-    }
-
+    /* ------------------------------------------------------------ */
     public boolean hasQuery()
     {
-        return (_fragment>_query);
+        return _query!=null && _query.length()>0;
     }
 
+    /* ------------------------------------------------------------ */
     public String getFragment()
     {
-        if (_fragment==_end)
-            return null;
-        return new String(_raw,_fragment+1,_end-_fragment-1,_charset);
+        return _fragment;
     }
 
+    /* ------------------------------------------------------------ */
     public void decodeQueryTo(MultiMap<String> parameters)
     {
         if (_query==_fragment)
             return;
-        if (_charset.equals(StandardCharsets.UTF_8))
-            UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
-        else
-            UrlEncoded.decodeTo(new String(_raw,_query+1,_fragment-_query-1,_charset),parameters,_charset,-1);
+        UrlEncoded.decodeUtf8To(_query,parameters);
     }
 
+    /* ------------------------------------------------------------ */
     public void decodeQueryTo(MultiMap<String> parameters, String encoding) throws UnsupportedEncodingException
     {
-        if (_query==_fragment)
-            return;
-
-        if (encoding==null || StringUtil.isUTF8(encoding))
-            UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
-        else
-            UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1);
+        decodeQueryTo(parameters,Charset.forName(encoding));
     }
 
+    /* ------------------------------------------------------------ */
     public void decodeQueryTo(MultiMap<String> parameters, Charset encoding) throws UnsupportedEncodingException
     {
         if (_query==_fragment)
             return;
 
         if (encoding==null || StandardCharsets.UTF_8.equals(encoding))
-            UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
+            UrlEncoded.decodeUtf8To(_query,parameters);
         else
-            UrlEncoded.decodeTo(new String(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding,-1);
+            UrlEncoded.decodeTo(_query,parameters,encoding);
     }
 
+    /* ------------------------------------------------------------ */
     public void clear()
     {
-        _scheme=_authority=_host=_port=_path=_param=_query=_fragment=_end=0;
-        _raw=__empty;
-        _rawString="";
-        _encoded=false;
+        _uri=null;
+
+        _scheme=null;
+        _host=null;
+        _port=-1;
+        _path=null;
+        _param=null;
+        _query=null;
+        _fragment=null;
+
+        _decodedPath=null;
     }
 
+    /* ------------------------------------------------------------ */
+    public boolean isAbsolute()
+    {
+        return _scheme!=null && _scheme.length()>0;
+    }
+    
+    /* ------------------------------------------------------------ */
     @Override
     public String toString()
     {
-        if (_rawString==null)
-            _rawString=new String(_raw,_scheme,_end-_scheme,_charset);
-        return _rawString;
+        if (_uri==null)
+        {
+            StringBuilder out = new StringBuilder();
+            
+            if (_scheme!=null)
+                out.append(_scheme).append(':');
+            
+            if (_host != null)
+            {
+                out.append("//");
+                if (_user != null)
+                    out.append(_user).append('@');
+                out.append(_host);
+            }
+            
+            if (_port>0)
+                out.append(':').append(_port);
+            
+            if (_path!=null)
+                out.append(_path);
+            
+            if (_query!=null)
+                out.append('?').append(_query);
+            
+            if (_fragment!=null)
+                out.append('#').append(_fragment);
+            
+            if (out.length()>0)
+                _uri=out.toString();
+            else
+                _uri="";
+        }
+        return _uri;
     }
 
-    public void writeTo(Utf8StringBuilder buf)
+    /* ------------------------------------------------------------ */
+    public boolean equals(Object o)
     {
-        buf.append(_raw,_scheme,_end-_scheme);
+        if (o==this)
+            return true;
+        if (!(o instanceof HttpURI))
+            return false;
+        return toString().equals(o.toString());
     }
 
+    /* ------------------------------------------------------------ */
+    public void setScheme(String scheme)
+    {
+        _scheme=scheme;
+        _uri=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param host the host
+     * @param port the port
+     */
+    public void setAuthority(String host, int port)
+    {
+        _host=host;
+        _port=port;
+        _uri=null;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param path the path
+     */
+    public void setPath(String path)
+    {
+        _uri=null;
+        _path=path;
+        _decodedPath=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setPathQuery(String path)
+    {
+        _uri=null;
+        _path=null;
+        _decodedPath=null;
+        _param=null;
+        _fragment=null;
+        if (path!=null)
+            parse(State.PATH,path,0,path.length());
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void setQuery(String query)
+    {
+        _query=query;
+        _uri=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public URI toURI() throws URISyntaxException
+    {
+        return new URI(_scheme,null,_host,_port,_path,_query==null?null:UrlEncoded.decodeString(_query),_fragment);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String getPathQuery()
+    {
+        if (_query==null)
+            return _path;
+        return _path+"?"+_query;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String getAuthority()
+    {
+        if (_port>0)
+            return _host+":"+_port;
+        return _host;
+    }
+
+
 }
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java
new file mode 100644
index 0000000..725870d
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java
@@ -0,0 +1,298 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.Collections;
+import java.util.Iterator;
+
+public class MetaData implements Iterable<HttpField>
+{
+    private HttpVersion _httpVersion;
+    private HttpFields _fields;
+    private long _contentLength;
+
+    public MetaData(HttpVersion version, HttpFields fields)
+    {
+        this(version, fields, Long.MIN_VALUE);
+    }
+
+    public MetaData(HttpVersion version, HttpFields fields, long contentLength)
+    {
+        _httpVersion = version;
+        _fields = fields;
+        _contentLength = contentLength;
+    }
+
+    protected void recycle()
+    {
+        _httpVersion = null;
+        if (_fields != null)
+            _fields.clear();
+        _contentLength = Long.MIN_VALUE;
+    }
+
+    public boolean isRequest()
+    {
+        return false;
+    }
+
+    public boolean isResponse()
+    {
+        return false;
+    }
+
+    /**
+     * @return the HTTP version of this MetaData object
+     */
+    public HttpVersion getVersion()
+    {
+        return _httpVersion;
+    }
+
+    /**
+     * @param httpVersion the HTTP version to set
+     */
+    public void setHttpVersion(HttpVersion httpVersion)
+    {
+        _httpVersion = httpVersion;
+    }
+
+    /**
+     * @return the HTTP fields of this MetaData object
+     */
+    public HttpFields getFields()
+    {
+        return _fields;
+    }
+
+    /**
+     * @return the content length if available, otherwise {@link Long#MIN_VALUE}
+     */
+    public long getContentLength()
+    {
+        if (_contentLength == Long.MIN_VALUE)
+        {
+            if (_fields != null)
+            {
+                HttpField field = _fields.getField(HttpHeader.CONTENT_LENGTH);
+                _contentLength = field == null ? -1 : field.getLongValue();
+            }
+        }
+        return _contentLength;
+    }
+
+    /**
+     * @return an iterator over the HTTP fields
+     * @see #getFields()
+     */
+    public Iterator<HttpField> iterator()
+    {
+        HttpFields fields = getFields();
+        return fields == null ? Collections.<HttpField>emptyIterator() : fields.iterator();
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder out = new StringBuilder();
+        for (HttpField field : this)
+            out.append(field).append(System.lineSeparator());
+        return out.toString();
+    }
+
+    public static class Request extends MetaData
+    {
+        private String _method;
+        private HttpURI _uri;
+
+        public Request(HttpFields fields)
+        {
+            this(null, null, null, fields);
+        }
+
+        public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields)
+        {
+            this(method, uri, version, fields, Long.MIN_VALUE);
+        }
+
+        public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength)
+        {
+            super(version, fields, contentLength);
+            _method = method;
+            _uri = uri;
+        }
+
+        public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields)
+        {
+            this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields);
+        }
+
+        public Request(String method, HttpScheme scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
+        {
+            this(method, new HttpURI(scheme == null ? null : scheme.asString(), hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength);
+        }
+
+        public Request(String method, String scheme, HostPortHttpField hostPort, String uri, HttpVersion version, HttpFields fields, long contentLength)
+        {
+            this(method, new HttpURI(scheme, hostPort.getHost(), hostPort.getPort(), uri), version, fields, contentLength);
+        }
+
+        public Request(Request request)
+        {
+            this(request.getMethod(),new HttpURI(request.getURI()), request.getVersion(), new HttpFields(request.getFields()), request.getContentLength());
+        }
+
+        // TODO MetaData should be immuttable!!! 
+        public void recycle()
+        {
+            super.recycle();
+            _method = null;
+            if (_uri != null)
+                _uri.clear();
+        }
+
+        @Override
+        public boolean isRequest()
+        {
+            return true;
+        }
+
+        /**
+         * @return the HTTP method
+         */
+        public String getMethod()
+        {
+            return _method;
+        }
+
+        /**
+         * @param method the HTTP method to set
+         */
+        public void setMethod(String method)
+        {
+            _method = method;
+        }
+
+        /**
+         * @return the HTTP URI
+         */
+        public HttpURI getURI()
+        {
+            return _uri;
+        }
+
+        /**
+         * @return the HTTP URI in string form
+         */
+        public String getURIString()
+        {
+            return _uri == null ? null : _uri.toString();
+        }
+
+        /**
+         * @param uri the HTTP URI to set
+         */
+        public void setURI(HttpURI uri)
+        {
+            _uri = uri;
+        }
+
+        @Override
+        public String toString()
+        {
+            HttpFields fields = getFields();
+            return String.format("%s{u=%s,%s,h=%d}",
+                    getMethod(), getURI(), getVersion(), fields == null ? -1 : fields.size());
+        }
+    }
+
+    public static class Response extends MetaData
+    {
+        private int _status;
+        private String _reason;
+
+        public Response()
+        {
+            this(null, 0, null);
+        }
+
+        public Response(HttpVersion version, int status, HttpFields fields)
+        {
+            this(version, status, fields, Long.MIN_VALUE);
+        }
+
+        public Response(HttpVersion version, int status, HttpFields fields, long contentLength)
+        {
+            super(version, fields, contentLength);
+            _status = status;
+        }
+
+        public Response(HttpVersion version, int status, String reason, HttpFields fields, long contentLength)
+        {
+            super(version, fields, contentLength);
+            _reason = reason;
+            _status = status;
+        }
+
+        @Override
+        public boolean isResponse()
+        {
+            return true;
+        }
+
+        /**
+         * @return the HTTP status
+         */
+        public int getStatus()
+        {
+            return _status;
+        }
+
+        /**
+         * @return the HTTP reason
+         */
+        public String getReason()
+        {
+            return _reason;
+        }
+
+        /**
+         * @param status the HTTP status to set
+         */
+        public void setStatus(int status)
+        {
+            _status = status;
+        }
+
+        /**
+         * @param reason the HTTP reason to set
+         */
+        public void setReason(String reason)
+        {
+            _reason = reason;
+        }
+
+        @Override
+        public String toString()
+        {
+            HttpFields fields = getFields();
+            return String.format("%s{s=%d,h=%d}", getVersion(), getStatus(), fields == null ? -1 : fields.size());
+        }
+    }
+}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
index 145f220..290b861 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
@@ -56,20 +56,20 @@
         TEXT_JSON("text/json",StandardCharsets.UTF_8),
         APPLICATION_JSON("application/json",StandardCharsets.UTF_8),
 
-        TEXT_HTML_8859_1("text/html; charset=ISO-8859-1",TEXT_HTML),
-        TEXT_HTML_UTF_8("text/html; charset=UTF-8",TEXT_HTML),
+        TEXT_HTML_8859_1("text/html;charset=iso-8859-1",TEXT_HTML),
+        TEXT_HTML_UTF_8("text/html;charset=utf-8",TEXT_HTML),
         
-        TEXT_PLAIN_8859_1("text/plain; charset=ISO-8859-1",TEXT_PLAIN),
-        TEXT_PLAIN_UTF_8("text/plain; charset=UTF-8",TEXT_PLAIN),
+        TEXT_PLAIN_8859_1("text/plain;charset=iso-8859-1",TEXT_PLAIN),
+        TEXT_PLAIN_UTF_8("text/plain;charset=utf-8",TEXT_PLAIN),
         
-        TEXT_XML_8859_1("text/xml; charset=ISO-8859-1",TEXT_XML),
-        TEXT_XML_UTF_8("text/xml; charset=UTF-8",TEXT_XML),
+        TEXT_XML_8859_1("text/xml;charset=iso-8859-1",TEXT_XML),
+        TEXT_XML_UTF_8("text/xml;charset=utf-8",TEXT_XML),
         
-        TEXT_JSON_8859_1("text/json; charset=ISO-8859-1",TEXT_JSON),
-        TEXT_JSON_UTF_8("text/json; charset=UTF-8",TEXT_JSON),
+        TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON),
+        TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON),
         
-        APPLICATION_JSON_8859_1("text/json; charset=ISO-8859-1",APPLICATION_JSON),
-        APPLICATION_JSON_UTF_8("text/json; charset=UTF-8",APPLICATION_JSON);
+        APPLICATION_JSON_8859_1("text/json;charset=iso-8859-1",APPLICATION_JSON),
+        APPLICATION_JSON_UTF_8("text/json;charset=utf-8",APPLICATION_JSON);
 
 
         /* ------------------------------------------------------------ */
@@ -77,6 +77,7 @@
         private final Type _base;
         private final ByteBuffer _buffer;
         private final Charset _charset;
+        private final String _charsetString;
         private final boolean _assumedCharset;
         private final HttpField _field;
 
@@ -87,8 +88,9 @@
             _buffer=BufferUtil.toBuffer(s);
             _base=this;
             _charset=null;
+            _charsetString=null;
             _assumedCharset=false;
-            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+            _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string);
         } 
 
         /* ------------------------------------------------------------ */
@@ -97,10 +99,11 @@
             _string=s;
             _buffer=BufferUtil.toBuffer(s);
             _base=base;
-            int i=s.indexOf("; charset=");
-            _charset=Charset.forName(s.substring(i+10));
+            int i=s.indexOf(";charset=");
+            _charset=Charset.forName(s.substring(i+9));
+            _charsetString=_charset==null?null:_charset.toString().toLowerCase();
             _assumedCharset=false;
-            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+            _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string);
         }
 
         /* ------------------------------------------------------------ */
@@ -110,8 +113,9 @@
             _base=this;
             _buffer=BufferUtil.toBuffer(s);
             _charset=cs;
+            _charsetString=_charset==null?null:_charset.toString().toLowerCase();
             _assumedCharset=true;
-            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+            _field=new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,_string);
         }
 
         /* ------------------------------------------------------------ */
@@ -127,6 +131,12 @@
         }
         
         /* ------------------------------------------------------------ */
+        public String getCharsetString()
+        {
+            return _charsetString;
+        }
+        
+        /* ------------------------------------------------------------ */
         public boolean is(String s)
         {
             return _string.equalsIgnoreCase(s);    
@@ -181,8 +191,9 @@
             int charset=type.toString().indexOf(";charset=");
             if (charset>0)
             {
-                CACHE.put(type.toString().replace(";charset=","; charset="),type);
-                TYPES.put(type.toString().replace(";charset=","; charset="),type.asBuffer());
+                String alt=type.toString().replace(";charset=","; charset=");
+                CACHE.put(alt,type);
+                TYPES.put(alt,type.asBuffer());
             }
         }
 
@@ -292,8 +303,8 @@
 
     /* ------------------------------------------------------------ */
     /** Set a mime mapping
-     * @param extension
-     * @param type
+     * @param extension the extension
+     * @param type the mime type
      */
     public void addMimeMapping(String extension,String type)
     {
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
index d219687..61c047c 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
@@ -26,45 +26,55 @@
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
+import java.util.function.Predicate;
 
 import org.eclipse.jetty.util.ArrayTernaryTrie;
-import org.eclipse.jetty.util.IncludeExclude;
-import org.eclipse.jetty.util.Predicate;
 import org.eclipse.jetty.util.Trie;
 import org.eclipse.jetty.util.URIUtil;
 
-/* ------------------------------------------------------------ */
-/** URI path map to Object.
+/** 
+ * URI path map to Object.
+ * <p>
  * This mapping implements the path specification recommended
  * in the 2.2 Servlet API.
+ * </p>
  *
- * Path specifications can be of the following forms:<PRE>
+ * <p>
+ * Path specifications can be of the following forms:
+ * </p>
+ * <pre>
  * /foo/bar           - an exact path specification.
  * /foo/*             - a prefix path specification (must end '/*').
  * *.ext              - a suffix path specification.
  * /                  - the default path specification.
  * ""                 - the / path specification
- * </PRE>
- * Matching is performed in the following order <NL>
- * <LI>Exact match.
- * <LI>Longest prefix match.
- * <LI>Longest suffix match.
- * <LI>default.
- * </NL>
+ * </pre>
+ * 
+ * Matching is performed in the following order 
+ * <ol>
+ * <li>Exact match.</li>
+ * <li>Longest prefix match.</li>
+ * <li>Longest suffix match.</li>
+ * <li>default.</li>
+ * </ol>
+ * 
+ * <p>
  * Multiple path specifications can be mapped by providing a list of
  * specifications. By default this class uses characters ":," as path
  * separators, unless configured differently by calling the static
  * method @see PathMap#setPathSpecSeparators(String)
- * <P>
+ * <p>
  * Special characters within paths such as '?� and ';' are not treated specially
  * as it is assumed they would have been either encoded in the original URL or
  * stripped from the path.
- * <P>
+ * <p>
  * This class is not synchronized.  If concurrent modifications are
  * possible then it should be synchronized at a higher level.
- *
- *
+ * 
+ * @param <O> the Map.Entry value type
+ * @deprecated replaced with {@link org.eclipse.jetty.http.pathmap.PathMappings} (this class will be removed in Jetty 10) 
  */
+@Deprecated
 public class PathMap<O> extends HashMap<String,O>
 {
     /* ------------------------------------------------------------ */
@@ -118,11 +128,13 @@
     }
 
     /* --------------------------------------------------------------- */
-    /** Construct from dictionary PathMap.
+    /** 
+     * Construct from dictionary PathMap.
+     * @param dictMap the map representing the dictionary to build this PathMap from
      */
-    public PathMap(Map<String, ? extends O> m)
+    public PathMap(Map<String, ? extends O> dictMap)
     {
-        putAll(m);
+        putAll(dictMap);
     }
 
     /* --------------------------------------------------------------- */
@@ -386,20 +398,23 @@
 
     /* --------------------------------------------------------------- */
     /**
+     * @param pathSpec the path spec
+     * @param path the path
      * @return true if match.
      */
     public static boolean match(String pathSpec, String path)
-        throws IllegalArgumentException
     {
         return match(pathSpec, path, false);
     }
 
     /* --------------------------------------------------------------- */
     /**
+     * @param pathSpec the path spec
+     * @param path the path
+     * @param noDefault true to not handle the default path "/" special, false to allow matcher rules to run  
      * @return true if match.
      */
     public static boolean match(String pathSpec, String path, boolean noDefault)
-        throws IllegalArgumentException
     {
         if (pathSpec.length()==0)
             return "/".equals(path);
@@ -435,6 +450,8 @@
 
     /* --------------------------------------------------------------- */
     /** Return the portion of a path that matches a path spec.
+     * @param pathSpec the path spec
+     * @param path the path
      * @return null if no match at all.
      */
     public static String pathMatch(String pathSpec, String path)
@@ -463,6 +480,8 @@
 
     /* --------------------------------------------------------------- */
     /** Return the portion of a path that is after a path spec.
+     * @param pathSpec the path spec
+     * @param path the path
      * @return The path info string
      */
     public static String pathInfo(String pathSpec, String path)
@@ -618,9 +637,5 @@
         { 
             return _map.containsMatch(s); 
         }
-        public boolean matches(String item)
-        {
-            return _map.containsMatch(item);
-        }
     }
 }
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java
new file mode 100644
index 0000000..6c81a91
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PreEncodedHttpField.java
@@ -0,0 +1,94 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ServiceLoader;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** Pre encoded HttpField.
+ * <p>A HttpField that will be cached and used many times can be created as 
+ * a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder}
+ * instances discovered by the {@link ServiceLoader} to pre-encode the header 
+ * for each version of HTTP in use.  This will save garbage 
+ * and CPU each time the field is encoded into a response.
+ * </p>
+ */
+public class PreEncodedHttpField extends HttpField
+{
+    private final static Logger LOG = Log.getLogger(PreEncodedHttpField.class);
+    private final static HttpFieldPreEncoder[] __encoders;
+    
+    static
+    { 
+        List<HttpFieldPreEncoder> encoders = new ArrayList<>();
+        Iterator<HttpFieldPreEncoder> iter = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader()).iterator();
+        while (iter.hasNext())
+        {
+            try
+            {
+                encoders.add(iter.next());
+            }
+            catch(Error|RuntimeException e)
+            {
+                LOG.debug(e);
+            }
+        }
+        // TODO avoid needing this catch all
+        if (encoders.size()==0)
+            encoders.add(new Http1FieldPreEncoder());
+        LOG.debug("HttpField encoders loaded: {}",encoders);
+        __encoders = encoders.toArray(new HttpFieldPreEncoder[encoders.size()]);
+    }
+    
+    private final byte[][] _encodedField=new byte[2][];
+
+    public PreEncodedHttpField(HttpHeader header,String name,String value)
+    {
+        super(header,name, value);
+        
+        for (HttpFieldPreEncoder e:__encoders)
+        {
+            _encodedField[e.getHttpVersion()==HttpVersion.HTTP_2?1:0]=e.getEncodedField(header,header.asString(),value);
+        }
+    }
+    
+    public PreEncodedHttpField(HttpHeader header,String value)
+    {
+        this(header,header.asString(),value);
+    }
+    
+    public PreEncodedHttpField(String name,String value)
+    {
+        this(null,name,value);
+    }
+    
+    public void putTo(ByteBuffer bufferInFillMode, HttpVersion version)
+    {
+        bufferInFillMode.put(_encodedField[version==HttpVersion.HTTP_2?1:0]);
+    }
+}
\ No newline at end of file
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java
new file mode 100644
index 0000000..7416c2c
--- /dev/null
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java
@@ -0,0 +1,227 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http.MimeTypes.Type;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.resource.Resource;
+
+
+/* ------------------------------------------------------------ */
+/** HttpContent created from a {@link Resource}.
+ * <p>The HttpContent is used to server static content that is not
+ * cached. So fields and values are only generated as need be an not 
+ * kept for reuse</p>
+ */
+public class ResourceHttpContent implements HttpContent
+{
+    final Resource _resource;
+    final String _contentType;
+    final int _maxBuffer;
+    HttpContent _gzip;
+    String _etag;
+
+    /* ------------------------------------------------------------ */
+    public ResourceHttpContent(final Resource resource, final String contentType)
+    {
+        this(resource,contentType,-1,null);
+    }
+
+    /* ------------------------------------------------------------ */
+    public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer)
+    {
+        this(resource,contentType,maxBuffer,null);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer, HttpContent gzip)
+    {
+        _resource=resource;
+        _contentType=contentType;
+        _maxBuffer=maxBuffer;
+        _gzip=gzip;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getContentTypeValue()
+    {
+        return _contentType;
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpField getContentType()
+    {
+        return _contentType==null?null:new HttpField(HttpHeader.CONTENT_TYPE,_contentType);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpField getContentEncoding()
+    {
+        return null;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getContentEncodingValue()
+    {
+        return null;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getCharacterEncoding()
+    {
+        return _contentType==null?null:MimeTypes.getCharsetFromContentType(_contentType);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public Type getMimeType()
+    {
+        return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType));
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpField getLastModified()
+    {
+        long lm = _resource.lastModified();
+        return lm>=0?new HttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(lm)):null;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getLastModifiedValue()
+    {
+        long lm = _resource.lastModified();
+        return lm>=0?DateGenerator.formatDate(lm):null;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public ByteBuffer getDirectBuffer()
+    {
+        if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length())
+            return null;
+        try
+        {
+            return BufferUtil.toBuffer(_resource,true);
+        }
+        catch(IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpField getETag()
+    {
+        return new HttpField(HttpHeader.ETAG,getETagValue());
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public String getETagValue()
+    {
+        return _resource.getWeakETag();
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public ByteBuffer getIndirectBuffer()
+    {
+        if (_resource.length()<=0 || _maxBuffer>0 && _maxBuffer<_resource.length())
+            return null;
+        try
+        {
+            return BufferUtil.toBuffer(_resource,false);
+        }
+        catch(IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpField getContentLength()
+    {
+        long l=_resource.length();
+        return l==-1?null:new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,_resource.length());
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public long getContentLengthValue()
+    {
+        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();
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x{r=%s,gz=%b}",this.getClass().getSimpleName(),hashCode(),_resource,_gzip!=null);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpContent getGzipContent()
+    {
+        return _gzip==null?null:new GzipHttpContent(this,_gzip);
+    }
+
+}
\ No newline at end of file
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java
index 1ffb783..c1a3235 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathSpecSet.java
@@ -24,8 +24,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
-
-import org.eclipse.jetty.util.Predicate;
+import java.util.function.Predicate;
 
 /**
  * A Set of PathSpec strings.
diff --git a/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder b/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder
new file mode 100644
index 0000000..92640bd
--- /dev/null
+++ b/jetty-http/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder
@@ -0,0 +1 @@
+org.eclipse.jetty.http.Http1FieldPreEncoder
\ No newline at end of file
diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties
index 311c802..04fe87e 100644
--- a/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties
+++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/encoding.properties
@@ -1,4 +1,5 @@
-text/html	= ISO-8859-1
-text/plain	= ISO-8859-1
-text/xml	= UTF-8
-text/json   = UTF-8
+text/html=utf-8
+text/plain=iso-8859-1
+text/xml=utf-8
+text/json=utf-8
+application/xhtml+xml=utf-8
\ No newline at end of file
diff --git a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties
index 654454c..e575db1 100644
--- a/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties
+++ b/jetty-http/src/main/resources/org/eclipse/jetty/http/mime.properties
@@ -10,6 +10,7 @@
 avi=video/x-msvideo
 bcpio=application/x-bcpio
 bin=application/octet-stream
+bmp=image/bmp
 cab=application/x-cabinet
 cdf=application/x-netcdf
 class=application/java-vm
@@ -18,7 +19,7 @@
 crt=application/x-x509-ca-cert
 csh=application/x-csh
 css=text/css
-csv=text/comma-separated-values
+csv=text/csv
 dcr=application/x-director
 dir=application/x-director
 dll=application/x-msdownload
@@ -50,6 +51,7 @@
 java=text/plain
 jnlp=application/x-java-jnlp-file
 jpe=image/jpeg
+jp2=image/jpeg2000
 jpeg=image/jpeg
 jpg=image/jpeg
 js=application/javascript
@@ -112,6 +114,7 @@
 qml=text/x-qml
 qt=video/quicktime
 ra=audio/x-pn-realaudio
+rar=application/x-rar-compressed
 ram=audio/x-pn-realaudio
 ras=image/x-cmu-raster
 rdf=application/rdf+xml
@@ -169,6 +172,7 @@
 wrl=model/vrml
 wtls-ca-certificate=application/vnd.wap.wtls-ca-certificate
 xbm=image/x-xbitmap
+xcf=image/xcf
 xht=application/xhtml+xml
 xhtml=application/xhtml+xml
 xls=application/vnd.ms-excel
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java
new file mode 100644
index 0000000..b9ecac7
--- /dev/null
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldTest.java
@@ -0,0 +1,184 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.junit.Test;
+
+public class HttpFieldTest
+{
+
+    @Test
+    public void testContainsSimple() throws Exception
+    {
+        HttpField field = new HttpField("name","SomeValue");
+        assertTrue(field.contains("somevalue"));
+        assertTrue(field.contains("sOmEvAlUe"));
+        assertTrue(field.contains("SomeValue"));
+        assertFalse(field.contains("other"));
+        assertFalse(field.contains("some"));
+        assertFalse(field.contains("Some"));
+        assertFalse(field.contains("value"));
+        assertFalse(field.contains("v"));
+        assertFalse(field.contains(""));
+        assertFalse(field.contains(null));
+    }
+    
+    @Test
+    public void testCaseInsensitiveHashcode_KnownField() throws Exception
+    {
+        HttpField fieldFoo1 = new HttpField("Cookie","foo");
+        HttpField fieldFoo2 = new HttpField("cookie","foo");
+        
+        assertThat("Field hashcodes are case insensitive", fieldFoo1.hashCode(), is(fieldFoo2.hashCode()));
+    }
+    
+    @Test
+    public void testCaseInsensitiveHashcode_UnknownField() throws Exception
+    {
+        HttpField fieldFoo1 = new HttpField("X-Foo","bar");
+        HttpField fieldFoo2 = new HttpField("x-foo","bar");
+        
+        assertThat("Field hashcodes are case insensitive", fieldFoo1.hashCode(), is(fieldFoo2.hashCode()));
+    }
+
+    @Test
+    public void testContainsList() throws Exception
+    {
+        HttpField field = new HttpField("name",",aaa,Bbb,CCC, ddd , e e, \"\\\"f,f\\\"\", ");
+        assertTrue(field.contains("aaa"));
+        assertTrue(field.contains("bbb"));
+        assertTrue(field.contains("ccc"));
+        assertTrue(field.contains("Aaa"));
+        assertTrue(field.contains("Bbb"));
+        assertTrue(field.contains("Ccc"));
+        assertTrue(field.contains("AAA"));
+        assertTrue(field.contains("BBB"));
+        assertTrue(field.contains("CCC"));
+        assertTrue(field.contains("ddd"));
+        assertTrue(field.contains("e e"));
+        assertTrue(field.contains("\"f,f\""));
+        assertFalse(field.contains(""));
+        assertFalse(field.contains("aa"));
+        assertFalse(field.contains("bb"));
+        assertFalse(field.contains("cc"));
+        assertFalse(field.contains(null));
+    }
+    
+
+    @Test
+    public void testQualityContainsList() throws Exception
+    {
+        HttpField field;
+        
+        field = new HttpField("name","yes");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+
+        field = new HttpField("name",",yes,");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","other,yes,other");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","other,  yes  ,other");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","other,  y s  ,other");
+        assertTrue(field.contains("y s"));
+        assertFalse(field.contains("no"));
+
+        field = new HttpField("name","other,  \"yes\"  ,other");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","other,  \"\\\"yes\\\"\"  ,other");
+        assertTrue(field.contains("\"yes\""));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name",";no,yes,;no");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+
+        field = new HttpField("name","no;q=0,yes;q=1,no; q = 0");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","no;q=0.0000,yes;q=0.0001,no; q = 0.00000");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+        
+        field = new HttpField("name","no;q=0.0000,Yes;Q=0.0001,no; Q = 0.00000");
+        assertTrue(field.contains("yes"));
+        assertFalse(field.contains("no"));
+       
+    }
+    
+    @Test
+    public void testValues()
+    {
+        String[] values = new HttpField("name","value").getValues();
+        assertEquals(1,values.length);
+        assertEquals("value",values[0]);
+        
+
+        values = new HttpField("name","a,b,c").getValues();
+        assertEquals(3,values.length);
+        assertEquals("a",values[0]);
+        assertEquals("b",values[1]);
+        assertEquals("c",values[2]);
+
+        values = new HttpField("name","a,\"x,y,z\",c").getValues();
+        assertEquals(3,values.length);
+        assertEquals("a",values[0]);
+        assertEquals("x,y,z",values[1]);
+        assertEquals("c",values[2]);
+        
+        values = new HttpField("name","a,\"x,\\\"p,q\\\",z\",c").getValues();
+        assertEquals(3,values.length);
+        assertEquals("a",values[0]);
+        assertEquals("x,\"p,q\",z",values[1]);
+        assertEquals("c",values[2]);
+        
+    }
+    
+    @Test
+    public void testCachedField()
+    {
+        PreEncodedHttpField field = new PreEncodedHttpField(HttpHeader.ACCEPT,"something");
+        ByteBuffer buf = BufferUtil.allocate(256);
+        BufferUtil.clearToFill(buf);
+        field.putTo(buf,HttpVersion.HTTP_1_0);
+        BufferUtil.flipToFlush(buf,0);
+        String s=BufferUtil.toString(buf);
+        
+        assertEquals("Accept: something\r\n",s);
+    }
+}
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
index 9491332..38c17cb 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
@@ -27,6 +27,9 @@
 
 import java.nio.ByteBuffer;
 import java.util.Enumeration;
+import java.util.List;
+import java.util.NoSuchElementException;
+
 import org.eclipse.jetty.util.BufferUtil;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
@@ -45,9 +48,10 @@
         header.put("name0", "value:0");
         header.put("name1", "value1");
 
-        assertEquals("value:0",header.getStringField("name0"));
-        assertEquals("value1",header.getStringField("name1"));
-        assertNull(header.getStringField("name2"));
+        assertEquals(2,header.size());
+        assertEquals("value:0",header.get("name0"));
+        assertEquals("value1",header.get("name1"));
+        assertNull(header.get("name2"));
 
         int matches=0;
         Enumeration<String> e = header.getFieldNames();
@@ -65,6 +69,7 @@
         assertEquals(true, e.hasMoreElements());
         assertEquals(e.nextElement(), "value:0");
         assertEquals(false, e.hasMoreElements());
+        
     }
 
     @Test
@@ -96,10 +101,45 @@
         header.put("name0", "value0");
         header.put("name1", "value1");
 
-        assertEquals("value0",header.getStringField("name0"));
-        assertEquals("value0",header.getStringField("Name0"));
-        assertEquals("value1",header.getStringField("name1"));
-        assertEquals("value1",header.getStringField("Name1"));
+        assertEquals("value0",header.get("name0"));
+        assertEquals("value0",header.get("Name0"));
+        assertEquals("value1",header.get("name1"));
+        assertEquals("value1",header.get("Name1"));
+        assertEquals(null,header.get("Name2"));
+        
+        assertEquals("value0",header.getField("name0").getValue());
+        assertEquals("value0",header.getField("Name0").getValue());
+        assertEquals("value1",header.getField("name1").getValue());
+        assertEquals("value1",header.getField("Name1").getValue());
+        assertEquals(null,header.getField("Name2"));
+
+        assertEquals("value0",header.getField(0).getValue());
+        assertEquals("value1",header.getField(1).getValue());
+        try
+        {
+            header.getField(2);
+            Assert.fail();
+        }
+        catch(NoSuchElementException e)
+        {}        
+    }
+    
+    @Test
+    public void testGetKnown() throws Exception
+    {
+        HttpFields header = new HttpFields();
+
+        header.put("Connection", "value0");
+        header.put(HttpHeader.ACCEPT, "value1");
+
+        assertEquals("value0",header.get(HttpHeader.CONNECTION));
+        assertEquals("value1",header.get(HttpHeader.ACCEPT));
+        
+        assertEquals("value0",header.getField(HttpHeader.CONNECTION).getValue());
+        assertEquals("value1",header.getField(HttpHeader.ACCEPT).getValue());
+        
+        assertEquals(null,header.getField(HttpHeader.AGE));
+        assertEquals(null,header.get(HttpHeader.AGE));
     }
 
     @Test
@@ -150,16 +190,16 @@
         header.put("name1", "xxxxxx");
         header.put("name2", "value2");
 
-        assertEquals("value0",header.getStringField("name0"));
-        assertEquals("xxxxxx",header.getStringField("name1"));
-        assertEquals("value2",header.getStringField("name2"));
+        assertEquals("value0",header.get("name0"));
+        assertEquals("xxxxxx",header.get("name1"));
+        assertEquals("value2",header.get("name2"));
 
         header.put("name1", "value1");
 
-        assertEquals("value0",header.getStringField("name0"));
-        assertEquals("value1",header.getStringField("name1"));
-        assertEquals("value2",header.getStringField("name2"));
-        assertNull(header.getStringField("name3"));
+        assertEquals("value0",header.get("name0"));
+        assertEquals("value1",header.get("name1"));
+        assertEquals("value2",header.get("name2"));
+        assertNull(header.get("name3"));
 
         int matches=0;
         Enumeration<String> e = header.getFieldNames();
@@ -185,22 +225,22 @@
     @Test
     public void testRemovePut() throws Exception
     {
-        HttpFields header = new HttpFields();
+        HttpFields header = new HttpFields(1);
 
         header.put("name0", "value0");
         header.put("name1", "value1");
         header.put("name2", "value2");
 
-        assertEquals("value0",header.getStringField("name0"));
-        assertEquals("value1",header.getStringField("name1"));
-        assertEquals("value2",header.getStringField("name2"));
+        assertEquals("value0",header.get("name0"));
+        assertEquals("value1",header.get("name1"));
+        assertEquals("value2",header.get("name2"));
 
         header.remove("name1");
 
-        assertEquals("value0",header.getStringField("name0"));
-        assertNull(header.getStringField("name1"));
-        assertEquals("value2",header.getStringField("name2"));
-        assertNull(header.getStringField("name3"));
+        assertEquals("value0",header.get("name0"));
+        assertNull(header.get("name1"));
+        assertEquals("value2",header.get("name2"));
+        assertNull(header.get("name3"));
 
         int matches=0;
         Enumeration<String> e = header.getFieldNames();
@@ -229,16 +269,16 @@
         fields.add("name1", "valueA");
         fields.add("name2", "value2");
 
-        assertEquals("value0",fields.getStringField("name0"));
-        assertEquals("valueA",fields.getStringField("name1"));
-        assertEquals("value2",fields.getStringField("name2"));
+        assertEquals("value0",fields.get("name0"));
+        assertEquals("valueA",fields.get("name1"));
+        assertEquals("value2",fields.get("name2"));
 
         fields.add("name1", "valueB");
 
-        assertEquals("value0",fields.getStringField("name0"));
-        assertEquals("valueA",fields.getStringField("name1"));
-        assertEquals("value2",fields.getStringField("name2"));
-        assertNull(fields.getStringField("name3"));
+        assertEquals("value0",fields.get("name0"));
+        assertEquals("valueA",fields.get("name1"));
+        assertEquals("value2",fields.get("name2"));
+        assertNull(fields.get("name3"));
 
         int matches=0;
         Enumeration<String> e = fields.getFieldNames();
@@ -301,9 +341,29 @@
         assertEquals(true, e.hasMoreElements());
         assertEquals(e.nextElement(), "value1D");
         assertEquals(false, e.hasMoreElements());
-        
     }
 
+
+    @Test
+    public void testGetQualityValues() throws Exception
+    {
+        HttpFields fields = new HttpFields();
+
+        fields.put("some", "value");
+        fields.add("name", "zero;q=0.9,four;q=0.1");
+        fields.put("other", "value");
+        fields.add("name", "nothing;q=0");
+        fields.add("name", "one;q=0.4");
+        fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3");
+        
+        List<String> list = HttpFields.qualityList(fields.getValues("name",","));
+        assertEquals("zero",HttpFields.valueParameters(list.get(0),null));
+        assertEquals("one",HttpFields.valueParameters(list.get(1),null));
+        assertEquals("two",HttpFields.valueParameters(list.get(2),null));
+        assertEquals("three",HttpFields.valueParameters(list.get(3),null));
+        assertEquals("four",HttpFields.valueParameters(list.get(4),null));
+    }
+    
     @Test
     public void testDateFields() throws Exception
     {
@@ -343,7 +403,7 @@
         assertEquals(951825600000L,d5);
 
         fields.putDateField("D2",d1);
-        assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.getStringField("D2"));
+        assertEquals("Fri, 31 Dec 1999 23:59:59 GMT",fields.get("D2"));
     }
 
     @Test
@@ -352,16 +412,16 @@
         HttpFields fields = new HttpFields();
 
         fields.putDateField("Dzero",0);
-        assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.getStringField("Dzero"));
+        assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Dzero"));
 
         fields.putDateField("Dminus",-1);
-        assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.getStringField("Dminus"));
+        assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus"));
 
         fields.putDateField("Dminus",-1000);
-        assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.getStringField("Dminus"));
+        assertEquals("Wed, 31 Dec 1969 23:59:59 GMT",fields.get("Dminus"));
 
         fields.putDateField("Dancient",Long.MIN_VALUE);
-        assertEquals("Sun, 02 Dec 55 16:47:04 GMT",fields.getStringField("Dancient"));
+        assertEquals("Sun, 02 Dec 55 16:47:04 GMT",fields.get("Dancient"));
     }
 
     @Test
@@ -371,15 +431,33 @@
 
         header.put("I1", "42");
         header.put("I2", " 43 99");
-        header.put("I3", "-44;");
+        header.put("I3", "-44");
         header.put("I4", " - 45abc");
         header.put("N1", " - ");
         header.put("N2", "xx");
 
         long i1=header.getLongField("I1");
-        long i2=header.getLongField("I2");
+        try
+        {
+            header.getLongField("I2");
+            assertTrue(false);
+        }
+        catch(NumberFormatException e)
+        {
+            assertTrue(true);
+        }
+            
         long i3=header.getLongField("I3");
-        long i4=header.getLongField("I4");
+        
+        try
+        {
+            header.getLongField("I4");
+            assertTrue(false);
+        }
+        catch(NumberFormatException e)
+        {
+            assertTrue(true);
+        }
 
         try{
             header.getLongField("N1");
@@ -400,14 +478,12 @@
         }
 
         assertEquals(42,i1);
-        assertEquals(43,i2);
         assertEquals(-44,i3);
-        assertEquals(-45,i4);
 
         header.putLongField("I5", 46);
         header.putLongField("I6",-47);
-        assertEquals("46",header.getStringField("I5"));
-        assertEquals("-47",header.getStringField("I6"));
+        assertEquals("46",header.get("I5"));
+        assertEquals("-47",header.get("I6"));
 
     }
 
@@ -416,20 +492,38 @@
     {
         HttpFields header = new HttpFields();
 
-        header.add("0", "");
-        header.add("1", ",");
-        header.add("2", ",,");
-        header.add("3", "abc");
-        header.add("4", "def");
-        header.add("5", "abc,def,hig");
-        header.add("6", "abc");
-        header.add("6", "def");
-        header.add("6", "hig");
+        header.add("n0", "");
+        header.add("n1", ",");
+        header.add("n2", ",,");
+        header.add("N3", "abc");
+        header.add("N4", "def");
+        header.add("n5", "abc,def,hig");
+        header.add("N6", "abc");
+        header.add("n6", "def");
+        header.add("N6", "hig");
+        header.add("n7", "abc ,  def;q=0.9  ,  hig");
+        header.add("n8", "abc ,  def;q=0  ,  hig");
+        header.add(HttpHeader.ACCEPT, "abc ,  def;q=0  ,  hig");
 
-        for (int i=0;i<7;i++)
+        for (int i=0;i<8;i++)
         {
-            assertFalse(""+i,header.contains(""+i,"xyz"));
-            assertEquals(""+i,i>=4,header.contains(""+i,"def"));
+            assertTrue(header.containsKey("n"+i));
+            assertTrue(header.containsKey("N"+i));
+            assertFalse(""+i,header.contains("n"+i,"xyz"));
+            assertEquals(""+i,i>=4,header.contains("n"+i,"def"));
         }
+        
+        
+        assertTrue(header.contains(new HttpField("N5","def")));
+        assertTrue(header.contains(new HttpField("accept","abc")));
+        assertTrue(header.contains(HttpHeader.ACCEPT,"abc"));
+        assertFalse(header.contains(new HttpField("N5","xyz")));
+        assertFalse(header.contains(new HttpField("N8","def")));
+        assertFalse(header.contains(HttpHeader.ACCEPT,"def"));
+        assertFalse(header.contains(HttpHeader.AGE,"abc"));
+        
+        assertFalse(header.containsKey("n11"));
+        
     }
+    
 }
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java
index 05b35fa..1b7e835 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java
@@ -29,16 +29,16 @@
 {
     public final static String[] connect={null,"keep-alive","close"};
 
-    class Info extends HttpGenerator.RequestInfo
+    class Info extends MetaData.Request
     {
         Info(String method,String uri)
         {
-            super(HttpVersion.HTTP_1_1,new HttpFields(),-1,method,uri);
+            super(method,new HttpURI(uri),HttpVersion.HTTP_1_1,new HttpFields(),-1);
         }
 
         public Info(String method,String uri, int contentLength)
         {
-            super(HttpVersion.HTTP_1_1,new HttpFields(),contentLength,method,uri);
+            super(method,new HttpURI(uri),HttpVersion.HTTP_1_1,new HttpFields(),contentLength);
         }
     }
 
@@ -54,8 +54,8 @@
         Assert.assertEquals(HttpGenerator.State.START, gen.getState());
 
         Info info = new Info("GET","/index.html");
-        info.getHttpFields().add("Host","something");
-        info.getHttpFields().add("User-Agent","test");
+        info.getFields().add("Host","something");
+        info.getFields().add("User-Agent","test");
         Assert.assertTrue(!gen.isChunking());
 
         result=gen.generateRequest(info,null,null,null, true);
@@ -91,8 +91,8 @@
         Assert.assertEquals(HttpGenerator.State.START, gen.getState());
 
         Info info = new Info("POST","/index.html");
-        info.getHttpFields().add("Host","something");
-        info.getHttpFields().add("User-Agent","test");
+        info.getFields().add("Host","something");
+        info.getFields().add("User-Agent","test");
         Assert.assertTrue(!gen.isChunking());
 
         result=gen.generateRequest(info,null,null,null, true);
@@ -130,8 +130,8 @@
         Assert.assertEquals(HttpGenerator.State.START, gen.getState());
 
         Info info = new Info("POST","/index.html");
-        info.getHttpFields().add("Host","something");
-        info.getHttpFields().add("User-Agent","test");
+        info.getFields().add("Host","something");
+        info.getFields().add("User-Agent","test");
 
         result=gen.generateRequest(info,null,null,content0, true);
         Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@@ -176,8 +176,8 @@
         Assert.assertEquals(HttpGenerator.State.START, gen.getState());
 
         Info info = new Info("POST","/index.html");
-        info.getHttpFields().add("Host","something");
-        info.getHttpFields().add("User-Agent","test");
+        info.getFields().add("Host","something");
+        info.getFields().add("User-Agent","test");
 
         result=gen.generateRequest(info,null,null,content0, false);
         Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@@ -248,8 +248,8 @@
         Assert.assertEquals(HttpGenerator.State.START, gen.getState());
 
         Info info = new Info("POST","/index.html",58);
-        info.getHttpFields().add("Host","something");
-        info.getHttpFields().add("User-Agent","test");
+        info.getFields().add("Host","something");
+        info.getFields().add("User-Agent","test");
 
         result=gen.generateRequest(info,null,null,content0, false);
         Assert.assertEquals(HttpGenerator.Result.NEED_HEADER, result);
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java
index fa400c6..d808edb 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerHTTPTest.java
@@ -18,6 +18,13 @@
 
 package org.eclipse.jetty.http;
 
+import static org.hamcrest.Matchers.either;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -31,13 +38,6 @@
 import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
-import static org.hamcrest.Matchers.either;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
 @RunWith(Parameterized.class)
 public class HttpGeneratorServerHTTPTest
 {
@@ -59,14 +59,6 @@
 
         String response = run.result.build(run.httpVersion, gen, "OK\r\nTest", run.connection.val, null, run.chunks);
 
-        if (run.httpVersion == 9)
-        {
-            assertFalse(t, gen.isPersistent());
-            if (run.result._body != null)
-                assertEquals(t, run.result._body, response);
-            return;
-        }
-
         HttpParser parser = new HttpParser(handler);
         parser.setHeadResponse(run.result._head);
 
@@ -80,8 +72,7 @@
         else
             assertTrue(t, gen.isPersistent() || EnumSet.of(ConnectionType.CLOSE, ConnectionType.TE_CLOSE).contains(run.connection));
 
-        if (run.httpVersion > 9)
-            assertEquals("OK??Test", _reason);
+        assertEquals("OK??Test", _reason);
 
         if (_content == null)
             assertTrue(t, run.result._body == null);
@@ -145,7 +136,7 @@
             }
             ByteBuffer header = null;
             ByteBuffer chunk = null;
-            HttpGenerator.ResponseInfo info = null;
+            MetaData.Response info = null;
 
             loop:
             while (true)
@@ -157,12 +148,12 @@
                 // Generate
                 boolean last = !BufferUtil.hasContent(content);
 
-                HttpGenerator.Result result = gen.generateResponse(info, header, chunk, content, last);
+                HttpGenerator.Result result = gen.generateResponse(info, _head, header, chunk, content, last);
 
                 switch (result)
                 {
                     case NEED_INFO:
-                        info = new HttpGenerator.ResponseInfo(HttpVersion.fromVersion(version), _fields, _contentLength, _code, reason, _head);
+                        info = new MetaData.Response(HttpVersion.fromVersion(version), _code, reason, _fields, _contentLength);
                         continue;
 
                     case NEED_HEADER:
@@ -216,7 +207,7 @@
         }
     }
 
-    private class Handler implements HttpParser.ResponseHandler<ByteBuffer>
+    private class Handler implements HttpParser.ResponseHandler
     {
         @Override
         public boolean content(ByteBuffer ref)
@@ -247,9 +238,8 @@
         }
 
         @Override
-        public boolean parsedHeader(HttpField field)
+        public void parsedHeader(HttpField field)
         {
-            return false;
         }
 
         @Override
@@ -347,7 +337,7 @@
         for (Result result : results)
         {
             // Loop over HTTP versions
-            for (int v = 9; v <= 11; v++)
+            for (int v = 10; v <= 11; v++)
             {
                 // Loop over chunks
                 for (int chunks = 1; chunks <= 6; chunks++)
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
index 15c9209..d965279 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorServerTest.java
@@ -18,19 +18,18 @@
 
 package org.eclipse.jetty.http;
 
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
-import org.eclipse.jetty.util.BufferUtil;
-import org.junit.Assert;
-import org.junit.Test;
-
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.startsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
 public class HttpGeneratorServerTest
 { 
     
@@ -46,9 +45,9 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), 10, 200, null, false);
-        info.getHttpFields().add("Content-Type", "test/data");
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
+        info.getFields().add("Content-Type", "test/data");
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
 
         result = gen.generateResponse(info, null, null, content, true);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@@ -81,9 +80,9 @@
 
         HttpGenerator gen = new HttpGenerator();
         
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), 10, 204, "Foo", false);
-        info.getHttpFields().add("Content-Type", "test/data");
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 204, "Foo", new HttpFields(), 10);
+        info.getFields().add("Content-Type", "test/data");
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
 
         HttpGenerator.Result result = gen.generateResponse(info, header, null, content, true);
      
@@ -118,9 +117,9 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), 10, 200, null, false);
-        info.getHttpFields().add("Content-Type", "test/data;\r\nextra=value");
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
+        info.getFields().add("Content-Type", "test/data;\r\nextra=value");
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
 
         result = gen.generateResponse(info, null, null, content, true);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@@ -150,11 +149,11 @@
     public void testSendServerXPoweredBy() throws Exception
     {
         ByteBuffer header = BufferUtil.allocate(8096);
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), -1, 200, null, false);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
         HttpFields fields = new HttpFields();
         fields.add(HttpHeader.SERVER, "SomeServer");
         fields.add(HttpHeader.X_POWERED_BY, "SomePower");
-        ResponseInfo infoF = new ResponseInfo(HttpVersion.HTTP_1_1, fields, -1, 200, null, false);
+        MetaData.Response infoF = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, fields, -1);
         String head;
 
         HttpGenerator gen = new HttpGenerator(true, true);
@@ -205,8 +204,8 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), -1, 200, null, false);
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
 
         result = gen.generateResponse(info, null, null, null, true);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
@@ -238,10 +237,10 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), -1, 101, null, false);
-        info.getHttpFields().add("Upgrade", "WebSocket");
-        info.getHttpFields().add("Connection", "Upgrade");
-        info.getHttpFields().add("Sec-WebSocket-Accept", "123456789==");
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 101, null, new HttpFields(), -1);
+        info.getFields().add("Upgrade", "WebSocket");
+        info.getFields().add("Connection", "Upgrade");
+        info.getFields().add("Sec-WebSocket-Accept", "123456789==");
 
         result = gen.generateResponse(info, header, null, null, true);
         assertEquals(HttpGenerator.Result.FLUSH, result);
@@ -273,8 +272,8 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), -1, 200, null, false);
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), -1);
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
         result = gen.generateResponse(info, null, null, content0, false);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
@@ -333,8 +332,8 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), 59, 200, null, false);
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 59);
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
         result = gen.generateResponse(info, null, null, content0, false);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
@@ -396,8 +395,8 @@
         assertEquals(HttpGenerator.Result.NEED_INFO, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
 
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), 59, 200, null, false);
-        info.getHttpFields().add("Last-Modified", DateGenerator.__01Jan1970);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), BufferUtil.length(content0)+BufferUtil.length(content1));
+        info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
         result = gen.generateResponse(info, null, null, content0, false);
         assertEquals(HttpGenerator.Result.NEED_HEADER, result);
         assertEquals(HttpGenerator.State.START, gen.getState());
@@ -441,7 +440,7 @@
         fields.put(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
         String customValue = "test";
         fields.add(HttpHeader.CONNECTION, customValue);
-        ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_0, fields, -1, 200, "OK", false);
+        MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_0, 200, "OK", fields, -1);
         ByteBuffer header = BufferUtil.allocate(4096);
         HttpGenerator.Result result = generator.generateResponse(info, header, null, null, true);
         Assert.assertSame(HttpGenerator.Result.FLUSH, result);
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
index 4d8f23a..81d628d 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
@@ -18,7 +18,11 @@
 
 package org.eclipse.jetty.http;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -42,6 +46,7 @@
      * Parse until {@link State#END} state.
      * If the parser is already in the END state, then it is {@link HttpParser#reset()} and re-parsed.
      * @param parser The parser to test
+     * @param buffer the buffer to parse
      * @throws IllegalStateException If the buffers have already been partially parsed.
      */
     public static void parseAll(HttpParser parser, ByteBuffer buffer)
@@ -86,7 +91,7 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer("POST /mock/127.0.0.1 HTTP/1.1\015\012" + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("POST", _methodOrVersion);
@@ -100,7 +105,7 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer("POST /foo HTTP/1.0\015\012" + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("POST", _methodOrVersion);
@@ -115,13 +120,11 @@
         ByteBuffer buffer= BufferUtil.toBuffer("GET /999\015\012");
 
         _versionOrReason= null;
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
-        assertEquals("GET", _methodOrVersion);
-        assertEquals("/999", _uriOrStatus);
-        assertEquals(null, _versionOrReason);
-        assertEquals(-1, _headers);
+        
+        assertEquals("HTTP/0.9 not supported", _bad);
     }
 
     @Test
@@ -130,13 +133,10 @@
         ByteBuffer buffer= BufferUtil.toBuffer("POST /222  \015\012");
 
         _versionOrReason= null;
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
-        assertEquals("POST", _methodOrVersion);
-        assertEquals("/222", _uriOrStatus);
-        assertEquals(null, _versionOrReason);
-        assertEquals(-1, _headers);
+        assertEquals("HTTP/0.9 not supported", _bad);
     }
 
     @Test
@@ -144,7 +144,7 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer("POST /fo\u0690 HTTP/1.0\015\012" + "\015\012",StandardCharsets.UTF_8);
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("POST", _methodOrVersion);
@@ -158,7 +158,7 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer("POST /foo?param=\u0690 HTTP/1.0\015\012" + "\015\012",StandardCharsets.UTF_8);
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("POST", _methodOrVersion);
@@ -172,7 +172,7 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer("POST /123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/ HTTP/1.0\015\012" + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("POST", _methodOrVersion);
@@ -185,7 +185,7 @@
     public void testConnect() throws Exception
     {
         ByteBuffer buffer= BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("CONNECT", _methodOrVersion);
@@ -203,7 +203,7 @@
                 "Connection: close\015\012" +
                 "\015\012");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -218,6 +218,102 @@
         assertEquals("close", _val[1]);
         assertEquals(1, _headers);
     }
+    
+    @Test
+    public void test7230NoContinuations() throws Exception
+    {
+        ByteBuffer buffer= BufferUtil.toBuffer(
+                "GET / HTTP/1.0\015\012" +
+                "Host: localhost\015\012" +
+                "Name: value\015\012" +
+                " extra\015\012" +
+                "\015\012");
+        
+        HttpParser.RequestHandler handler  = new Handler();
+        HttpParser parser= new HttpParser(handler);
+        parseAll(parser,buffer);
+
+        Assert.assertThat(_bad,Matchers.notNullValue());
+        Assert.assertThat(_bad,Matchers.containsString("Bad Continuation"));
+    }
+
+    
+    @Test
+    public void test7230NoWhiteSpaceInName() throws Exception
+    {
+        ByteBuffer buffer= BufferUtil.toBuffer(
+                "GET / HTTP/1.0\015\012" +
+                "Host: localhost\015\012" +
+                " Name: value\015\012" +
+                "\015\012");
+        
+        HttpParser.RequestHandler handler  = new Handler();
+        HttpParser parser= new HttpParser(handler);
+        parseAll(parser,buffer);
+
+        Assert.assertThat(_bad,Matchers.notNullValue());
+        Assert.assertThat(_bad,Matchers.containsString("Bad"));
+        
+        init();
+        buffer= BufferUtil.toBuffer(
+                "GET / HTTP/1.0\015\012" +
+                "Host: localhost\015\012" +
+                "N ame: value\015\012" +
+                "\015\012");
+        
+        handler  = new Handler();
+        parser= new HttpParser(handler);
+        parseAll(parser,buffer);
+
+        Assert.assertThat(_bad,Matchers.containsString("Illegal character"));
+        
+
+        init();
+        buffer= BufferUtil.toBuffer(
+                "GET / HTTP/1.0\015\012" +
+                "Host: localhost\015\012" +
+                "Name : value\015\012" +
+                "\015\012");
+        
+        handler  = new Handler();
+        parser= new HttpParser(handler);
+        parseAll(parser,buffer);
+
+        Assert.assertThat(_bad,Matchers.containsString("Illegal character"));
+        
+    }
+    
+
+    @Test
+    public void testNoValue() throws Exception
+    {
+        ByteBuffer buffer= BufferUtil.toBuffer(
+                "GET / HTTP/1.0\015\012" +
+                "Host: localhost\015\012" +
+                "Name0: \015\012"+
+                "Name1: \015\012"+
+                "Connection: close\015\012" +
+                "\015\012");
+        
+        HttpParser.RequestHandler handler  = new Handler();
+        HttpParser parser= new HttpParser(handler);
+        parseAll(parser,buffer);
+
+        assertTrue(_headerCompleted);
+        assertTrue(_messageCompleted);
+        assertEquals("GET", _methodOrVersion);
+        assertEquals("/", _uriOrStatus);
+        assertEquals("HTTP/1.0", _versionOrReason);
+        assertEquals("Host", _hdr[0]);
+        assertEquals("localhost", _val[0]);
+        assertEquals("Name0", _hdr[1]);
+        assertEquals(null, _val[1]);
+        assertEquals("Name1", _hdr[2]);
+        assertEquals(null, _val[2]);
+        assertEquals("Connection", _hdr[3]);
+        assertEquals("close", _val[3]);
+        assertEquals(3, _headers);
+    }
 
     @Test
     public void testHeaderParseDirect() throws Exception
@@ -226,13 +322,11 @@
                 "GET / HTTP/1.0\015\012" +
                         "Host: localhost\015\012" +
                         "Header1: value1\015\012" +
-                        "Header 2  :   value 2a  \015\012" +
-                        "    value 2b  \015\012" +
-                        "Header3: \015\012" +
-                        "Header4 \015\012" +
-                        "  value4\015\012" +
-                        "Server5 : notServer\015\012" +
-                        "Host Header: notHost\015\012" +
+                        "Header2:   value 2a  \015\012" +
+                        "Header3: 3\015\012" +
+                        "Header4:value4\015\012" +
+                        "Server5: notServer\015\012" +
+                        "HostHeader: notHost\015\012" +
                         "Connection: close\015\012" +
                         "Accept-Encoding: gzip, deflated\015\012" +
                         "Accept: unknown\015\012" +
@@ -242,7 +336,7 @@
         BufferUtil.put(b0,buffer);
         BufferUtil.flipToFlush(buffer,pos);
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -253,15 +347,15 @@
         assertEquals("localhost", _val[0]);
         assertEquals("Header1", _hdr[1]);
         assertEquals("value1", _val[1]);
-        assertEquals("Header 2", _hdr[2]);
-        assertEquals("value 2a value 2b", _val[2]);
+        assertEquals("Header2", _hdr[2]);
+        assertEquals("value 2a", _val[2]);
         assertEquals("Header3", _hdr[3]);
-        assertEquals(null, _val[3]);
+        assertEquals("3", _val[3]);
         assertEquals("Header4", _hdr[4]);
         assertEquals("value4", _val[4]);
         assertEquals("Server5", _hdr[5]);
         assertEquals("notServer", _val[5]);
-        assertEquals("Host Header", _hdr[6]);
+        assertEquals("HostHeader", _hdr[6]);
         assertEquals("notHost", _val[6]);
         assertEquals("Connection", _hdr[7]);
         assertEquals("close", _val[7]);
@@ -279,18 +373,16 @@
                 "GET / HTTP/1.0\015\012" +
                         "Host: localhost\015\012" +
                         "Header1: value1\015\012" +
-                        "Header 2  :   value 2a  \015\012" +
-                        "    value 2b  \015\012" +
-                        "Header3: \015\012" +
-                        "Header4 \015\012" +
-                        "  value4\015\012" +
-                        "Server5 : notServer\015\012" +
-                        "Host Header: notHost\015\012" +
+                        "Header2:   value 2a  \015\012" +
+                        "Header3: 3\015\012" +
+                        "Header4:value4\015\012" +
+                        "Server5: notServer\015\012" +
+                        "HostHeader: notHost\015\012" +
                         "Connection: close\015\012" +
                         "Accept-Encoding: gzip, deflated\015\012" +
                         "Accept: unknown\015\012" +
                 "\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -301,15 +393,15 @@
         assertEquals("localhost", _val[0]);
         assertEquals("Header1", _hdr[1]);
         assertEquals("value1", _val[1]);
-        assertEquals("Header 2", _hdr[2]);
-        assertEquals("value 2a value 2b", _val[2]);
+        assertEquals("Header2", _hdr[2]);
+        assertEquals("value 2a", _val[2]);
         assertEquals("Header3", _hdr[3]);
-        assertEquals(null, _val[3]);
+        assertEquals("3", _val[3]);
         assertEquals("Header4", _hdr[4]);
         assertEquals("value4", _val[4]);
         assertEquals("Server5", _hdr[5]);
         assertEquals("notServer", _val[5]);
-        assertEquals("Host Header", _hdr[6]);
+        assertEquals("HostHeader", _hdr[6]);
         assertEquals("notHost", _val[6]);
         assertEquals("Connection", _hdr[7]);
         assertEquals("close", _val[7]);
@@ -329,18 +421,16 @@
                 "GET / HTTP/1.0\n" +
                         "Host: localhost\n" +
                         "Header1: value1\n" +
-                        "Header 2  :   value 2a  \n" +
-                        "    value 2b  \n" +
-                        "Header3: \n" +
-                        "Header4 \n" +
-                        "  value4\n" +
-                        "Server5 : notServer\n" +
-                        "Host Header: notHost\n" +
+                        "Header2:   value 2a value 2b  \n" +
+                        "Header3: 3\n" +
+                        "Header4:value4\n" +
+                        "Server5: notServer\n" +
+                        "HostHeader: notHost\n" +
                         "Connection: close\n" +
                         "Accept-Encoding: gzip, deflated\n" +
                         "Accept: unknown\n" +
                 "\n");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -351,15 +441,15 @@
         assertEquals("localhost", _val[0]);
         assertEquals("Header1", _hdr[1]);
         assertEquals("value1", _val[1]);
-        assertEquals("Header 2", _hdr[2]);
+        assertEquals("Header2", _hdr[2]);
         assertEquals("value 2a value 2b", _val[2]);
         assertEquals("Header3", _hdr[3]);
-        assertEquals(null, _val[3]);
+        assertEquals("3", _val[3]);
         assertEquals("Header4", _hdr[4]);
         assertEquals("value4", _val[4]);
         assertEquals("Server5", _hdr[5]);
         assertEquals("notServer", _val[5]);
-        assertEquals("Host Header", _hdr[6]);
+        assertEquals("HostHeader", _hdr[6]);
         assertEquals("notHost", _val[6]);
         assertEquals("Connection", _hdr[7]);
         assertEquals("close", _val[7]);
@@ -379,7 +469,7 @@
                         "Name1: \"value\t1\"\n" +
                         "Name2: \"value\t2A\",\"value,2B\"\t\n" +
                 "\n");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -408,7 +498,7 @@
         BufferUtil.put(BufferUtil.toBuffer("  \r\n\r\n"),buffer);
         BufferUtil.flipToFlush(buffer,0);
                     
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -429,7 +519,7 @@
         ByteBuffer buffer= BufferUtil.toBuffer(
             "G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertThat(_bad,Matchers.notNullValue());
@@ -441,7 +531,7 @@
         ByteBuffer buffer= BufferUtil.toBuffer(
             "GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertThat(_bad,Matchers.notNullValue());
@@ -454,7 +544,7 @@
         ByteBuffer buffer= BufferUtil.toBuffer(
             "GET / HTTP/1.0\r\nH\u00e6der0: value0\r\n\n\n");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertThat(_bad,Matchers.notNullValue());
@@ -469,7 +559,7 @@
             "Header: value\talternate\r\n" +
             "\n\n");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         
@@ -490,7 +580,7 @@
                 "HOST: localhost\015\012" +
                 "cOnNeCtIoN: ClOsE\015\012"+
                 "\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler,-1,false);
         parseAll(parser,buffer);
 
@@ -512,7 +602,7 @@
                 "HOST: localhost\015\012" +
                 "cOnNeCtIoN: ClOsE\015\012"+
                 "\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler,-1,true);
         parseAll(parser,buffer);
 
@@ -533,11 +623,9 @@
                 "XXXXSPLIT / HTTP/1.0\015\012" +
                     "Host: localhost\015\012" +
                     "Header1: value1\015\012" +
-                    "Header2  :   value 2a  \015\012" +
-                    "                    value 2b  \015\012" +
-                    "Header3: \015\012" +
-                    "Header4 \015\012" +
-                    "  value4\015\012" +
+                    "Header2:   value 2a  \015\012" +
+                    "Header3: 3\015\012" +
+                    "Header4:value4\015\012" +
                     "Server5: notServer\015\012" +
                     "\015\012ZZZZ");
         buffer.position(2);
@@ -546,7 +634,7 @@
 
         for (int i=0;i<buffer.capacity()-4;i++)
         {
-            HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+            HttpParser.RequestHandler handler  = new Handler();
             HttpParser parser= new HttpParser(handler);
 
             // System.err.println(BufferUtil.toDetailString(buffer));
@@ -571,9 +659,9 @@
             assertEquals("Header1", _hdr[1]);
             assertEquals("value1", _val[1]);
             assertEquals("Header2", _hdr[2]);
-            assertEquals("value 2a value 2b", _val[2]);
+            assertEquals("value 2a", _val[2]);
             assertEquals("Header3", _hdr[3]);
-            assertEquals(null, _val[3]);
+            assertEquals("3", _val[3]);
             assertEquals("Header4", _hdr[4]);
             assertEquals("value4", _val[4]);
             assertEquals("Server5", _hdr[5]);
@@ -597,7 +685,7 @@
                         + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012"
                         + "0\015\012"
                         + "\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -616,7 +704,7 @@
     @Test
     public void testStartEOF() throws Exception
     {
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.atEOF();
         parser.parseNext(BufferUtil.EMPTY_BUFFER);
@@ -633,7 +721,7 @@
                         + "Content-Length: 20\015\012"
                         + "\015\012"
                         + "0123456789");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.atEOF();
         parseAll(parser,buffer);
@@ -656,7 +744,7 @@
                         + "\015\012"
                         + "a;\015\012"
                         + "0123456789\015\012");
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.atEOF();
         parseAll(parser,buffer);
@@ -704,7 +792,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("GET", _methodOrVersion);
@@ -772,7 +860,7 @@
                         + "0123456789\015\012");
 
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer0);
         parser.atEOF();
@@ -818,7 +906,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -837,7 +925,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -861,7 +949,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -894,7 +982,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -915,7 +1003,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -935,7 +1023,7 @@
                         + "\015\012"
                         + "0123456789\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.atEOF();
         parser.parseNext(buffer);
@@ -957,7 +1045,7 @@
                         + "Content-Length: 10\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -976,7 +1064,7 @@
                         + "Transfer-Encoding: chunked\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("HTTP/1.1", _methodOrVersion);
@@ -999,7 +1087,7 @@
                         + "HTTP/1.1 400 OK\015\012");  // extra data causes close ??
 
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
@@ -1009,11 +1097,15 @@
         assertEquals(null,_content);
         assertTrue(_headerCompleted);
         assertTrue(_messageCompleted);
-
+        
+        parser.close();
         parser.reset();
         parser.parseNext(buffer);
         assertFalse(buffer.hasRemaining());
-        assertTrue(parser.isClosed());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
+        assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
     
     
@@ -1027,13 +1119,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("No URI",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1047,13 +1142,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("No URI",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1066,14 +1164,18 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("Unknown Version",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
+        
     }
 
     @Test
@@ -1085,13 +1187,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.ResponseHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("No Status",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1104,13 +1209,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.ResponseHandler<ByteBuffer> handler = new Handler();
+        HttpParser.ResponseHandler handler = new Handler();
         HttpParser parser= new HttpParser(handler);
         
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("No Status",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1123,14 +1231,17 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
+        HttpParser.RequestHandler handler = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals(null,_methodOrVersion);
         assertEquals("Unknown Version",_bad);
         assertFalse(buffer.hasRemaining());
-        assertEquals(HttpParser.State.CLOSED,parser.getState()); 
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
+        assertEquals(HttpParser.State.CLOSED,parser.getState());
         
         buffer= BufferUtil.toBuffer(
             "GET / HTTP/1.01\015\012"
@@ -1145,6 +1256,9 @@
         assertEquals(null,_methodOrVersion);
         assertEquals("Unknown Version",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
     
@@ -1157,12 +1271,15 @@
                         + "Connection: close\r"
                         + "\r");
 
-        HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
+        HttpParser.RequestHandler handler = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals("Bad EOL",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
 
 
@@ -1178,6 +1295,9 @@
         parser.parseNext(buffer);
         assertEquals("Bad EOL",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
     
@@ -1193,13 +1313,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals("GET",_methodOrVersion);
         assertEquals("Bad Content-Length",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1212,13 +1335,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals("GET",_methodOrVersion);
         assertEquals("Bad Content-Length",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
 
@@ -1231,13 +1357,16 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
 
         parser.parseNext(buffer);
         assertEquals("GET",_methodOrVersion);
         assertEquals("Bad Content-Length",_bad);
         assertFalse(buffer.hasRemaining());
+        assertEquals(HttpParser.State.CLOSE,parser.getState());
+        parser.atEOF();
+        parser.parseNext(BufferUtil.EMPTY_BUFFER);
         assertEquals(HttpParser.State.CLOSED,parser.getState());
     }
     
@@ -1250,7 +1379,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("host",_host);
@@ -1265,7 +1394,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("No Host",_bad);
@@ -1280,7 +1409,7 @@
                 "GET http://host/ HTTP/1.0\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         Assert.assertNull(_bad);
@@ -1296,7 +1425,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("No Host",_bad);
@@ -1311,7 +1440,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("192.168.0.1",_host);
@@ -1327,7 +1456,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("[::1]",_host);
@@ -1343,10 +1472,10 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
-        assertEquals("Bad IPv6 Host header",_bad);
+        Assert.assertThat(_bad,Matchers.containsString("Bad"));
     }
     
     @Test
@@ -1358,7 +1487,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("myhost",_host);
@@ -1370,14 +1499,14 @@
     {
         ByteBuffer buffer= BufferUtil.toBuffer(
                 "GET / HTTP/1.1\015\012"
-                        + "Host: myhost:xxx\015\012"
+                        + "Host: myhost:testBadPort\015\012"
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
-        assertEquals("Bad Host header",_bad);
+        Assert.assertThat(_bad,Matchers.containsString("Bad Host"));
     }
 
     @Test
@@ -1389,7 +1518,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("192.168.0.1",_host);
@@ -1405,7 +1534,7 @@
                         + "Connection: close\015\012"
                         + "\015\012");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
         assertEquals("[::1]",_host);
@@ -1420,7 +1549,7 @@
             "Host: www.smh.com.au\r\n"+
             "\r\n");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
         assertEquals("www.smh.com.au",parser.getFieldCache().get("Host: www.smh.com.au").getValue());
@@ -1435,63 +1564,6 @@
     }
 
     @Test
-    public void testProxyProtocol() throws Exception
-    {
-        ByteBuffer buffer=BufferUtil
-            .toBuffer("PROXY TCP4 107.47.45.254 10.0.1.116 27689 80\015\012"
-                +"GET / HTTP/1.1\015\012"
-                +"Host: localhost \015\012"
-                +"Connection: close\015\012"+"\015\012"+"\015\012");
-
-        Handler handler=new Handler();
-        HttpParser parser=new HttpParser((HttpParser.RequestHandler)handler);
-        parseAll(parser, buffer);
-
-        assertTrue(_headerCompleted);
-        assertTrue(_messageCompleted);
-        assertEquals("GET", _methodOrVersion);
-        assertEquals("/", _uriOrStatus);
-        assertEquals("HTTP/1.1", _versionOrReason);
-        assertEquals("PROXY TCP4 107.47.45.254 10.0.1.116 27689 80", handler._proxy);
-        assertEquals("Host", _hdr[0]);
-        assertEquals("localhost", _val[0]);
-        assertEquals("Connection", _hdr[1]);
-        assertEquals("close", _val[1]);
-        assertEquals(1, _headers);
-    }
-
-    @Test
-    public void testSplitProxyHeaderParseTest() throws Exception
-    {
-        Handler handler=new Handler();
-        HttpParser parser=new HttpParser((HttpParser.RequestHandler)handler);
-
-        ByteBuffer buffer=BufferUtil.toBuffer("PROXY TCP4 207.47.45.254 10.0.1.116 27689 80\015\012");
-        parser.parseNext(buffer);
-
-        buffer=BufferUtil.toBuffer(
-            "GET / HTTP/1.1\015\012"
-                +"Host: localhost \015\012"
-                +"Connection: close\015\012"
-                +"\015\012"
-                +"\015\012");
-
-        parser.parseNext(buffer);
-        assertTrue(_headerCompleted);
-        assertTrue(_messageCompleted);
-        assertEquals("GET", _methodOrVersion);
-        assertEquals("/", _uriOrStatus);
-        assertEquals("HTTP/1.1", _versionOrReason);
-        assertEquals("PROXY TCP4 207.47.45.254 10.0.1.116 27689 80", handler._proxy);
-        assertEquals("Host", _hdr[0]);
-        assertEquals("localhost", _val[0]);
-        assertEquals("Connection", _hdr[1]);
-        assertEquals("close", _val[1]);
-        assertEquals(1, _headers);
-    }
-    
-
-    @Test
     public void testFolded() throws Exception
     {
         ByteBuffer buffer= BufferUtil.toBuffer(
@@ -1502,22 +1574,12 @@
                 "\taction=\"xxx\" \015\012" +
                 "\015\012");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
-        assertTrue(_headerCompleted);
-        assertTrue(_messageCompleted);
-        assertEquals("GET", _methodOrVersion);
-        assertEquals("/", _uriOrStatus);
-        assertEquals("HTTP/1.0", _versionOrReason);
-        assertEquals("Host", _hdr[0]);
-        assertEquals("localhost", _val[0]);
-        assertEquals("Connection", _hdr[1]);
-        assertEquals("close", _val[1]);
-        assertEquals("Content-Type", _hdr[2]);
-        assertEquals("application/soap+xml; charset=utf-8; action=\"xxx\"", _val[2]);
-        assertEquals(2, _headers);
+        assertFalse(_headerCompleted);
+        assertEquals(_bad, "Bad Continuation");
     }
 
     
@@ -1533,7 +1595,7 @@
                 "Accept: unknown\r\n" + 
                 "\r\n");
 
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parser.parseNext(buffer);
 
@@ -1560,7 +1622,7 @@
                 "SM\015\012"+
                 "\015\012");
         
-        HttpParser.RequestHandler<ByteBuffer> handler  = new Handler();
+        HttpParser.RequestHandler handler  = new Handler();
         HttpParser parser= new HttpParser(handler);
         parseAll(parser,buffer);
 
@@ -1605,7 +1667,7 @@
     private boolean _headerCompleted;
     private boolean _messageCompleted;
 
-    private class Handler implements HttpParser.RequestHandler<ByteBuffer>, HttpParser.ResponseHandler<ByteBuffer>, HttpParser.ProxyHandler
+    private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler
     {
         private HttpFields fields;
         String _proxy;
@@ -1623,14 +1685,14 @@
         }
 
         @Override
-        public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
+        public boolean startRequest(String method, String uri, HttpVersion version)
         {
             _fields.clear();
             _headers= -1;
             _hdr= new String[10];
             _val= new String[10];
             _methodOrVersion= method;
-            _uriOrStatus= BufferUtil.toUTF8String(uri);
+            _uriOrStatus= uri.toString();
             _versionOrReason= version==null?null:version.asString();
 
             fields=new HttpFields();
@@ -1641,21 +1703,19 @@
         }
 
         @Override
-        public boolean parsedHeader(HttpField field)
+        public void parsedHeader(HttpField field)
         {
             _fields.add(field);
             //System.err.println("header "+name+": "+value);
             _hdr[++_headers]= field.getName();
             _val[_headers]= field.getValue();
-            return false;
-        }
-
-        @Override
-        public boolean parsedHostHeader(String host,int port)
-        {
-            _host=host;
-            _port=port;
-            return false;
+            
+            if (field instanceof HostPortHttpField)
+            {
+                HostPortHttpField hpfield = (HostPortHttpField)field;
+                _host=hpfield.getHost();
+                _port=hpfield.getPort();
+            }
         }
 
         @Override
@@ -1716,11 +1776,5 @@
         {
             return 512;
         }
-
-        @Override
-        public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort)
-        {
-            _proxy="PROXY "+protocol+" "+sAddr+" "+dAddr+" "+sPort+" "+dPort;
-        }
     }
 }
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
new file mode 100644
index 0000000..becf1c9
--- /dev/null
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
@@ -0,0 +1,358 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.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
+    {
+        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 void parsedHeader(HttpField field)
+        {
+            put(field.getName(),field.getValue());
+        }
+
+        @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();
+                MetaData 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 MetaData.Request
+                        ?generator.generateRequest((MetaData.Request)info,header,chunk,content,true)
+                        :generator.generateResponse((MetaData.Response)info,false,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 MetaData getInfo();
+
+        @Override
+        public int getHeaderCacheSize()
+        {
+            return 0;
+        }
+
+    }
+
+    public static class Request extends Message implements HttpParser.RequestHandler
+    {
+        private String _method;
+        private String _uri;
+
+        @Override
+        public boolean startRequest(String method, String uri, HttpVersion version)
+        {
+            _method=method;
+            _uri=uri.toString();
+            _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 MetaData.Request getInfo()
+        {
+            return new MetaData.Request(_method,new HttpURI(_uri),_version,this,_content==null?0:_content.size());
+        }
+
+        @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);
+        }
+    }
+
+    public static class Response extends Message implements HttpParser.ResponseHandler
+    {
+        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 MetaData.Response getInfo()
+        {
+            return new MetaData.Response(_version,_status,_reason,this,_content==null?-1:_content.size());
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s %s %s\n%s\n",_version,_status,_reason,super.toString());
+        }
+    }
+}
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java
new file mode 100644
index 0000000..d67a3b7
--- /dev/null
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURIParseTest.java
@@ -0,0 +1,282 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.http;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jetty.util.URIUtil;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+
+@RunWith(Parameterized.class)
+public class HttpURIParseTest
+{
+    @Parameters(name="{0}")
+    public static List<String[]> data()
+    {
+        String[][] tests = {
+
+        // Nothing but path 
+        {"path",null,null,"-1","path",null,null,null},
+        {"path/path",null,null,"-1","path/path",null,null,null},
+        {"%65ncoded/path",null,null,"-1","%65ncoded/path",null,null,null},
+                
+        // Basic path reference     
+        {"/path/to/context",null,null,"-1","/path/to/context",null,null,null},
+        
+        // Basic with encoded query 
+        {"http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context;param","param","query=%22value%22","fragment"},
+        {"http://[::1]/path/to/context;param?query=%22value%22#fragment","http","[::1]","-1","/path/to/context;param","param","query=%22value%22","fragment"},
+        
+        // Basic with parameters and query
+        {"http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context;param","param","query=%22value%22","fragment"},
+        {"http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","[::1]","8080","/path/to/context;param","param","query=%22value%22","fragment"},
+        
+        // Path References
+        {"/path/info",null,null,null,"/path/info",null,null,null},
+        {"/path/info#fragment",null,null,null,"/path/info",null,null,"fragment"},
+        {"/path/info?query",null,null,null,"/path/info",null,"query",null},
+        {"/path/info?query#fragment",null,null,null,"/path/info",null,"query","fragment"},
+        {"/path/info;param",null,null,null,"/path/info;param","param",null,null},
+        {"/path/info;param#fragment",null,null,null,"/path/info;param","param",null,"fragment"},
+        {"/path/info;param?query",null,null,null,"/path/info;param","param","query",null},
+        {"/path/info;param?query#fragment",null,null,null,"/path/info;param","param","query","fragment"},
+        
+        // Protocol Less (aka scheme-less) URIs
+        {"//host/path/info",null,"host",null,"/path/info",null,null,null},
+        {"//user@host/path/info",null,"host",null,"/path/info",null,null,null},
+        {"//user@host:8080/path/info",null,"host","8080","/path/info",null,null,null},
+        {"//host:8080/path/info",null,"host","8080","/path/info",null,null,null},
+        
+        // Host Less 
+        {"http:/path/info","http",null,null,"/path/info",null,null,null},
+        {"http:/path/info#fragment","http",null,null,"/path/info",null,null,"fragment"},
+        {"http:/path/info?query","http",null,null,"/path/info",null,"query",null},
+        {"http:/path/info?query#fragment","http",null,null,"/path/info",null,"query","fragment"},
+        {"http:/path/info;param","http",null,null,"/path/info;param","param",null,null},
+        {"http:/path/info;param#fragment","http",null,null,"/path/info;param","param",null,"fragment"},
+        {"http:/path/info;param?query","http",null,null,"/path/info;param","param","query",null},
+        {"http:/path/info;param?query#fragment","http",null,null,"/path/info;param","param","query","fragment"},
+        
+        // Everything and the kitchen sink
+        {"http://user@host:8080/path/info;param?query#fragment","http","host","8080","/path/info;param","param","query","fragment"},
+        {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","host","8080","/path/info;param","param","query","fragment"},
+        
+        // No host, parameter with no content
+        {"http:///;?#","http",null,null,"/;","","",""},
+        
+        // Path with query that has no value
+        {"/path/info?a=?query",null,null,null,"/path/info",null,"a=?query",null},
+        
+        // Path with query alt syntax
+        {"/path/info?a=;query",null,null,null,"/path/info",null,"a=;query",null},
+
+        // URI with host character
+        {"/@path/info",null,null,null,"/@path/info",null,null,null},
+        {"/user@path/info",null,null,null,"/user@path/info",null,null,null},
+        {"//user@host/info",null,"host",null,"/info",null,null,null},
+        {"//@host/info",null,"host",null,"/info",null,null,null},
+        {"@host/info",null,null,null,"@host/info",null,null,null},
+        
+        // Scheme-less, with host and port (overlapping with path)
+        {"//host:8080//",null,"host","8080","//",null,null,null},
+        
+        // File reference
+        {"file:///path/info","file",null,null,"/path/info",null,null,null},
+        {"file:/path/info","file",null,null,"/path/info",null,null,null},
+        
+        // Bad URI (no scheme, no host, no path) 
+        {"//",null,null,null,null,null,null,null},
+        
+        // Simple localhost references
+        {"http://localhost/","http","localhost",null,"/",null,null,null},
+        {"http://localhost:8080/", "http", "localhost","8080","/", null, null,null},
+        {"http://localhost/?x=y", "http", "localhost",null,"/", null,"x=y",null},
+        
+        // Simple path with parameter 
+        {"/;param",null, null,null,"/;param", "param",null,null},
+        {";param",null, null,null,";param", "param",null,null},
+        
+        // Simple path with query
+        {"/?x=y",null, null,null,"/", null,"x=y",null},
+        {"/?abc=test",null, null,null,"/", null,"abc=test",null},
+        
+        // Simple path with fragment
+        {"/#fragment",null, null,null,"/", null,null,"fragment"},
+        
+        // Simple IPv4 host with port (default path)
+        {"http://192.0.0.1:8080/","http","192.0.0.1","8080","/",null,null,null},
+        
+        // Simple IPv6 host with port (default path)
+        
+        {"http://[2001:db8::1]:8080/","http","[2001:db8::1]","8080","/",null,null,null},
+        // IPv6 authenticated host with port (default path)
+        
+        {"http://user@[2001:db8::1]:8080/","http","[2001:db8::1]","8080","/",null,null,null},
+        
+        // Simple IPv6 host no port (default path)
+        {"http://[2001:db8::1]/","http","[2001:db8::1]",null,"/",null,null,null},
+        
+        // Scheme-less IPv6, host with port (default path)
+        {"//[2001:db8::1]:8080/",null,"[2001:db8::1]","8080","/",null,null,null},
+        
+        // Interpreted as relative path of "*" (no host/port/scheme/query/fragment)
+        {"*",null,null,null,"*",null, null,null},
+
+        // Path detection Tests (seen from JSP/JSTL and <c:url> use
+        {"http://host:8080/path/info?q1=v1&q2=v2","http","host","8080","/path/info",null,"q1=v1&q2=v2",null},
+        {"/path/info?q1=v1&q2=v2",null,null,null,"/path/info",null,"q1=v1&q2=v2",null},
+        {"/info?q1=v1&q2=v2",null,null,null,"/info",null,"q1=v1&q2=v2",null},
+        {"info?q1=v1&q2=v2",null,null,null,"info",null,"q1=v1&q2=v2",null},
+        {"info;q1=v1?q2=v2",null,null,null,"info;q1=v1","q1=v1","q2=v2",null},
+        
+        // Path-less, query only (seen from JSP/JSTL and <c:url> use
+        {"?q1=v1&q2=v2",null,null,null,"",null,"q1=v1&q2=v2",null}
+        };
+        
+        return Arrays.asList(tests);
+    }
+    
+    @Parameter(0)
+    public String input;
+
+    @Parameter(1)
+    public String scheme;
+    
+    @Parameter(2)
+    public String host;
+    
+    @Parameter(3)
+    public String port;
+
+    @Parameter(4)
+    public String path;
+    
+    @Parameter(5)
+    public String param;
+    
+    @Parameter(6)
+    public String query;
+    
+    @Parameter(7)
+    public String fragment;
+    
+    @Test
+    public void testParseString() throws Exception
+    {
+        HttpURI httpUri = new HttpURI(input);
+        
+        try
+        {
+            new URI(input);
+            // URI is valid (per java.net.URI parsing)
+            
+            // Test case sanity check
+            assertThat("[" + input + "] expected path (test case) cannot be null",path,notNullValue());
+
+            // Assert expectations
+            assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(scheme));
+            assertThat("[" + input + "] .host",httpUri.getHost(),is(host));
+            assertThat("[" + input + "] .port",httpUri.getPort(),is(port == null ? -1 : Integer.parseInt(port)));
+            assertThat("[" + input + "] .path",httpUri.getPath(),is(path));
+            assertThat("[" + input + "] .param",httpUri.getParam(),is(param));
+            assertThat("[" + input + "] .query",httpUri.getQuery(),is(query));
+            assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(fragment));
+            assertThat("[" + input + "] .toString",httpUri.toString(),is(input));
+        }
+        catch (URISyntaxException e)
+        {
+            // Assert HttpURI values for invalid URI (such as "//")
+            assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(nullValue()));
+            assertThat("[" + input + "] .host",httpUri.getHost(),is(nullValue()));
+            assertThat("[" + input + "] .port",httpUri.getPort(),is(-1));
+            assertThat("[" + input + "] .path",httpUri.getPath(),is(nullValue()));
+            assertThat("[" + input + "] .param",httpUri.getParam(),is(nullValue()));
+            assertThat("[" + input + "] .query",httpUri.getQuery(),is(nullValue()));
+            assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(nullValue()));
+        }
+    }
+    
+    @Test
+    public void testParseURI() throws Exception
+    {
+        URI javaUri = null;
+        try
+        {
+            javaUri = new URI(input);
+            assumeNotNull(javaUri);
+        }
+        catch (URISyntaxException e)
+        {
+            // Ignore, as URI is invalid anyway
+            assumeNoException(e);
+        }
+        
+        HttpURI httpUri = new HttpURI(javaUri);
+
+        assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(scheme));
+        assertThat("[" + input + "] .host",httpUri.getHost(),is(host));
+        assertThat("[" + input + "] .port",httpUri.getPort(),is(port == null ? -1 : Integer.parseInt(port)));
+        assertThat("[" + input + "] .path",httpUri.getPath(),is(path));
+        assertThat("[" + input + "] .param",httpUri.getParam(),is(param));
+        assertThat("[" + input + "] .query",httpUri.getQuery(),is(query));
+        assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(fragment));
+        
+        assertThat("[" + input + "] .toString",httpUri.toString(),is(input));
+    }
+    
+    @Test
+    public void testCompareToJavaNetURI() throws Exception
+    {
+        URI javaUri = null;
+        try
+        {
+            javaUri = new URI(input);
+            assumeNotNull(javaUri);
+        }
+        catch (URISyntaxException e)
+        {
+            // Ignore, as URI is invalid anyway
+            assumeNoException(e);
+        }
+        
+        HttpURI httpUri = new HttpURI(javaUri);
+        
+        assertThat("[" + input + "] .scheme",httpUri.getScheme(),is(javaUri.getScheme()));
+        assertThat("[" + input + "] .host",httpUri.getHost(),is(javaUri.getHost()));
+        assertThat("[" + input + "] .port",httpUri.getPort(),is(javaUri.getPort()));
+        assertThat("[" + input + "] .path",httpUri.getPath(),is(javaUri.getRawPath()));
+        // Not Relevant for java.net.URI -- assertThat("["+input+"] .param", httpUri.getParam(), is(param));
+        assertThat("[" + input + "] .query",httpUri.getQuery(),is(javaUri.getRawQuery()));
+        assertThat("[" + input + "] .fragment",httpUri.getFragment(),is(javaUri.getFragment()));
+        assertThat("[" + input + "] .toString",httpUri.toString(),is(javaUri.toASCIIString()));
+    }
+}
\ No newline at end of file
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
index 2a76579..d308cde 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
@@ -19,61 +19,178 @@
 
 package org.eclipse.jetty.http;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
 
-import java.net.URI;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 
+import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.Utf8Appendable;
+import org.junit.Assert;
 import org.junit.Test;
 
-
-/* ------------------------------------------------------------ */
 public class HttpURITest
 {
-    String[][] tests=
-    {
-        {"/path/to/context",null,null,"-1","/path/to/context",null,null,null},
-        {"http://example.com/path/to/context;param?query=%22value%22#fragment","http","example.com","-1","/path/to/context","param","query=%22value%22","fragment"},
-        {"http://[::1]/path/to/context;param?query=%22value%22#fragment","http","[::1]","-1","/path/to/context","param","query=%22value%22","fragment"},
-        {"http://example.com:8080/path/to/context;param?query=%22value%22#fragment","http","example.com","8080","/path/to/context","param","query=%22value%22","fragment"},
-        {"http://[::1]:8080/path/to/context;param?query=%22value%22#fragment","http","[::1]","8080","/path/to/context","param","query=%22value%22","fragment"},
-    };
-    
-    public static int
-    INPUT=0,SCHEME=1,HOST=2,PORT=3,PATH=4,PARAM=5,QUERY=6,FRAGMENT=7;
-
-    /* ------------------------------------------------------------ */
     @Test
-    public void testFromString() throws Exception
+    public void testInvalidAddress() throws Exception
     {
-        for (String[] test:tests)
-        {
-            HttpURI uri = new HttpURI(test[INPUT]);
+        assertInvalidURI("http://[ffff::1:8080/", "Invalid URL; no closing ']' -- should throw exception");
+        assertInvalidURI("**", "only '*', not '**'");
+        assertInvalidURI("*/", "only '*', not '*/'");
+    }
 
-            assertEquals(test[SCHEME], uri.getScheme());
-            assertEquals(test[HOST], uri.getHost());
-            assertEquals(Integer.parseInt(test[PORT]), uri.getPort());
-            assertEquals(test[PATH], uri.getPath());
-            assertEquals(test[PARAM], uri.getParam());
-            assertEquals(test[QUERY], uri.getQuery());
-            assertEquals(test[FRAGMENT], uri.getFragment());
+    private void assertInvalidURI(String invalidURI, String message)
+    {
+        HttpURI uri = new HttpURI();
+        try
+        {
+            uri.parse(invalidURI);
+            fail(message);
+        }
+        catch (IllegalArgumentException e)
+        {
+            assertTrue(true);
         }
     }
 
-    /* ------------------------------------------------------------ */
     @Test
-    public void testFromURI() throws Exception
+    public void testUnicodeErrors() throws UnsupportedEncodingException
     {
-        for (String[] test:tests)
+        String uri="http://server/path?invalid=data%uXXXXhere%u000";
+        try
         {
-            HttpURI uri = new HttpURI(new URI(test[INPUT]));
-
-            assertEquals(test[SCHEME], uri.getScheme());
-            assertEquals(test[HOST], uri.getHost());
-            assertEquals(Integer.parseInt(test[PORT]), uri.getPort());
-            assertEquals(test[PATH], uri.getPath());
-            assertEquals(test[PARAM], uri.getParam());
-            assertEquals(test[QUERY], uri.getQuery());
-            assertEquals(test[FRAGMENT], uri.getFragment());
+            URLDecoder.decode(uri,"UTF-8");
+            Assert.assertTrue(false);
         }
+        catch (IllegalArgumentException e)
+        {
+        }
+
+        HttpURI huri=new HttpURI(uri);
+        MultiMap<String> params = new MultiMap<>();
+        huri.decodeQueryTo(params);
+        assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
+
+        huri=new HttpURI(uri);
+        params = new MultiMap<>();
+        huri.decodeQueryTo(params,StandardCharsets.UTF_8);
+        assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
+
+    }
+
+    @Test
+    public void testExtB() throws Exception
+    {
+        for (String value: new String[]{"a","abcdABCD","\u00C0","\u697C","\uD869\uDED5","\uD840\uDC08"} )
+        {
+            HttpURI uri = new HttpURI("/path?value="+URLEncoder.encode(value,"UTF-8"));
+
+            MultiMap<String> parameters = new MultiMap<>();
+            uri.decodeQueryTo(parameters,StandardCharsets.UTF_8);
+            assertEquals(value,parameters.getString("value"));
+        }
+    }
+
+    @Test
+    public void testAt() throws Exception
+    {
+        HttpURI uri = new HttpURI("/@foo/bar");
+        assertEquals("/@foo/bar",uri.getPath());
+    }
+
+    @Test
+    public void testParams() throws Exception
+    {
+        HttpURI uri = new HttpURI("/foo/bar");
+        assertEquals("/foo/bar",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        assertEquals(null,uri.getParam());
+        
+        uri = new HttpURI("/foo/bar;jsessionid=12345");
+        assertEquals("/foo/bar;jsessionid=12345",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        assertEquals("jsessionid=12345",uri.getParam());
+        
+        uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345");
+        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        assertEquals("jsessionid=12345",uri.getParam());
+        
+        uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345?name=value");
+        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        assertEquals("jsessionid=12345",uri.getParam());
+        
+        uri = new HttpURI("/foo;abc=123/bar;jsessionid=12345#target");
+        assertEquals("/foo;abc=123/bar;jsessionid=12345",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        assertEquals("jsessionid=12345",uri.getParam());
+    }
+    
+    @Test
+    public void testMutableURI()
+    {
+        HttpURI uri = new HttpURI("/foo/bar");
+        assertEquals("/foo/bar",uri.toString());
+        assertEquals("/foo/bar",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+
+        uri.setScheme("http");
+        assertEquals("http:/foo/bar",uri.toString());
+        assertEquals("/foo/bar",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+
+        uri.setAuthority("host",0);
+        assertEquals("http://host/foo/bar",uri.toString());
+        assertEquals("/foo/bar",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+
+        uri.setAuthority("host",8888);
+        assertEquals("http://host:8888/foo/bar",uri.toString());
+        assertEquals("/foo/bar",uri.getPath());
+        assertEquals("/foo/bar",uri.getDecodedPath());
+        
+        uri.setPathQuery("/f%30%30;p0/bar;p1;p2");
+        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2",uri.toString());
+        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
+        assertEquals("/f00/bar",uri.getDecodedPath());
+        assertEquals("p2",uri.getParam());
+        assertEquals(null,uri.getQuery());
+        
+        uri.setPathQuery("/f%30%30;p0/bar;p1;p2?name=value");
+        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?name=value",uri.toString());
+        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
+        assertEquals("/f00/bar",uri.getDecodedPath());
+        assertEquals("p2",uri.getParam());
+        assertEquals("name=value",uri.getQuery());
+        
+        uri.setQuery("other=123456");
+        assertEquals("http://host:8888/f%30%30;p0/bar;p1;p2?other=123456",uri.toString());
+        assertEquals("/f%30%30;p0/bar;p1;p2",uri.getPath());
+        assertEquals("/f00/bar",uri.getDecodedPath());
+        assertEquals("p2",uri.getParam());
+        assertEquals("other=123456",uri.getQuery());
+    }
+
+    @Test
+    public void testSchemeAndOrAuthority() throws Exception
+    {
+        HttpURI uri = new HttpURI("/path/info");
+        assertEquals("/path/info",uri.toString());
+        
+        uri.setAuthority("host",0);
+        assertEquals("//host/path/info",uri.toString());
+        
+        uri.setAuthority("host",8888);
+        assertEquals("//host:8888/path/info",uri.toString());
+        
+        uri.setScheme("http");
+        assertEquals("http://host:8888/path/info",uri.toString());
+        
+        uri.setAuthority(null,0);
+        assertEquals("http:/path/info",uri.toString());
+        
     }
 }
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
index 2e5bd65..a45260f 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java
@@ -90,9 +90,9 @@
         assertEquals("abc",MimeTypes.getCharsetFromContentType("foo/bar other = param ; charset = abc"));
         assertEquals("abc",MimeTypes.getCharsetFromContentType("foo/bar other = param ; charset = \"abc\" ; some=else"));
         assertEquals(null,MimeTypes.getCharsetFromContentType("foo/bar"));
-        assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("foo/bar;charset=uTf8"));
-        assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("foo/bar;other=\"charset=abc\";charset=uTf8"));
-        assertEquals("UTF-8",MimeTypes.getCharsetFromContentType("text/html;charset=utf-8"));
+        assertEquals("utf-8",MimeTypes.getCharsetFromContentType("foo/bar;charset=uTf8"));
+        assertEquals("utf-8",MimeTypes.getCharsetFromContentType("foo/bar;other=\"charset=abc\";charset=uTf8"));
+        assertEquals("utf-8",MimeTypes.getCharsetFromContentType("text/html;charset=utf-8"));
 
     }
 
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
index d2e96d7..c14b5f0 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -146,6 +145,7 @@
 
     /**
      * See JIRA issue: JETTY-88.
+     * @throws Exception failed test
      */
     @Test
     public void testPathMappingsOnlyMatchOnDirectoryNames() throws Exception
diff --git a/jetty-http2/http2-alpn-tests/pom.xml b/jetty-http2/http2-alpn-tests/pom.xml
new file mode 100644
index 0000000..4084bb1
--- /dev/null
+++ b/jetty-http2/http2-alpn-tests/pom.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.eclipse.jetty.http2</groupId>
+        <artifactId>http2-parent</artifactId>
+        <version>9.3.7-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>http2-alpn-tests</artifactId>
+    <name>Jetty :: HTTP2 :: ALPN Tests</name>
+
+    <properties>
+        <bundle-symbolic-name>${project.groupId}.alpn.tests</bundle-symbolic-name>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.mortbay.jetty.alpn</groupId>
+                                    <artifactId>alpn-boot</artifactId>
+                                    <version>${alpn.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                    <outputDirectory>${project.build.directory}/alpn</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty.alpn</groupId>
+            <artifactId>alpn-api</artifactId>
+            <version>${alpn.api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-test-helper</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    
+</project>
diff --git a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java
new file mode 100644
index 0000000..baac1bf
--- /dev/null
+++ b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/ALPNNegotiationTest.java
@@ -0,0 +1,312 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.alpn.tests;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSocket;
+
+import org.eclipse.jetty.alpn.ALPN;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ALPNNegotiationTest extends AbstractALPNTest
+{
+    @Test
+    public void testGentleCloseDuringHandshake() throws Exception
+    {
+        InetSocketAddress address = prepare();
+        SslContextFactory sslContextFactory = newSslContextFactory();
+        sslContextFactory.start();
+        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
+        sslEngine.setUseClientMode(true);
+        ALPN.put(sslEngine, new ALPN.ClientProvider()
+        {
+            @Override
+            public void unsupported()
+            {
+            }
+
+            @Override
+            public List<String> protocols()
+            {
+                return Arrays.asList("h2");
+            }
+
+            @Override
+            public void selected(String protocol)
+            {
+            }
+        });
+        sslEngine.beginHandshake();
+
+        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
+        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
+        encrypted.flip();
+
+        try (SocketChannel channel = SocketChannel.open(address))
+        {
+            // Send ClientHello, immediately followed by TLS Close Alert and then by FIN
+            channel.write(encrypted);
+            sslEngine.closeOutbound();
+            encrypted.clear();
+            sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
+            encrypted.flip();
+            channel.write(encrypted);
+            channel.shutdownOutput();
+
+            // Read ServerHello from server
+            encrypted.clear();
+            int read = channel.read(encrypted);
+            encrypted.flip();
+            Assert.assertTrue(read > 0);
+            // Cannot decrypt, as the SSLEngine has been already closed
+
+            // Now if we read more, we should either read the TLS Close Alert, or directly -1
+            encrypted.clear();
+            read = channel.read(encrypted);
+            // Sending a TLS Close Alert during handshake results in an exception when
+            // unwrapping that the server react to by closing the connection abruptly.
+            Assert.assertTrue(read < 0);
+        }
+    }
+
+    @Test
+    public void testAbruptCloseDuringHandshake() throws Exception
+    {
+        InetSocketAddress address = prepare();
+        SslContextFactory sslContextFactory = newSslContextFactory();
+        sslContextFactory.start();
+        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
+        sslEngine.setUseClientMode(true);
+        ALPN.put(sslEngine, new ALPN.ClientProvider()
+        {
+            @Override
+            public void unsupported()
+            {
+            }
+
+            @Override
+            public List<String> protocols()
+            {
+                return Arrays.asList("h2");
+            }
+
+            @Override
+            public void selected(String s)
+            {
+            }
+        });
+        sslEngine.beginHandshake();
+
+        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
+        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
+        encrypted.flip();
+
+        try (SocketChannel channel = SocketChannel.open(address))
+        {
+            // Send ClientHello, immediately followed by FIN (no TLS Close Alert)
+            channel.write(encrypted);
+            channel.shutdownOutput();
+
+            // Read ServerHello from server
+            encrypted.clear();
+            int read = channel.read(encrypted);
+            encrypted.flip();
+            Assert.assertTrue(read > 0);
+            ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
+            sslEngine.unwrap(encrypted, decrypted);
+
+            // Now if we read more, we should either read the TLS Close Alert, or directly -1
+            encrypted.clear();
+            read = channel.read(encrypted);
+            // Since we have close the connection abruptly, the server also does so
+            Assert.assertTrue(read < 0);
+        }
+    }
+
+    @Test
+    public void testClientAdvertisingHTTPServerSpeaksHTTP() throws Exception
+    {
+        InetSocketAddress address = prepare();
+
+        SslContextFactory sslContextFactory = newSslContextFactory();
+        sslContextFactory.start();
+        SSLContext sslContext = sslContextFactory.getSslContext();
+
+        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
+        {
+            client.setUseClientMode(true);
+            client.setSoTimeout(5000);
+
+            ALPN.put(client, new ALPN.ClientProvider()
+            {
+                @Override
+                public void unsupported()
+                {
+                }
+
+                @Override
+                public List<String> protocols()
+                {
+                    return Arrays.asList("http/1.1");
+                }
+
+                @Override
+                public void selected(String protocol)
+                {
+                    Assert.assertEquals("http/1.1", protocol);
+                }
+            });
+
+            client.startHandshake();
+
+            // Verify that the server really speaks http/1.1
+
+            OutputStream output = client.getOutputStream();
+            output.write(("" +
+                    "GET / HTTP/1.1\r\n" +
+                    "Host: localhost:" + address.getPort() + "\r\n" +
+                    "\r\n" +
+                    "").getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            InputStream input = client.getInputStream();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
+            String line = reader.readLine();
+            Assert.assertTrue(line.contains(" 404 "));
+        }
+    }
+
+    @Test
+    public void testClientAdvertisingMultipleProtocolsServerSpeaksHTTPWhenNegotiated() throws Exception
+    {
+        InetSocketAddress address = prepare();
+
+        SslContextFactory sslContextFactory = newSslContextFactory();
+        sslContextFactory.start();
+        SSLContext sslContext = sslContextFactory.getSslContext();
+        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
+        {
+            client.setUseClientMode(true);
+            client.setSoTimeout(5000);
+
+            ALPN.put(client, new ALPN.ClientProvider()
+            {
+                @Override
+                public void unsupported()
+                {
+                }
+
+                @Override
+                public List<String> protocols()
+                {
+                    return Arrays.asList("unknown/1.0", "http/1.1");
+                }
+
+                @Override
+                public void selected(String protocol)
+                {
+                    Assert.assertEquals("http/1.1", protocol);
+                }
+            });
+
+            client.startHandshake();
+
+            // Verify that the server really speaks http/1.1
+
+            OutputStream output = client.getOutputStream();
+            output.write(("" +
+                    "GET / HTTP/1.1\r\n" +
+                    "Host: localhost:" + address.getPort() + "\r\n" +
+                    "\r\n" +
+                    "").getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            InputStream input = client.getInputStream();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
+            String line = reader.readLine();
+            Assert.assertTrue(line.contains(" 404 "));
+        }
+    }
+
+    @Test
+    public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
+    {
+        InetSocketAddress address = prepare();
+
+        SslContextFactory sslContextFactory = newSslContextFactory();
+        sslContextFactory.start();
+        SSLContext sslContext = sslContextFactory.getSslContext();
+        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
+        {
+            client.setUseClientMode(true);
+            client.setSoTimeout(5000);
+
+            ALPN.put(client, new ALPN.ClientProvider()
+            {
+                @Override
+                public void unsupported()
+                {
+                }
+
+                @Override
+                public List<String> protocols()
+                {
+                    return null;
+                }
+
+                @Override
+                public void selected(String s)
+                {
+                }
+            });
+
+            client.startHandshake();
+
+            // Verify that the server really speaks http/1.1
+
+            OutputStream output = client.getOutputStream();
+            output.write(("" +
+                    "GET / HTTP/1.1\r\n" +
+                    "Host: localhost:" + address.getPort() + "\r\n" +
+                    "\r\n" +
+                    "").getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            InputStream input = client.getInputStream();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
+            String line = reader.readLine();
+            Assert.assertTrue(line.contains(" 404 "));
+        }
+    }
+}
diff --git a/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java
new file mode 100644
index 0000000..84db370
--- /dev/null
+++ b/jetty-http2/http2-alpn-tests/src/test/java/org/eclipse/jetty/http2/alpn/tests/AbstractALPNTest.java
@@ -0,0 +1,93 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.alpn.tests;
+
+import java.net.InetSocketAddress;
+
+import org.eclipse.jetty.alpn.ALPN;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.JDK;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+
+public class AbstractALPNTest
+{
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+    protected Server server;
+    protected ServerConnector connector;
+
+    @Before
+    public void before()
+    {
+        // The mandatory cipher needed to run HTTP/2
+        // over TLS is only available in JDK 8.
+        Assume.assumeTrue(JDK.IS_8);
+    }
+
+    protected InetSocketAddress prepare() throws Exception
+    {
+        server = new Server();
+        HttpConfiguration httpConfiguration = new HttpConfiguration();
+        HttpConnectionFactory h1 = new HttpConnectionFactory(httpConfiguration);
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpConfiguration);
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(h1.getProtocol());
+        
+        connector = new ServerConnector(server, newSslContextFactory(), alpn, h1, h2);
+        connector.setPort(0);
+        connector.setIdleTimeout(30000);
+        server.addConnector(connector);
+        server.start();
+
+        ALPN.debug = true;
+
+        return new InetSocketAddress("localhost", connector.getLocalPort());
+    }
+
+    protected SslContextFactory newSslContextFactory()
+    {
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
+        sslContextFactory.setTrustStorePassword("storepwd");
+        sslContextFactory.setIncludeProtocols("TLSv1.2");
+        // The mandatory HTTP/2 cipher.
+        sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+        return sslContextFactory;
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (server != null)
+            server.stop();
+    }
+}
diff --git a/jetty-http2/http2-alpn-tests/src/test/resources/jetty-logging.properties b/jetty-http2/http2-alpn-tests/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..29a0dfa
--- /dev/null
+++ b/jetty-http2/http2-alpn-tests/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.alpn.LEVEL=DEBUG
+org.eclipse.jetty.http2.LEVEL=DEBUG
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/keystore.jks b/jetty-http2/http2-alpn-tests/src/test/resources/keystore.jks
similarity index 100%
rename from jetty-spdy/spdy-alpn-tests/src/test/resources/keystore.jks
rename to jetty-http2/http2-alpn-tests/src/test/resources/keystore.jks
Binary files differ
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/truststore.jks b/jetty-http2/http2-alpn-tests/src/test/resources/truststore.jks
similarity index 100%
rename from jetty-spdy/spdy-alpn-tests/src/test/resources/truststore.jks
rename to jetty-http2/http2-alpn-tests/src/test/resources/truststore.jks
Binary files differ
diff --git a/jetty-http2/http2-client/pom.xml b/jetty-http2/http2-client/pom.xml
new file mode 100644
index 0000000..db91dd1
--- /dev/null
+++ b/jetty-http2/http2-client/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.http2</groupId>
+    <artifactId>http2-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>http2-client</artifactId>
+  <name>Jetty :: HTTP2 :: Client</name>
+
+ <properties>
+    <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
+  </properties>
+
+  <build>
+  </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-test-helper</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlets</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-proxy</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
new file mode 100644
index 0000000..05a8621
--- /dev/null
+++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
@@ -0,0 +1,411 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
+import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.ClientConnectionFactory;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.io.SelectChannelEndPoint;
+import org.eclipse.jetty.io.SelectorManager;
+import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+/**
+ * <p>{@link HTTP2Client} provides an asynchronous, non-blocking implementation
+ * to send HTTP/2 frames to a server.</p>
+ * <p>Typical usage:</p>
+ * <pre>
+ * // Create and start HTTP2Client.
+ * HTTP2Client client = new HTTP2Client();
+ * SslContextFactory sslContextFactory = new SslContextFactory();
+ * client.addBean(sslContextFactory);
+ * client.start();
+ *
+ * // Connect to host.
+ * String host = "webtide.com";
+ * int port = 443;
+ *
+ * FuturePromise&lt;Session&gt; sessionPromise = new FuturePromise&lt;&gt;();
+ * client.connect(sslContextFactory, new InetSocketAddress(host, port), new ServerSessionListener.Adapter(), sessionPromise);
+ *
+ * // Obtain the client Session object.
+ * Session session = sessionPromise.get(5, TimeUnit.SECONDS);
+ *
+ * // Prepare the HTTP request headers.
+ * HttpFields requestFields = new HttpFields();
+ * requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
+ * // Prepare the HTTP request object.
+ * MetaData.Request request = new MetaData.Request("PUT", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
+ * // Create the HTTP/2 HEADERS frame representing the HTTP request.
+ * HeadersFrame headersFrame = new HeadersFrame(request, null, false);
+ *
+ * // Prepare the listener to receive the HTTP response frames.
+ * Stream.Listener responseListener = new new Stream.Listener.Adapter()
+ * {
+ *      &#64;Override
+ *      public void onHeaders(Stream stream, HeadersFrame frame)
+ *      {
+ *          System.err.println(frame);
+ *      }
+ *
+ *      &#64;Override
+ *      public void onData(Stream stream, DataFrame frame, Callback callback)
+ *      {
+ *          System.err.println(frame);
+ *          callback.succeeded();
+ *      }
+ * };
+ *
+ * // Send the HEADERS frame to create a stream.
+ * FuturePromise&lt;Stream&gt; streamPromise = new FuturePromise&lt;&gt;();
+ * session.newStream(headersFrame, streamPromise, responseListener);
+ * Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+ *
+ * // Use the Stream object to send request content, if any, using a DATA frame.
+ * ByteBuffer content = ...;
+ * DataFrame requestContent = new DataFrame(stream.getId(), content, true);
+ * stream.data(requestContent, Callback.Adapter.INSTANCE);
+ *
+ * // When done, stop the client.
+ * client.stop();
+ * </pre>
+ */
+@ManagedObject
+public class HTTP2Client extends ContainerLifeCycle
+{
+    private Executor executor;
+    private Scheduler scheduler;
+    private ByteBufferPool bufferPool;
+    private ClientConnectionFactory connectionFactory;
+    private SelectorManager selector;
+    private int selectors = 1;
+    private long idleTimeout = 30000;
+    private long connectTimeout = 10000;
+    private int inputBufferSize = 8192;
+    private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14");
+    private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+    private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+    private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        if (executor == null)
+            setExecutor(new QueuedThreadPool());
+
+        if (scheduler == null)
+            setScheduler(new ScheduledExecutorScheduler());
+
+        if (bufferPool == null)
+            setByteBufferPool(new MappedByteBufferPool());
+
+        if (connectionFactory == null)
+        {
+            HTTP2ClientConnectionFactory h2 = new HTTP2ClientConnectionFactory();
+            setClientConnectionFactory((endPoint, context) ->
+            {
+                ClientConnectionFactory factory = h2;
+                SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+                if (sslContextFactory != null)
+                {
+                    ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), h2, getProtocols());
+                    factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), alpn);
+                }
+                return factory.newConnection(endPoint, context);
+            });
+        }
+
+        if (selector == null)
+        {
+            selector = newSelectorManager();
+            addBean(selector);
+        }
+        selector.setConnectTimeout(getConnectTimeout());
+
+        super.doStart();
+    }
+
+    protected SelectorManager newSelectorManager()
+    {
+        return new ClientSelectorManager(getExecutor(), getScheduler(), getSelectors());
+    }
+
+    public Executor getExecutor()
+    {
+        return executor;
+    }
+
+    public void setExecutor(Executor executor)
+    {
+        this.updateBean(this.executor, executor);
+        this.executor = executor;
+    }
+
+    public Scheduler getScheduler()
+    {
+        return scheduler;
+    }
+
+    public void setScheduler(Scheduler scheduler)
+    {
+        this.updateBean(this.scheduler, scheduler);
+        this.scheduler = scheduler;
+    }
+
+    public ByteBufferPool getByteBufferPool()
+    {
+        return bufferPool;
+    }
+
+    public void setByteBufferPool(ByteBufferPool bufferPool)
+    {
+        this.updateBean(this.bufferPool, bufferPool);
+        this.bufferPool = bufferPool;
+    }
+
+    public ClientConnectionFactory getClientConnectionFactory()
+    {
+        return connectionFactory;
+    }
+
+    public void setClientConnectionFactory(ClientConnectionFactory connectionFactory)
+    {
+        this.updateBean(this.connectionFactory, connectionFactory);
+        this.connectionFactory = connectionFactory;
+    }
+
+    public FlowControlStrategy.Factory getFlowControlStrategyFactory()
+    {
+        return flowControlStrategyFactory;
+    }
+
+    public void setFlowControlStrategyFactory(FlowControlStrategy.Factory flowControlStrategyFactory)
+    {
+        this.flowControlStrategyFactory = flowControlStrategyFactory;
+    }
+
+    @ManagedAttribute("The number of selectors")
+    public int getSelectors()
+    {
+        return selectors;
+    }
+
+    public void setSelectors(int selectors)
+    {
+        this.selectors = selectors;
+    }
+
+    @ManagedAttribute("The idle timeout in milliseconds")
+    public long getIdleTimeout()
+    {
+        return idleTimeout;
+    }
+
+    public void setIdleTimeout(long idleTimeout)
+    {
+        this.idleTimeout = idleTimeout;
+    }
+
+    @ManagedAttribute("The connect timeout in milliseconds")
+    public long getConnectTimeout()
+    {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(long connectTimeout)
+    {
+        this.connectTimeout = connectTimeout;
+        SelectorManager selector = this.selector;
+        if (selector != null)
+            selector.setConnectTimeout(connectTimeout);
+    }
+
+    @ManagedAttribute("The size of the buffer used to read from the network")
+    public int getInputBufferSize()
+    {
+        return inputBufferSize;
+    }
+
+    public void setInputBufferSize(int inputBufferSize)
+    {
+        this.inputBufferSize = inputBufferSize;
+    }
+
+    @ManagedAttribute("The ALPN protocol list")
+    public List<String> getProtocols()
+    {
+        return protocols;
+    }
+
+    public void setProtocols(List<String> protocols)
+    {
+        this.protocols = protocols;
+    }
+
+    @ManagedAttribute("The initial size of session's flow control receive window")
+    public int getInitialSessionRecvWindow()
+    {
+        return initialSessionRecvWindow;
+    }
+
+    public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
+    {
+        this.initialSessionRecvWindow = initialSessionRecvWindow;
+    }
+
+    @ManagedAttribute("The initial size of stream's flow control receive window")
+    public int getInitialStreamRecvWindow()
+    {
+        return initialStreamRecvWindow;
+    }
+
+    public void setInitialStreamRecvWindow(int initialStreamRecvWindow)
+    {
+        this.initialStreamRecvWindow = initialStreamRecvWindow;
+    }
+
+    public void connect(InetSocketAddress address, Session.Listener listener, Promise<Session> promise)
+    {
+        connect(null, address, listener, promise);
+    }
+
+    public void connect(SslContextFactory sslContextFactory, InetSocketAddress address, Session.Listener listener, Promise<Session> promise)
+    {
+        connect(sslContextFactory, address, listener, promise, null);
+    }
+
+    public void connect(SslContextFactory sslContextFactory, InetSocketAddress address, Session.Listener listener, Promise<Session> promise, Map<String, Object> context)
+    {
+        try
+        {
+            SocketChannel channel = SocketChannel.open();
+            configure(channel);
+            channel.configureBlocking(false);
+            context = contextFrom(sslContextFactory, address, listener, promise, context);
+            if (channel.connect(address))
+                selector.accept(channel, context);
+            else
+                selector.connect(channel, context);
+        }
+        catch (Throwable x)
+        {
+            promise.failed(x);
+        }
+    }
+
+    public void accept(SslContextFactory sslContextFactory, SocketChannel channel, Session.Listener listener, Promise<Session> promise)
+    {
+        try
+        {
+            if (!channel.isConnected())
+                throw new IllegalStateException("SocketChannel must be connected");
+            channel.configureBlocking(false);
+            Map<String, Object> context = contextFrom(sslContextFactory, (InetSocketAddress)channel.getRemoteAddress(), listener, promise, null);
+            selector.accept(channel, context);
+        }
+        catch (Throwable x)
+        {
+            promise.failed(x);
+        }
+    }
+
+    private Map<String, Object> contextFrom(SslContextFactory sslContextFactory, InetSocketAddress address, Session.Listener listener, Promise<Session> promise, Map<String, Object> context)
+    {
+        if (context == null)
+            context = new HashMap<>();
+        context.put(HTTP2ClientConnectionFactory.CLIENT_CONTEXT_KEY, this);
+        context.put(HTTP2ClientConnectionFactory.SESSION_LISTENER_CONTEXT_KEY, listener);
+        context.put(HTTP2ClientConnectionFactory.SESSION_PROMISE_CONTEXT_KEY, promise);
+        if (sslContextFactory != null)
+            context.put(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY, sslContextFactory);
+        context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, address.getHostString());
+        context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, address.getPort());
+        return context;
+    }
+
+    protected void configure(SocketChannel channel) throws IOException
+    {
+        channel.socket().setTcpNoDelay(true);
+    }
+
+    private class ClientSelectorManager extends SelectorManager
+    {
+        private ClientSelectorManager(Executor executor, Scheduler scheduler, int selectors)
+        {
+            super(executor, scheduler, selectors);
+        }
+
+        @Override
+        protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException
+        {
+            return new SelectChannelEndPoint(channel, selector, selectionKey, getScheduler(), getIdleTimeout());
+        }
+
+        @Override
+        public Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException
+        {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> context = (Map<String, Object>)attachment;
+            context.put(HTTP2ClientConnectionFactory.BYTE_BUFFER_POOL_CONTEXT_KEY, getByteBufferPool());
+            context.put(HTTP2ClientConnectionFactory.EXECUTOR_CONTEXT_KEY, getExecutor());
+            context.put(HTTP2ClientConnectionFactory.SCHEDULER_CONTEXT_KEY, getScheduler());
+            return getClientConnectionFactory().newConnection(endpoint, context);
+        }
+
+        @Override
+        protected void connectionFailed(SocketChannel channel, Throwable failure, Object attachment)
+        {
+            @SuppressWarnings("unchecked")
+            Map<String, Object> context = (Map<String, Object>)attachment;
+            if (LOG.isDebugEnabled())
+            {
+                Object host = context.get(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY);
+                Object port = context.get(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY);
+                LOG.debug("Could not connect to {}:{}", host, port);
+            }
+            @SuppressWarnings("unchecked")
+            Promise<Session> promise = (Promise<Session>)context.get(HTTP2ClientConnectionFactory.SESSION_PROMISE_CONTEXT_KEY);
+            promise.failed(failure);
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java
new file mode 100644
index 0000000..28aad7e
--- /dev/null
+++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java
@@ -0,0 +1,181 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.HTTP2Connection;
+import org.eclipse.jetty.http2.ISession;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.ClientConnectionFactory;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
+{
+    public static final String CLIENT_CONTEXT_KEY = "http2.client";
+    public static final String BYTE_BUFFER_POOL_CONTEXT_KEY = "http2.client.byteBufferPool";
+    public static final String EXECUTOR_CONTEXT_KEY = "http2.client.executor";
+    public static final String SCHEDULER_CONTEXT_KEY = "http2.client.scheduler";
+    public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
+    public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
+
+    private final Connection.Listener connectionListener = new ConnectionListener();
+    private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+
+    @Override
+    public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
+    {
+        HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY);
+        ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY);
+        Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY);
+        Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY);
+        Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY);
+        @SuppressWarnings("unchecked")
+        Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY);
+
+        Generator generator = new Generator(byteBufferPool);
+        FlowControlStrategy flowControl = newFlowControlStrategy();
+        if (flowControl == null)
+            flowControl = client.getFlowControlStrategyFactory().newFlowControlStrategy();
+        HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
+        Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
+        HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener);
+        connection.addListener(connectionListener);
+        return connection;
+    }
+
+    /**
+     * @deprecated use {@link HTTP2Client#setFlowControlStrategyFactory(FlowControlStrategy.Factory)} instead
+     */
+    @Deprecated
+    protected FlowControlStrategy newFlowControlStrategy()
+    {
+        return null;
+    }
+
+    /**
+     * @deprecated use {@link HTTP2Client#getInitialSessionRecvWindow()} instead
+     */
+    @Deprecated
+    public int getInitialSessionRecvWindow()
+    {
+        return initialSessionRecvWindow;
+    }
+
+    /**
+     * @deprecated use {@link HTTP2Client#setInitialSessionRecvWindow(int)} instead
+     */
+    @Deprecated
+    public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
+    {
+        this.initialSessionRecvWindow = initialSessionRecvWindow;
+    }
+
+    private class HTTP2ClientConnection extends HTTP2Connection implements Callback
+    {
+        private final HTTP2Client client;
+        private final Promise<Session> promise;
+        private final Session.Listener listener;
+
+        public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener)
+        {
+            super(byteBufferPool, executor, endpoint, parser, session, bufferSize);
+            this.client = client;
+            this.promise = promise;
+            this.listener = listener;
+        }
+
+        @Override
+        public void onOpen()
+        {
+            Map<Integer, Integer> settings = listener.onPreface(getSession());
+            if (settings == null)
+                settings = Collections.emptyMap();
+
+            PrefaceFrame prefaceFrame = new PrefaceFrame();
+            SettingsFrame settingsFrame = new SettingsFrame(settings, false);
+
+            ISession session = getSession();
+
+            int sessionRecv = client.getInitialSessionRecvWindow();
+            if (sessionRecv == FlowControlStrategy.DEFAULT_WINDOW_SIZE)
+                sessionRecv = initialSessionRecvWindow;
+
+            int windowDelta = sessionRecv - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+            if (windowDelta > 0)
+            {
+                session.updateRecvWindow(windowDelta);
+                session.frames(null, this, prefaceFrame, settingsFrame, new WindowUpdateFrame(0, windowDelta));
+            }
+            else
+            {
+                session.frames(null, this, prefaceFrame, settingsFrame);
+            }
+            // Only start reading from server after we have sent the client preface,
+            // otherwise we risk to read the server preface (a SETTINGS frame) and
+            // reply to that before we have the chance to send the client preface.
+            super.onOpen();
+        }
+
+        @Override
+        public void succeeded()
+        {
+            promise.succeeded(getSession());
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            close();
+            promise.failed(x);
+        }
+    }
+
+    private class ConnectionListener implements Connection.Listener
+    {
+        @Override
+        public void onOpened(Connection connection)
+        {
+            HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
+            http2Connection.client.addManaged((LifeCycle)http2Connection.getSession());
+        }
+
+        @Override
+        public void onClosed(Connection connection)
+        {
+            HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
+            http2Connection.client.removeBean(http2Connection.getSession());
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java
new file mode 100644
index 0000000..0b57662
--- /dev/null
+++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java
@@ -0,0 +1,117 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+public class HTTP2ClientSession extends HTTP2Session
+{
+    private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class);
+
+    public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl)
+    {
+        super(scheduler, endPoint, generator, listener, flowControl, 1);
+    }
+
+    @Override
+    public void onHeaders(HeadersFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        int streamId = frame.getStreamId();
+        IStream stream = getStream(streamId);
+        if (stream == null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Ignoring {}, stream #{} not found", frame, streamId);
+        }
+        else
+        {
+            stream.process(frame, Callback.NOOP);
+            notifyHeaders(stream, frame);
+        }
+    }
+
+    private void notifyHeaders(IStream stream, HeadersFrame frame)
+    {
+        Stream.Listener listener = stream.getListener();
+        if (listener == null)
+            return;
+        try
+        {
+            listener.onHeaders(stream, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    @Override
+    public void onPushPromise(PushPromiseFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        int streamId = frame.getStreamId();
+        int pushStreamId = frame.getPromisedStreamId();
+        IStream stream = getStream(streamId);
+        if (stream == null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Ignoring {}, stream #{} not found", frame, streamId);
+        }
+        else
+        {
+            IStream pushStream = createRemoteStream(pushStreamId);
+            pushStream.process(frame, Callback.NOOP);
+            Stream.Listener listener = notifyPush(stream, pushStream, frame);
+            pushStream.setListener(listener);
+        }
+    }
+
+    private Stream.Listener notifyPush(IStream stream, IStream pushStream, PushPromiseFrame frame)
+    {
+        Stream.Listener listener = stream.getListener();
+        if (listener == null)
+            return null;
+        try
+        {
+            return listener.onPush(pushStream, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+            return null;
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java
new file mode 100644
index 0000000..5490054
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AbstractTest.java
@@ -0,0 +1,129 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.http.HttpServlet;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Rule;
+
+public class AbstractTest
+{
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    protected ServerConnector connector;
+    protected String servletPath = "/test";
+    protected HTTP2Client client;
+    protected Server server;
+
+    protected void start(HttpServlet servlet) throws Exception
+    {
+        prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration()));
+        ServletContextHandler context = new ServletContextHandler(server, "/", true, false);
+        context.addServlet(new ServletHolder(servlet), servletPath + "/*");
+        customizeContext(context);
+        server.start();
+
+        prepareClient();
+        client.start();
+    }
+
+    protected void customizeContext(ServletContextHandler context)
+    {
+    }
+
+    protected void start(ServerSessionListener listener) throws Exception
+    {
+        prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener));
+        server.start();
+
+        prepareClient();
+        client.start();
+    }
+
+    protected void prepareServer(ConnectionFactory... connectionFactories)
+    {
+        QueuedThreadPool serverExecutor = new QueuedThreadPool();
+        serverExecutor.setName("server");
+        server = new Server(serverExecutor);
+        connector = new ServerConnector(server, 1, 1, connectionFactories);
+        server.addConnector(connector);
+    }
+
+    private void prepareClient()
+    {
+        client = new HTTP2Client();
+        QueuedThreadPool clientExecutor = new QueuedThreadPool();
+        clientExecutor.setName("client");
+        client.setExecutor(clientExecutor);
+    }
+
+    protected Session newClient(Session.Listener listener) throws Exception
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        FuturePromise<Session> promise = new FuturePromise<>();
+        client.connect(address, listener, promise);
+        return promise.get(5, TimeUnit.SECONDS);
+    }
+
+    protected MetaData.Request newRequest(String method, HttpFields fields)
+    {
+        return newRequest(method, "", fields);
+    }
+
+    protected MetaData.Request newRequest(String method, String pathInfo, HttpFields fields)
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        String authority = host + ":" + port;
+        return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), servletPath + pathInfo, HttpVersion.HTTP_2, fields);
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (client != null)
+            client.stop();
+        if (server != null)
+            server.stop();
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java
new file mode 100644
index 0000000..75121ee
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncIOTest.java
@@ -0,0 +1,248 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AsyncIOTest extends AbstractTest
+{
+    @Test
+    public void testLastContentAvailableBeforeService() throws Exception
+    {
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                // Wait for the data to fully arrive.
+                sleep(1000);
+
+                final AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+                request.getInputStream().setReadListener(new EmptyReadListener()
+                {
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        ServletInputStream input = request.getInputStream();
+                        while (input.isReady())
+                        {
+                            int read = input.read();
+                            if (read < 0)
+                                break;
+                        }
+                        if (input.isFinished())
+                            asyncContext.complete();
+                    }
+                });
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, false);
+        final CountDownLatch latch = new CountDownLatch(1);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), Callback.NOOP);
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testLastContentAvailableAfterServiceReturns() throws Exception
+    {
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                final AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+                request.getInputStream().setReadListener(new EmptyReadListener()
+                {
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        ServletInputStream input = request.getInputStream();
+                        while (input.isReady())
+                        {
+                            int read = input.read();
+                            if (read < 0)
+                                break;
+                        }
+                        if (input.isFinished())
+                            asyncContext.complete();
+                    }
+                });
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, false);
+        final CountDownLatch latch = new CountDownLatch(1);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+
+        // Wait until service() returns.
+        Thread.sleep(1000);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), Callback.NOOP);
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testSomeContentAvailableAfterServiceReturns() throws Exception
+    {
+        final AtomicInteger count = new AtomicInteger();
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                final AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+                request.getInputStream().setReadListener(new EmptyReadListener()
+                {
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        count.incrementAndGet();
+                        ServletInputStream input = request.getInputStream();
+                        while (input.isReady())
+                        {
+                            int read = input.read();
+                            if (read < 0)
+                                break;
+                        }
+                        if (input.isFinished())
+                            asyncContext.complete();
+                    }
+                });
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, false);
+        final CountDownLatch latch = new CountDownLatch(1);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+
+        // Wait until service() returns.
+        Thread.sleep(1000);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), false), Callback.NOOP);
+
+        // Wait until onDataAvailable() returns.
+        Thread.sleep(1000);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), true), Callback.NOOP);
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+        // Make sure onDataAvailable() has been called twice
+        Assert.assertEquals(2, count.get());
+    }
+
+    private static void sleep(long ms) throws InterruptedIOException
+    {
+        try
+        {
+            Thread.sleep(ms);
+        }
+        catch (InterruptedException x)
+        {
+            throw new InterruptedIOException();
+        }
+    }
+
+    private static class EmptyReadListener implements ReadListener
+    {
+        @Override
+        public void onDataAvailable() throws IOException
+        {
+        }
+
+        @Override
+        public void onAllDataRead() throws IOException
+        {
+        }
+
+        @Override
+        public void onError(Throwable t)
+        {
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java
new file mode 100644
index 0000000..48f3bd5
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/BufferingFlowControlStrategyTest.java
@@ -0,0 +1,31 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client;
+
+import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+
+public class BufferingFlowControlStrategyTest extends FlowControlStrategyTest
+{
+    @Override
+    protected FlowControlStrategy newFlowControlStrategy()
+    {
+        return new BufferingFlowControlStrategy(0.5F);
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java
new file mode 100644
index 0000000..98743a3
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/Client.java
@@ -0,0 +1,94 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Jetty;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+public class Client
+{
+    public static void main(String[] args) throws Exception
+    {
+        HTTP2Client client = new HTTP2Client();
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        client.addBean(sslContextFactory);
+        client.start();
+
+        String host = "webtide.com";
+        int port = 443;
+
+        FuturePromise<Session> sessionPromise = new FuturePromise<>();
+        client.connect(sslContextFactory, new InetSocketAddress(host, port), new ServerSessionListener.Adapter(), sessionPromise);
+        Session session = sessionPromise.get(5, TimeUnit.SECONDS);
+
+        HttpFields requestFields = new HttpFields();
+        requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
+        MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
+        HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
+        final Phaser phaser = new Phaser(2);
+        session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                System.err.println(frame);
+                if (frame.isEndStream())
+                    phaser.arrive();
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                System.err.println(frame);
+                callback.succeeded();
+                if (frame.isEndStream())
+                    phaser.arrive();
+            }
+
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                System.err.println(frame);
+                phaser.register();
+                return this;
+            }
+        });
+
+        phaser.awaitAdvanceInterruptibly(phaser.arrive(), 5, TimeUnit.SECONDS);
+
+        client.stop();
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java
new file mode 100644
index 0000000..59b9319
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ConnectTimeoutTest.java
@@ -0,0 +1,90 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class ConnectTimeoutTest extends AbstractTest
+{
+    @Test
+    public void testConnectTimeout() throws Exception
+    {
+        final String host = "10.255.255.1";
+        final int port = 80;
+        int connectTimeout = 1000;
+        assumeConnectTimeout(host, port, connectTimeout);
+
+        start(new ServerSessionListener.Adapter());
+        client.setConnectTimeout(connectTimeout);
+
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        final CountDownLatch latch = new CountDownLatch(1);
+        client.connect(address, new Session.Listener.Adapter(), new Promise.Adapter<Session>()
+        {
+            @Override
+            public void failed(Throwable x)
+            {
+                Assert.assertTrue(x instanceof SocketTimeoutException);
+                latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(2 * connectTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    private void assumeConnectTimeout(String host, int port, int connectTimeout) throws IOException
+    {
+        boolean socketTimeout = false;
+        
+        try (Socket socket = new Socket())
+        {
+            // Try to connect to a private address in the 10.x.y.z range.
+            // These addresses are usually not routed, so an attempt to
+            // connect to them will hang the connection attempt, which is
+            // what we want to simulate in this test.
+            socket.connect(new InetSocketAddress(host, port), connectTimeout);
+        }
+        catch (SocketTimeoutException x)
+        {
+            // We expect a timeout during connect, allow test to continue.
+            socketTimeout = true;
+        }
+        catch (Throwable x)
+        {
+            // Dump stacktrace when there is an unexpected test failure
+            // Useful when debugging
+            x.printStackTrace(System.err);
+        }
+        
+        // Abort the test if we can connect.
+        Assume.assumeTrue("Should have seen connect timeout",socketTimeout);
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java
new file mode 100644
index 0000000..abc0265
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/EmptyHttpServlet.java
@@ -0,0 +1,34 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class EmptyHttpServlet extends HttpServlet
+{
+    @Override
+    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java
new file mode 100644
index 0000000..3d6c0a8
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStalledTest.java
@@ -0,0 +1,305 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.ISession;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class FlowControlStalledTest
+{
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    protected ServerConnector connector;
+    protected HTTP2Client client;
+    protected Server server;
+
+    protected void start(FlowControlStrategy.Factory flowControlFactory, ServerSessionListener listener) throws Exception
+    {
+        QueuedThreadPool serverExecutor = new QueuedThreadPool();
+        serverExecutor.setName("server");
+        server = new Server(serverExecutor);
+        RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
+        connectionFactory.setFlowControlStrategyFactory(flowControlFactory);
+        connector = new ServerConnector(server, connectionFactory);
+        server.addConnector(connector);
+        server.start();
+
+        client = new HTTP2Client();
+        QueuedThreadPool clientExecutor = new QueuedThreadPool();
+        clientExecutor.setName("client");
+        client.setExecutor(clientExecutor);
+        client.setFlowControlStrategyFactory(flowControlFactory);
+        client.start();
+    }
+
+    protected Session newClient(Session.Listener listener) throws Exception
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        FuturePromise<Session> promise = new FuturePromise<>();
+        client.connect(address, listener, promise);
+        return promise.get(5, TimeUnit.SECONDS);
+    }
+
+    protected MetaData.Request newRequest(String method, String target, HttpFields fields)
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        String authority = host + ":" + port;
+        return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), target, HttpVersion.HTTP_2, fields);
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        // Allow WINDOW_UPDATE frames to be sent/received to avoid exception stack traces.
+        Thread.sleep(1000);
+        client.stop();
+        server.stop();
+    }
+
+    @Test
+    public void testStreamStalledIsInvokedOnlyOnce() throws Exception
+    {
+        AtomicReference<CountDownLatch> stallLatch = new AtomicReference<>(new CountDownLatch(1));
+        CountDownLatch unstallLatch = new CountDownLatch(1);
+        start(() -> new BufferingFlowControlStrategy(0.5f)
+        {
+            @Override
+            public void onStreamStalled(IStream stream)
+            {
+                super.onStreamStalled(stream);
+                stallLatch.get().countDown();
+            }
+
+            @Override
+            protected void onStreamUnstalled(IStream stream)
+            {
+                super.onStreamUnstalled(stream);
+                unstallLatch.countDown();
+            }
+        }, new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Request request = (MetaData.Request)frame.getMetaData();
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+
+                if (request.getURIString().endsWith("/stall"))
+                {
+                    stream.headers(new HeadersFrame(stream.getId(), response, null, false), new Callback()
+                    {
+                        @Override
+                        public void succeeded()
+                        {
+                            // Send a large chunk of data so the stream gets stalled.
+                            ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE + 1);
+                            stream.data(new DataFrame(stream.getId(), data, true), NOOP);
+                        }
+                    });
+                }
+                else
+                {
+                    stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                }
+
+                return null;
+            }
+        });
+
+        // Use a large session window so that only the stream gets stalled.
+        client.setInitialSessionRecvWindow(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        Session client = newClient(new Session.Listener.Adapter());
+
+        CountDownLatch latch = new CountDownLatch(1);
+        Queue<Callback> callbacks = new ArrayDeque<>();
+        MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
+        client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callbacks.offer(callback);
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(stallLatch.get().await(5, TimeUnit.SECONDS));
+
+        // First stream is now stalled, check that writing a second stream
+        // does not result in the first be notified again of being stalled.
+        stallLatch.set(new CountDownLatch(1));
+
+        request = newRequest("GET", "/", new HttpFields());
+        client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter());
+
+        Assert.assertFalse(stallLatch.get().await(1, TimeUnit.SECONDS));
+
+        // Consume all data.
+        while (!latch.await(10, TimeUnit.MILLISECONDS))
+        {
+            Callback callback = callbacks.poll();
+            if (callback != null)
+                callback.succeeded();
+        }
+
+        // Make sure the unstall callback is invoked.
+        Assert.assertTrue(unstallLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testSessionStalledIsInvokedOnlyOnce() throws Exception
+    {
+        AtomicReference<CountDownLatch> stallLatch = new AtomicReference<>(new CountDownLatch(1));
+        CountDownLatch unstallLatch = new CountDownLatch(1);
+        start(() -> new BufferingFlowControlStrategy(0.5f)
+        {
+            @Override
+            public void onSessionStalled(ISession session)
+            {
+                super.onSessionStalled(session);
+                stallLatch.get().countDown();
+            }
+
+            @Override
+            protected void onSessionUnstalled(ISession session)
+            {
+                super.onSessionUnstalled(session);
+                unstallLatch.countDown();
+            }
+        }, new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Request request = (MetaData.Request)frame.getMetaData();
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+
+                if (request.getURIString().endsWith("/stall"))
+                {
+                    stream.headers(new HeadersFrame(stream.getId(), response, null, false), new Callback()
+                    {
+                        @Override
+                        public void succeeded()
+                        {
+                            // Send a large chunk of data so the session gets stalled.
+                            ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE + 1);
+                            stream.data(new DataFrame(stream.getId(), data, true), NOOP);
+                        }
+                    });
+                }
+                else
+                {
+                    stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                }
+
+                return null;
+            }
+        });
+
+        // Use a large stream window so that only the session gets stalled.
+        client.setInitialStreamRecvWindow(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>();
+                settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow());
+                return settings;
+            }
+        });
+
+        CountDownLatch latch = new CountDownLatch(1);
+        Queue<Callback> callbacks = new ArrayDeque<>();
+        MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
+        session.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callbacks.offer(callback);
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(stallLatch.get().await(5, TimeUnit.SECONDS));
+
+        // The session is now stalled, check that writing a second stream
+        // does not result in the session be notified again of being stalled.
+        stallLatch.set(new CountDownLatch(1));
+
+        request = newRequest("GET", "/", new HttpFields());
+        session.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter());
+
+        Assert.assertFalse(stallLatch.get().await(1, TimeUnit.SECONDS));
+
+        // Consume all data.
+        while (!latch.await(10, TimeUnit.MILLISECONDS))
+        {
+            Callback callback = callbacks.poll();
+            if (callback != null)
+                callback.succeeded();
+        }
+
+        // Make sure the unstall callback is invoked.
+        Assert.assertTrue(unstallLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java
new file mode 100644
index 0000000..eaeaa09
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java
@@ -0,0 +1,963 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.HTTP2Stream;
+import org.eclipse.jetty.http2.ISession;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FutureCallback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public abstract class FlowControlStrategyTest
+{
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    protected ServerConnector connector;
+    protected HTTP2Client client;
+    protected Server server;
+
+    protected abstract FlowControlStrategy newFlowControlStrategy();
+
+    protected void start(ServerSessionListener listener) throws Exception
+    {
+        QueuedThreadPool serverExecutor = new QueuedThreadPool();
+        serverExecutor.setName("server");
+        server = new Server(serverExecutor);
+        RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
+        connectionFactory.setFlowControlStrategyFactory(FlowControlStrategyTest.this::newFlowControlStrategy);
+        connector = new ServerConnector(server, connectionFactory);
+        server.addConnector(connector);
+        server.start();
+
+        client = new HTTP2Client();
+        QueuedThreadPool clientExecutor = new QueuedThreadPool();
+        clientExecutor.setName("client");
+        client.setExecutor(clientExecutor);
+        client.setFlowControlStrategyFactory(FlowControlStrategyTest.this::newFlowControlStrategy);
+        client.start();
+    }
+
+    protected Session newClient(Session.Listener listener) throws Exception
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        FuturePromise<Session> promise = new FuturePromise<>();
+        client.connect(address, listener, promise);
+        return promise.get(5, TimeUnit.SECONDS);
+    }
+
+    protected MetaData.Request newRequest(String method, HttpFields fields)
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        String authority = host + ":" + port;
+        return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), "/", HttpVersion.HTTP_2, fields);
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        // Allow WINDOW_UPDATE frames to be sent/received to avoid exception stack traces.
+        Thread.sleep(1000);
+        client.stop();
+        server.stop();
+    }
+
+    @Test
+    public void testWindowSizeUpdates() throws Exception
+    {
+        final CountDownLatch prefaceLatch = new CountDownLatch(1);
+        final CountDownLatch stream1Latch = new CountDownLatch(1);
+        final CountDownLatch stream2Latch = new CountDownLatch(1);
+        final CountDownLatch settingsLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                HTTP2Session serverSession = (HTTP2Session)session;
+                Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverSession.getSendWindow());
+                Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverSession.getRecvWindow());
+                prefaceLatch.countDown();
+                return null;
+            }
+
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                for (Stream stream : session.getStreams())
+                {
+                    HTTP2Stream serverStream = (HTTP2Stream)stream;
+                    Assert.assertEquals(0, serverStream.getSendWindow());
+                    Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
+                }
+                settingsLatch.countDown();
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                HTTP2Stream serverStream = (HTTP2Stream)stream;
+                MetaData.Request request = (MetaData.Request)frame.getMetaData();
+                if ("GET".equalsIgnoreCase(request.getMethod()))
+                {
+                    Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getSendWindow());
+                    Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
+                    stream1Latch.countDown();
+                }
+                else
+                {
+                    Assert.assertEquals(0, serverStream.getSendWindow());
+                    Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
+                    stream2Latch.countDown();
+                }
+                return null;
+            }
+        });
+
+        HTTP2Session clientSession = (HTTP2Session)newClient(new Session.Listener.Adapter());
+
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientSession.getSendWindow());
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientSession.getRecvWindow());
+        Assert.assertTrue(prefaceLatch.await(5, TimeUnit.SECONDS));
+
+        MetaData.Request request1 = newRequest("GET", new HttpFields());
+        FuturePromise<Stream> promise1 = new FuturePromise<>();
+        clientSession.newStream(new HeadersFrame(request1, null, true), promise1, new Stream.Listener.Adapter());
+        HTTP2Stream clientStream1 = (HTTP2Stream)promise1.get(5, TimeUnit.SECONDS);
+
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getSendWindow());
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getRecvWindow());
+        Assert.assertTrue(stream1Latch.await(5, TimeUnit.SECONDS));
+
+        // Send a SETTINGS frame that changes the window size.
+        // This tells the server that its stream send window must be updated,
+        // so on the client it's the receive window that must be updated.
+        Map<Integer, Integer> settings = new HashMap<>();
+        settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
+        SettingsFrame frame = new SettingsFrame(settings, false);
+        FutureCallback callback = new FutureCallback();
+        clientSession.settings(frame, callback);
+        callback.get(5, TimeUnit.SECONDS);
+
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getSendWindow());
+        Assert.assertEquals(0, clientStream1.getRecvWindow());
+        settingsLatch.await(5, TimeUnit.SECONDS);
+
+        // Now create a new stream, it must pick up the new value.
+        MetaData.Request request2 = newRequest("POST", new HttpFields());
+        FuturePromise<Stream> promise2 = new FuturePromise<>();
+        clientSession.newStream(new HeadersFrame(request2, null, true), promise2, new Stream.Listener.Adapter());
+        HTTP2Stream clientStream2 = (HTTP2Stream)promise2.get(5, TimeUnit.SECONDS);
+
+        Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream2.getSendWindow());
+        Assert.assertEquals(0, clientStream2.getRecvWindow());
+        Assert.assertTrue(stream2Latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testFlowControlWithConcurrentSettings() throws Exception
+    {
+        // Initial window is 64 KiB. We allow the client to send 1024 B
+        // then we change the window to 512 B. At this point, the client
+        // must stop sending data (although the initial window allows it).
+
+        final int size = 512;
+        // We get 3 data frames: the first of 1024 and 2 of 512 each
+        // after the flow control window has been reduced.
+        final CountDownLatch dataLatch = new CountDownLatch(3);
+        final AtomicReference<Callback> callbackRef = new AtomicReference<>();
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                HttpFields fields = new HttpFields();
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+
+                return new Stream.Listener.Adapter()
+                {
+                    private final AtomicInteger dataFrames = new AtomicInteger();
+
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        dataLatch.countDown();
+                        int dataFrameCount = dataFrames.incrementAndGet();
+                        if (dataFrameCount == 1)
+                        {
+                            callbackRef.set(callback);
+                            Map<Integer, Integer> settings = new HashMap<>();
+                            settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, size);
+                            stream.getSession().settings(new SettingsFrame(settings, false), Callback.NOOP);
+                            // Do not succeed the callback here.
+                        }
+                        else if (dataFrameCount > 1)
+                        {
+                            // Consume the data.
+                            callback.succeeded();
+                        }
+                    }
+                };
+            }
+        });
+
+        // Two SETTINGS frames, the initial one and the one we send from the server.
+        final CountDownLatch settingsLatch = new CountDownLatch(2);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.countDown();
+            }
+        });
+
+        MetaData.Request request = newRequest("POST", new HttpFields());
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(new HeadersFrame(request, null, false), promise, new Stream.Listener.Adapter());
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+
+        // Send first chunk that exceeds the window.
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), false), Callback.NOOP);
+        settingsLatch.await(5, TimeUnit.SECONDS);
+
+        // Send the second chunk of data, must not arrive since we're flow control stalled on the client.
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(size * 2), true), Callback.NOOP);
+        Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
+
+        // Consume the data arrived to server, this will resume flow control on the client.
+        callbackRef.get().succeeded();
+
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testServerFlowControlOneBigWrite() throws Exception
+    {
+        final int windowSize = 1536;
+        final int length = 5 * windowSize;
+        final CountDownLatch settingsLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.countDown();
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
+                stream.headers(responseFrame, Callback.NOOP);
+
+                DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true);
+                stream.data(dataFrame, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        Map<Integer, Integer> settings = new HashMap<>();
+        settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
+        session.settings(new SettingsFrame(settings, false), Callback.NOOP);
+
+        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
+
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        final Exchanger<Callback> exchanger = new Exchanger<>();
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            private AtomicInteger dataFrames = new AtomicInteger();
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                try
+                {
+                    int dataFrames = this.dataFrames.incrementAndGet();
+                    if (dataFrames == 1 || dataFrames == 2)
+                    {
+                        // Do not consume the data frame.
+                        // We should then be flow-control stalled.
+                        exchanger.exchange(callback);
+                    }
+                    else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5)
+                    {
+                        // Consume totally.
+                        callback.succeeded();
+                        if (frame.isEndStream())
+                            dataLatch.countDown();
+                    }
+                    else
+                    {
+                        Assert.fail();
+                    }
+                }
+                catch (InterruptedException x)
+                {
+                    callback.failed(x);
+                }
+            }
+        });
+
+        Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
+        checkThatWeAreFlowControlStalled(exchanger);
+
+        // Consume the first chunk.
+        callback.succeeded();
+
+        callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
+        checkThatWeAreFlowControlStalled(exchanger);
+
+        // Consume the second chunk.
+        callback.succeeded();
+
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testClientFlowControlOneBigWrite() throws Exception
+    {
+        final int windowSize = 1536;
+        final Exchanger<Callback> exchanger = new Exchanger<>();
+        final CountDownLatch settingsLatch = new CountDownLatch(1);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>();
+                settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
+                return settings;
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
+                stream.headers(responseFrame, Callback.NOOP);
+                return new Stream.Listener.Adapter()
+                {
+                    private AtomicInteger dataFrames = new AtomicInteger();
+
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        try
+                        {
+                            int dataFrames = this.dataFrames.incrementAndGet();
+                            if (dataFrames == 1 || dataFrames == 2)
+                            {
+                                // Do not consume the data frame.
+                                // We should then be flow-control stalled.
+                                exchanger.exchange(callback);
+                            }
+                            else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5)
+                            {
+                                // Consume totally.
+                                callback.succeeded();
+                                if (frame.isEndStream())
+                                    dataLatch.countDown();
+                            }
+                            else
+                            {
+                                Assert.fail();
+                            }
+                        }
+                        catch (InterruptedException x)
+                        {
+                            callback.failed(x);
+                        }
+                    }
+                };
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
+
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise = new FuturePromise<>();
+        session.newStream(requestFrame, streamPromise, null);
+        Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+
+        final int length = 5 * windowSize;
+        DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true);
+        stream.data(dataFrame, Callback.NOOP);
+
+        Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
+        checkThatWeAreFlowControlStalled(exchanger);
+
+        // Consume the first chunk.
+        callback.succeeded();
+
+        callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
+        checkThatWeAreFlowControlStalled(exchanger);
+
+        // Consume the second chunk.
+        callback.succeeded();
+
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    private void checkThatWeAreFlowControlStalled(Exchanger<Callback> exchanger) throws Exception
+    {
+        try
+        {
+            exchanger.exchange(null, 1, TimeUnit.SECONDS);
+            Assert.fail();
+        }
+        catch (TimeoutException x)
+        {
+            // Expected.
+        }
+    }
+
+    @Test
+    public void testSessionStalledStallsNewStreams() throws Exception
+    {
+        final int windowSize = 1024;
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                MetaData.Request request = (MetaData.Request)requestFrame.getMetaData();
+                if ("POST".equalsIgnoreCase(request.getMethod()))
+                {
+                    // Send data to consume most of the session window.
+                    ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE - windowSize);
+                    DataFrame dataFrame = new DataFrame(stream.getId(), data, true);
+                    stream.data(dataFrame, Callback.NOOP);
+                    return null;
+                }
+                else
+                {
+                    // For every stream, send down half the window size of data.
+                    MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                    HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
+                    stream.headers(responseFrame, Callback.NOOP);
+                    DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(windowSize / 2), true);
+                    stream.data(dataFrame, Callback.NOOP);
+                    return null;
+                }
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        // First request is just to consume most of the session window.
+        final List<Callback> callbacks1 = new ArrayList<>();
+        final CountDownLatch prepareLatch = new CountDownLatch(1);
+        MetaData.Request request1 = newRequest("POST", new HttpFields());
+        session.newStream(new HeadersFrame(request1, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                // Do not consume the data to reduce the session window.
+                callbacks1.add(callback);
+                if (frame.isEndStream())
+                    prepareLatch.countDown();
+            }
+        });
+        Assert.assertTrue(prepareLatch.await(5, TimeUnit.SECONDS));
+
+        // Second request will consume half of the remaining the session window.
+        MetaData.Request request2 = newRequest("GET", new HttpFields());
+        session.newStream(new HeadersFrame(request2, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                // Do not consume it to stall flow control.
+            }
+        });
+
+        // Third request will consume the whole session window, which is now stalled.
+        // A fourth request will not be able to receive data.
+        MetaData.Request request3 = newRequest("GET", new HttpFields());
+        session.newStream(new HeadersFrame(request3, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                // Do not consume it to stall flow control.
+            }
+        });
+
+        // Fourth request is now stalled.
+        final CountDownLatch latch = new CountDownLatch(1);
+        MetaData.Request request4 = newRequest("GET", new HttpFields());
+        session.newStream(new HeadersFrame(request4, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        // Verify that the data does not arrive because the server session is stalled.
+        Assert.assertFalse(latch.await(1, TimeUnit.SECONDS));
+
+        // Consume the data of the first response.
+        // This will open up the session window, allowing the fourth stream to send data.
+        for (Callback callback : callbacks1)
+            callback.succeeded();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testServerSendsBigContent() throws Exception
+    {
+        final byte[] data = new byte[1024 * 1024];
+        new Random().nextBytes(data);
+
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
+                stream.headers(responseFrame, Callback.NOOP);
+                DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true);
+                stream.data(dataFrame, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        final byte[] bytes = new byte[data.length];
+        final CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            private int received;
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                int remaining = frame.remaining();
+                frame.getData().get(bytes, received, remaining);
+                this.received += remaining;
+                callback.succeeded();
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(15, TimeUnit.SECONDS));
+        Assert.assertArrayEquals(data, bytes);
+    }
+
+    @Test
+    public void testServerTwoDataFramesWithStalledStream() throws Exception
+    {
+        // Frames in queue = DATA1, DATA2.
+        // Server writes part of DATA1, then stalls.
+        // A window update unstalls the session, verify that the data is correctly sent.
+
+        Random random = new Random();
+        final byte[] chunk1 = new byte[1024];
+        random.nextBytes(chunk1);
+        final byte[] chunk2 = new byte[2048];
+        random.nextBytes(chunk2);
+
+        // Two SETTINGS frames: the initial after the preface,
+        // and the explicit where we set the stream window size to zero.
+        final AtomicReference<CountDownLatch> settingsLatch = new AtomicReference<>(new CountDownLatch(2));
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.get().countDown();
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk1), false), Callback.NOOP);
+                stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk2), true), Callback.NOOP);
+                dataLatch.countDown();
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        Map<Integer, Integer> settings = new HashMap<>();
+        settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
+        session.settings(new SettingsFrame(settings, false), Callback.NOOP);
+        Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
+
+        byte[] content = new byte[chunk1.length + chunk2.length];
+        final ByteBuffer buffer = ByteBuffer.wrap(content);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch responseLatch = new CountDownLatch(1);
+        session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                buffer.put(frame.getData());
+                callback.succeeded();
+                if (frame.isEndStream())
+                    responseLatch.countDown();
+            }
+        });
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+
+        // Now we have the 2 DATA frames queued in the server.
+
+        // Unstall the stream window.
+        settingsLatch.set(new CountDownLatch(1));
+        settings.clear();
+        settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, chunk1.length / 2);
+        session.settings(new SettingsFrame(settings, false), Callback.NOOP);
+        Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
+
+        Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+
+        // Check that the data is sent correctly.
+        byte[] expected = new byte[content.length];
+        System.arraycopy(chunk1, 0, expected, 0, chunk1.length);
+        System.arraycopy(chunk2, 0, expected, chunk1.length, chunk2.length);
+        Assert.assertArrayEquals(expected, content);
+    }
+
+    @Test
+    public void testClientSendingInitialSmallWindow() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, false);
+                stream.headers(responseFrame, Callback.NOOP);
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        // Since we echo back the data
+                        // asynchronously we must copy it.
+                        ByteBuffer data = frame.getData();
+                        ByteBuffer copy = ByteBuffer.allocateDirect(data.remaining());
+                        copy.put(data).flip();
+                        stream.data(new DataFrame(stream.getId(), copy, frame.isEndStream()), callback);
+                    }
+                };
+            }
+        });
+
+        final int initialWindow = 16;
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>();
+                settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, initialWindow);
+                return settings;
+            }
+        });
+
+        byte[] requestData = new byte[initialWindow * 4];
+        new Random().nextBytes(requestData);
+
+        byte[] responseData = new byte[requestData.length];
+        final ByteBuffer responseContent = ByteBuffer.wrap(responseData);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise = new FuturePromise<>();
+        final CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                responseContent.put(frame.getData());
+                callback.succeeded();
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+        Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+
+        ByteBuffer requestContent = ByteBuffer.wrap(requestData);
+        DataFrame dataFrame = new DataFrame(stream.getId(), requestContent, true);
+        stream.data(dataFrame, Callback.NOOP);
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
+        responseContent.flip();
+        Assert.assertArrayEquals(requestData, responseData);
+    }
+
+    @Test
+    public void testClientExceedingSessionWindow() throws Exception
+    {
+        // On server, we don't consume the data.
+        start(new ServerSessionListener.Adapter());
+
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (frame.getError() == ErrorCode.FLOW_CONTROL_ERROR.code)
+                    closeLatch.countDown();
+            }
+        });
+
+        // Consume the whole session and stream window.
+        MetaData.Request metaData = newRequest("POST", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise = new FuturePromise<>();
+        session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter());
+        Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+        ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        stream.data(new DataFrame(stream.getId(), data, false), new Callback.NonBlocking()
+        {
+            @Override
+            public void succeeded()
+            {
+                dataLatch.countDown();
+            }
+        });
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+
+        // The following "sneaky" write may clash with the write
+        // of the reply SETTINGS frame sent by the client in
+        // response to the server SETTINGS frame.
+        // It is not enough to use a latch on the server to
+        // wait for the reply frame, since the client may have
+        // sent the bytes, but not yet be ready to write again.
+        Thread.sleep(1000);
+
+        // Now the client is supposed to not send more frames.
+        // If it does, the connection must be closed.
+        HTTP2Session http2Session = (HTTP2Session)session;
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool());
+        ByteBuffer extraData = ByteBuffer.allocate(1024);
+        http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
+        List<ByteBuffer> buffers = lease.getByteBuffers();
+        http2Session.getEndPoint().write(Callback.NOOP, buffers.toArray(new ByteBuffer[buffers.size()]));
+
+        // Expect the connection to be closed.
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testClientExceedingStreamWindow() throws Exception
+    {
+        // On server, we don't consume the data.
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                // Enlarge the session window.
+                ((ISession)session).updateRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+                return super.onPreface(session);
+            }
+        });
+
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (frame.getError() == ErrorCode.FLOW_CONTROL_ERROR.code)
+                    closeLatch.countDown();
+            }
+        });
+
+        // Consume the whole stream window.
+        MetaData.Request metaData = newRequest("POST", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise = new FuturePromise<>();
+        session.newStream(requestFrame, streamPromise, new Stream.Listener.Adapter());
+        Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+        ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        stream.data(new DataFrame(stream.getId(), data, false), new Callback.NonBlocking()
+        {
+            @Override
+            public void succeeded()
+            {
+                dataLatch.countDown();
+            }
+        });
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+
+        // Wait for a while before doing the "sneaky" write
+        // below, see comments in the previous test case.
+        Thread.sleep(1000);
+
+        // Now the client is supposed to not send more frames.
+        // If it does, the connection must be closed.
+        HTTP2Session http2Session = (HTTP2Session)session;
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool());
+        ByteBuffer extraData = ByteBuffer.allocate(1024);
+        http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
+        List<ByteBuffer> buffers = lease.getByteBuffers();
+        http2Session.getEndPoint().write(Callback.NOOP, buffers.toArray(new ByteBuffer[buffers.size()]));
+
+        // Expect the connection to be closed.
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testFlowControlWhenServerResetsStream() throws Exception
+    {
+        // On server, don't consume the data and immediately reset.
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Request request = (MetaData.Request)frame.getMetaData();
+
+                if (HttpMethod.GET.is(request.getMethod()))
+                    return new Stream.Listener.Adapter();
+
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        // Fail the callback to enlarge the session window.
+                        // More data frames will be discarded because the
+                        // stream is reset, and automatically consumed to
+                        // keep the session window large for other streams.
+                        callback.failed(new Throwable());
+                        stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+                    }
+                };
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("POST", new HttpFields());
+        HeadersFrame frame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise = new FuturePromise<>();
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        session.newStream(frame, streamPromise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onReset(Stream stream, ResetFrame frame)
+            {
+                resetLatch.countDown();
+            }
+        });
+        Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
+
+        // Perform a big upload that will stall the flow control windows.
+        ByteBuffer data = ByteBuffer.allocate(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        stream.data(new DataFrame(stream.getId(), data, true), new Callback.NonBlocking()
+        {
+            @Override
+            public void failed(Throwable x)
+            {
+                dataLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
new file mode 100644
index 0000000..6abca17
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
@@ -0,0 +1,462 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Jetty;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HTTP2Test extends AbstractTest
+{
+    @Test
+    public void testRequestNoContentResponseNoContent() throws Exception
+    {
+        start(new EmptyHttpServlet());
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                Assert.assertTrue(stream.getId() > 0);
+
+                Assert.assertTrue(frame.isEndStream());
+                Assert.assertEquals(stream.getId(), frame.getStreamId());
+                Assert.assertTrue(frame.getMetaData().isResponse());
+                MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                Assert.assertEquals(200, response.getStatus());
+
+                latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testRequestNoContentResponseContent() throws Exception
+    {
+        final byte[] content = "Hello World!".getBytes(StandardCharsets.UTF_8);
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                resp.getOutputStream().write(content);
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch latch = new CountDownLatch(2);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                Assert.assertTrue(stream.getId() > 0);
+
+                Assert.assertFalse(frame.isEndStream());
+                Assert.assertEquals(stream.getId(), frame.getStreamId());
+                Assert.assertTrue(frame.getMetaData().isResponse());
+                MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                Assert.assertEquals(200, response.getStatus());
+
+                latch.countDown();
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                Assert.assertTrue(frame.isEndStream());
+                Assert.assertEquals(ByteBuffer.wrap(content), frame.getData());
+
+                callback.succeeded();
+                latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testMultipleRequests() throws Exception
+    {
+        final String downloadBytes = "X-Download";
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                int download = request.getIntHeader(downloadBytes);
+                byte[] content = new byte[download];
+                new Random().nextBytes(content);
+                response.getOutputStream().write(content);
+            }
+        });
+
+        int requests = 20;
+        Session session = newClient(new Session.Listener.Adapter());
+
+        Random random = new Random();
+        HttpFields fields = new HttpFields();
+        fields.putLongField(downloadBytes, random.nextInt(128 * 1024));
+        fields.put("User-Agent", "HTTP2Client/" + Jetty.VERSION);
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch latch = new CountDownLatch(requests);
+        for (int i = 0; i < requests; ++i)
+        {
+            session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+            {
+                @Override
+                public void onData(Stream stream, DataFrame frame, Callback callback)
+                {
+                    callback.succeeded();
+                    if (frame.isEndStream())
+                        latch.countDown();
+                }
+            });
+        }
+
+        Assert.assertTrue(latch.await(requests, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testCustomResponseCode() throws Exception
+    {
+        final int status = 475;
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                response.setStatus(status);
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                Assert.assertEquals(status, response.getStatus());
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testHostHeader() throws Exception
+    {
+        final String host = "fooBar";
+        final int port = 1313;
+        final String authority = host + ":" + port;
+        start(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Assert.assertEquals(host, request.getServerName());
+                Assert.assertEquals(port, request.getServerPort());
+                Assert.assertEquals(authority, request.getHeader("Host"));
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HostPortHttpField hostHeader = new HostPortHttpField(authority);
+        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, hostHeader, servletPath, HttpVersion.HTTP_2, new HttpFields());
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        final CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                Assert.assertEquals(200, response.getStatus());
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testServerSendsGoAwayOnStop() throws Exception
+    {
+        start(new ServerSessionListener.Adapter());
+
+        CountDownLatch closeLatch = new CountDownLatch(1);
+        newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                closeLatch.countDown();
+            }
+        });
+
+        Thread.sleep(1000);
+
+        server.stop();
+
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testClientSendsGoAwayOnStop() throws Exception
+    {
+        CountDownLatch closeLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                closeLatch.countDown();
+            }
+        });
+
+        newClient(new Session.Listener.Adapter());
+
+        Thread.sleep(1000);
+
+        client.stop();
+
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testMaxConcurrentStreams() throws Exception
+    {
+        int maxStreams = 2;
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>(1);
+                settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxStreams);
+                return settings;
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields(), 0);
+                stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                return null;
+            }
+        });
+
+        CountDownLatch settingsLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.countDown();
+            }
+        });
+        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
+
+        MetaData.Request request1 = newRequest("GET", new HttpFields());
+        FuturePromise<Stream> promise1 = new FuturePromise<>();
+        CountDownLatch exchangeLatch1 = new CountDownLatch(2);
+        session.newStream(new HeadersFrame(request1, null, false), promise1, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    exchangeLatch1.countDown();
+            }
+        });
+        Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
+
+        MetaData.Request request2 = newRequest("GET", new HttpFields());
+        FuturePromise<Stream> promise2 = new FuturePromise<>();
+        CountDownLatch exchangeLatch2 = new CountDownLatch(2);
+        session.newStream(new HeadersFrame(request2, null, false), promise2, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    exchangeLatch2.countDown();
+            }
+        });
+        Stream stream2 = promise2.get(5, TimeUnit.SECONDS);
+
+        // The third stream must not be created.
+        MetaData.Request request3 = newRequest("GET", new HttpFields());
+        CountDownLatch maxStreamsLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(request3, null, false), new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void failed(Throwable x)
+            {
+                if (x instanceof IllegalStateException)
+                    maxStreamsLatch.countDown();
+            }
+        }, new Stream.Listener.Adapter());
+
+        Assert.assertTrue(maxStreamsLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertEquals(2, session.getStreams().size());
+
+        // End the second stream.
+        stream2.data(new DataFrame(stream2.getId(), BufferUtil.EMPTY_BUFFER, true), new Callback()
+        {
+            @Override
+            public void succeeded()
+            {
+                exchangeLatch2.countDown();
+            }
+        });
+        Assert.assertTrue(exchangeLatch2.await(5, TimeUnit.SECONDS));
+        Assert.assertEquals(1, session.getStreams().size());
+
+        // Create a fourth stream.
+        MetaData.Request request4 = newRequest("GET", new HttpFields());
+        CountDownLatch exchangeLatch4 = new CountDownLatch(2);
+        session.newStream(new HeadersFrame(request4, null, true), new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream result)
+            {
+                exchangeLatch4.countDown();
+            }
+        }, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    exchangeLatch4.countDown();
+            }
+        });
+        Assert.assertTrue(exchangeLatch4.await(5, TimeUnit.SECONDS));
+        Assert.assertEquals(1, session.getStreams().size());
+
+        // End the first stream.
+        stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), new Callback()
+        {
+            @Override
+            public void succeeded()
+            {
+                exchangeLatch1.countDown();
+            }
+        });
+        Assert.assertTrue(exchangeLatch2.await(5, TimeUnit.SECONDS));
+        Assert.assertEquals(0, session.getStreams().size());
+    }
+
+    @Test
+    public void testCleanGoAwayDoesNotTriggerFailureNotification() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+                HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(response, Callback.NOOP);
+                // Close cleanly.
+                stream.getSession().close(ErrorCode.NO_ERROR.code, null, Callback.NOOP);
+                return null;
+            }
+        });
+
+        CountDownLatch closeLatch = new CountDownLatch(1);
+        CountDownLatch failureLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                closeLatch.countDown();
+            }
+
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+                failureLatch.countDown();
+            }
+        });
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame request = new HeadersFrame(metaData, null, true);
+        session.newStream(request, new Promise.Adapter<>(), new Stream.Listener.Adapter());
+
+        // Make sure onClose() is called.
+        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertFalse(failureLatch.await(1, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java
new file mode 100644
index 0000000..ef39cde
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/IdleTimeoutTest.java
@@ -0,0 +1,536 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+
+public class IdleTimeoutTest extends AbstractTest
+{
+    private final int idleTimeout = 1000;
+
+    @Test
+    public void testServerEnforcingIdleTimeout() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+        connector.setIdleTimeout(idleTimeout);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (session.isClosed() && ((HTTP2Session)session).isDisconnected())
+                    latch.countDown();
+            }
+        });
+
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter());
+
+        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+
+        sleep(1000);
+    }
+
+    @Test
+    public void testServerEnforcingIdleTimeoutWithUnrespondedStream() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                return null;
+            }
+        });
+        connector.setIdleTimeout(idleTimeout);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (session.isClosed() && ((HTTP2Session)session).isDisconnected())
+                    latch.countDown();
+            }
+        });
+
+        // The request is not replied, and the server should idle timeout.
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter());
+
+        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testServerNotEnforcingIdleTimeoutWithinCallback() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                // Stay in the callback for more than idleTimeout,
+                // but not for an integer number of idle timeouts,
+                // to avoid a race where the idle timeout fires
+                // again before we can send the headers to the client.
+                sleep(idleTimeout + idleTimeout / 2);
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+        connector.setIdleTimeout(idleTimeout);
+
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        Session session = newClient(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                closeLatch.countDown();
+            }
+        });
+
+        final CountDownLatch replyLatch = new CountDownLatch(1);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                replyLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS));
+
+        // Just make sure onClose() has never been called, but don't wait too much
+        Assert.assertFalse(closeLatch.await(idleTimeout / 2, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testClientEnforcingIdleTimeout() throws Exception
+    {
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (session.isClosed() && ((HTTP2Session)session).isDisconnected())
+                    closeLatch.countDown();
+            }
+        });
+        client.setIdleTimeout(idleTimeout);
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter());
+
+        Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertTrue(session.isClosed());
+    }
+
+    @Test
+    public void testClientEnforcingIdleTimeoutWithUnrespondedStream() throws Exception
+    {
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                return null;
+            }
+
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                if (session.isClosed() && ((HTTP2Session)session).isDisconnected())
+                    closeLatch.countDown();
+            }
+        });
+        client.setIdleTimeout(idleTimeout);
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter());
+
+        Assert.assertTrue(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testClientNotEnforcingIdleTimeoutWithinCallback() throws Exception
+    {
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+                closeLatch.countDown();
+            }
+        });
+        client.setIdleTimeout(idleTimeout);
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        final CountDownLatch replyLatch = new CountDownLatch(1);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+            }
+        }, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                // Stay in the callback for more than idleTimeout,
+                // but not for an integer number of idle timeouts,
+                // to avoid that the idle timeout fires again.
+                sleep(idleTimeout + idleTimeout / 2);
+                replyLatch.countDown();
+            }
+        });
+
+        Assert.assertFalse(closeLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testClientEnforcingStreamIdleTimeout() throws Exception
+    {
+        final int idleTimeout = 1000;
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                sleep(2 * idleTimeout);
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        final CountDownLatch timeoutLatch = new CountDownLatch(1);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(idleTimeout);
+            }
+        }, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                dataLatch.countDown();
+            }
+
+            @Override
+            public void onTimeout(Stream stream, Throwable x)
+            {
+                assertThat(x, instanceOf(TimeoutException.class));
+                timeoutLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(timeoutLatch.await(5, TimeUnit.SECONDS));
+        // We must not receive any DATA frame.
+        Assert.assertFalse(dataLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+        // Stream must be gone.
+        Assert.assertTrue(session.getStreams().isEmpty());
+        // Session must not be closed, nor disconnected.
+        Assert.assertFalse(session.isClosed());
+        Assert.assertFalse(((HTTP2Session)session).isDisconnected());
+    }
+
+    @Test
+    public void testServerEnforcingStreamIdleTimeout() throws Exception
+    {
+        final CountDownLatch timeoutLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(idleTimeout);
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onTimeout(Stream stream, Throwable x)
+                    {
+                        timeoutLatch.countDown();
+                    }
+                };
+            }
+        });
+
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        // Stream does not end here, but we won't send any DATA frame.
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onReset(Stream stream, ResetFrame frame)
+            {
+                resetLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(timeoutLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+        // Stream must be gone.
+        Assert.assertTrue(session.getStreams().isEmpty());
+        // Session must not be closed, nor disconnected.
+        Assert.assertFalse(session.isClosed());
+        Assert.assertFalse(((HTTP2Session)session).isDisconnected());
+    }
+
+    @Test
+    public void testStreamIdleTimeoutIsNotEnforcedWhenReceiving() throws Exception
+    {
+        final CountDownLatch timeoutLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(idleTimeout);
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onTimeout(Stream stream, Throwable x)
+                    {
+                        timeoutLatch.countDown();
+                    }
+                };
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(requestFrame, promise, new Stream.Listener.Adapter());
+        final Stream stream = promise.get(5, TimeUnit.SECONDS);
+
+        sleep(idleTimeout / 2);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), false), new Callback()
+        {
+            private int sends;
+
+            @Override
+            public void succeeded()
+            {
+                sleep(idleTimeout / 2);
+                final boolean last = ++sends == 2;
+                stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), last), !last ? this : new Callback.NonBlocking()
+                {
+                    @Override
+                    public void succeeded()
+                    {
+                        dataLatch.countDown();
+                    }
+                });
+            }
+        });
+
+        Assert.assertTrue(dataLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertFalse(timeoutLatch.await(0, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testStreamIdleTimeoutIsNotEnforcedWhenSending() throws Exception
+    {
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                return null;
+            }
+
+            @Override
+            public void onReset(Session session, ResetFrame frame)
+            {
+                resetLatch.countDown();
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> promise = new FuturePromise<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                stream.setIdleTimeout(idleTimeout);
+                super.succeeded(stream);
+            }
+        };
+        session.newStream(requestFrame, promise, new Stream.Listener.Adapter());
+        final Stream stream = promise.get(5, TimeUnit.SECONDS);
+
+        sleep(idleTimeout / 2);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), false), Callback.NOOP);
+        sleep(idleTimeout / 2);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), false), Callback.NOOP);
+        sleep(idleTimeout / 2);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1), true), Callback.NOOP);
+
+        Assert.assertFalse(resetLatch.await(0, TimeUnit.SECONDS));
+    }
+
+    private void sleep(long value)
+    {
+        try
+        {
+            TimeUnit.MILLISECONDS.sleep(value);
+        }
+        catch (InterruptedException x)
+        {
+            Assert.fail();
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java
new file mode 100644
index 0000000..d08a288
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PingTest.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client;
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.util.Callback;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PingTest extends AbstractTest
+{
+    @Test
+    public void testPing() throws Exception
+    {
+        start(new ServerSessionListener.Adapter());
+
+        final byte[] payload = new byte[8];
+        new Random().nextBytes(payload);
+        final CountDownLatch latch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onPing(Session session, PingFrame frame)
+            {
+                Assert.assertTrue(frame.isReply());
+                Assert.assertArrayEquals(payload, frame.getPayload());
+                latch.countDown();
+            }
+        });
+
+        PingFrame frame = new PingFrame(payload, false);
+        session.ping(frame, Callback.NOOP);
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java
new file mode 100644
index 0000000..94e3122
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java
@@ -0,0 +1,327 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.util.ArrayQueue;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PrefaceTest extends AbstractTest
+{
+    @Test
+    public void testServerPrefaceReplySentAfterClientPreface() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onAccept(Session session)
+            {
+                // Send the server preface from here.
+                session.settings(new SettingsFrame(new HashMap<>(), false), Callback.NOOP);
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                try
+                {
+                    // Wait for the server preface (a SETTINGS frame) to
+                    // arrive on the client, and for its reply to be sent.
+                    Thread.sleep(1000);
+                    return null;
+                }
+                catch (InterruptedException x)
+                {
+                    x.printStackTrace();
+                    return null;
+                }
+            }
+        });
+
+        CountDownLatch latch = new CountDownLatch(1);
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
+        session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testClientPrefaceReplySentAfterServerPreface() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>();
+                settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, 128);
+                return settings;
+            }
+
+            @Override
+            public void onPing(Session session, PingFrame frame)
+            {
+                session.close(ErrorCode.NO_ERROR.code, null, Callback.NOOP);
+            }
+        });
+
+        ByteBufferPool byteBufferPool = client.getByteBufferPool();
+        try (SocketChannel socket = SocketChannel.open())
+        {
+            socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
+
+            Generator generator = new Generator(byteBufferPool);
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            Map<Integer, Integer> clientSettings = new HashMap<>();
+            clientSettings.put(SettingsFrame.ENABLE_PUSH, 0);
+            generator.control(lease, new SettingsFrame(clientSettings, false));
+            // The PING frame just to make sure the client stops reading.
+            generator.control(lease, new PingFrame(true));
+
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            socket.write(buffers.toArray(new ByteBuffer[buffers.size()]));
+
+            Queue<SettingsFrame> settings = new ArrayQueue<>();
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onSettings(SettingsFrame frame)
+                {
+                    settings.offer(frame);
+                }
+            }, 4096, 8192);
+
+            ByteBuffer buffer = byteBufferPool.acquire(1024, true);
+            while (true)
+            {
+                int read = socket.read(buffer);
+                buffer.flip();
+                if (read < 0)
+                    break;
+                parser.parse(buffer);
+                buffer.clear();
+            }
+
+            Assert.assertEquals(2, settings.size());
+            SettingsFrame frame1 = settings.poll();
+            Assert.assertFalse(frame1.isReply());
+            SettingsFrame frame2 = settings.poll();
+            Assert.assertTrue(frame2.isReply());
+        }
+    }
+
+    @Test
+    public void testOnPrefaceNotifiedForStandardUpgrade() throws Exception
+    {
+        Integer maxConcurrentStreams = 128;
+        AtomicReference<CountDownLatch> serverPrefaceLatch = new AtomicReference<>(new CountDownLatch(1));
+        AtomicReference<CountDownLatch> serverSettingsLatch = new AtomicReference<>(new CountDownLatch(1));
+        HttpConfiguration config = new HttpConfiguration();
+        prepareServer(new HttpConnectionFactory(config), new HTTP2CServerConnectionFactory(config)
+        {
+            @Override
+            protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint)
+            {
+                return new ServerSessionListener.Adapter()
+                {
+                    @Override
+                    public Map<Integer, Integer> onPreface(Session session)
+                    {
+                        Map<Integer, Integer> serverSettings = new HashMap<>();
+                        serverSettings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams);
+                        serverPrefaceLatch.get().countDown();
+                        return serverSettings;
+                    }
+
+                    @Override
+                    public void onSettings(Session session, SettingsFrame frame)
+                    {
+                        serverSettingsLatch.get().countDown();
+                    }
+
+                    @Override
+                    public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+                    {
+                        MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+                        stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                        return null;
+                    }
+                };
+            }
+        });
+        server.start();
+
+        ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+        try (SocketChannel socket = SocketChannel.open())
+        {
+            socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
+
+            String upgradeRequest = "" +
+                    "GET /one HTTP/1.1\r\n" +
+                    "Host: localhost\r\n" +
+                    "Connection: Upgrade, HTTP2-Settings\r\n" +
+                    "Upgrade: h2c\r\n" +
+                    "HTTP2-Settings: \r\n" +
+                    "\r\n";
+            ByteBuffer upgradeBuffer = ByteBuffer.wrap(upgradeRequest.getBytes(StandardCharsets.ISO_8859_1));
+            socket.write(upgradeBuffer);
+
+            // Make sure onPreface() is called on server.
+            Assert.assertTrue(serverPrefaceLatch.get().await(5, TimeUnit.SECONDS));
+            Assert.assertTrue(serverSettingsLatch.get().await(5, TimeUnit.SECONDS));
+
+            // The 101 response is the reply to the client preface SETTINGS frame.
+            ByteBuffer buffer = byteBufferPool.acquire(1024, true);
+            http1: while (true)
+            {
+                buffer.clear();
+                int read = socket.read(buffer);
+                buffer.flip();
+                if (read < 0)
+                    Assert.fail();
+
+                int crlfs = 0;
+                while (buffer.hasRemaining())
+                {
+                    byte b = buffer.get();
+                    if (b == '\r' || b == '\n')
+                        ++crlfs;
+                    else
+                        crlfs = 0;
+                    if (crlfs == 4)
+                        break http1;
+                }
+            }
+
+            // Reset the latches on server.
+            serverPrefaceLatch.set(new CountDownLatch(1));
+            serverSettingsLatch.set(new CountDownLatch(1));
+
+            // After the 101, the client must send the connection preface.
+            Generator generator = new Generator(byteBufferPool);
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            Map<Integer, Integer> clientSettings = new HashMap<>();
+            clientSettings.put(SettingsFrame.ENABLE_PUSH, 1);
+            generator.control(lease, new SettingsFrame(clientSettings, false));
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            socket.write(buffers.toArray(new ByteBuffer[buffers.size()]));
+
+            // However, we should not call onPreface() again.
+            Assert.assertFalse(serverPrefaceLatch.get().await(1, TimeUnit.SECONDS));
+            // Although we should notify of the SETTINGS frame.
+            Assert.assertTrue(serverSettingsLatch.get().await(5, TimeUnit.SECONDS));
+
+            CountDownLatch clientSettingsLatch = new CountDownLatch(1);
+            AtomicBoolean responded = new AtomicBoolean();
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onSettings(SettingsFrame frame)
+                {
+                    if (frame.isReply())
+                        return;
+                    Assert.assertEquals(maxConcurrentStreams, frame.getSettings().get(SettingsFrame.MAX_CONCURRENT_STREAMS));
+                    clientSettingsLatch.countDown();
+                }
+
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    if (frame.isEndStream())
+                        responded.set(true);
+                }
+            }, 4096, 8192);
+
+            // HTTP/2 parsing.
+            while (true)
+            {
+                parser.parse(buffer);
+                if (responded.get())
+                    break;
+
+                buffer.clear();
+                int read = socket.read(buffer);
+                buffer.flip();
+                if (read < 0)
+                    Assert.fail();
+            }
+
+            Assert.assertTrue(clientSettingsLatch.await(5, TimeUnit.SECONDS));
+        }
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java
new file mode 100644
index 0000000..01cb6b5
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PriorityTest.java
@@ -0,0 +1,184 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PriorityTest extends AbstractTest
+{
+    @Test
+    public void testPriorityBeforeHeaders() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        int streamId = session.priority(new PriorityFrame(0, 13, false), Callback.NOOP);
+        Assert.assertTrue(streamId > 0);
+
+        CountDownLatch latch = new CountDownLatch(2);
+        MetaData metaData = newRequest("GET", new HttpFields());
+        HeadersFrame headersFrame = new HeadersFrame(streamId, metaData, null, true);
+        session.newStream(headersFrame, new Promise.Adapter<Stream>()
+        {
+            @Override
+            public void succeeded(Stream result)
+            {
+                Assert.assertEquals(streamId, result.getId());
+                latch.countDown();
+            }
+        }, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPriorityAfterHeaders() throws Exception
+    {
+        CountDownLatch beforeRequests = new CountDownLatch(1);
+        CountDownLatch afterRequests = new CountDownLatch(2);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                try
+                {
+                    beforeRequests.await(5, TimeUnit.SECONDS);
+                    MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                    HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                    stream.headers(responseFrame, Callback.NOOP);
+                    afterRequests.countDown();
+                    return null;
+                }
+                catch (InterruptedException x)
+                {
+                    x.printStackTrace();
+                    return null;
+                }
+            }
+        });
+
+        CountDownLatch responses = new CountDownLatch(2);
+        Stream.Listener.Adapter listener = new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    responses.countDown();
+            }
+        };
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData metaData1 = newRequest("GET", "/one", new HttpFields());
+        HeadersFrame headersFrame1 = new HeadersFrame(metaData1, null, true);
+        FuturePromise<Stream> promise1 = new FuturePromise<>();
+        session.newStream(headersFrame1, promise1, listener);
+        Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
+
+        MetaData metaData2 = newRequest("GET", "/two", new HttpFields());
+        HeadersFrame headersFrame2 = new HeadersFrame(metaData2, null, true);
+        FuturePromise<Stream> promise2 = new FuturePromise<>();
+        session.newStream(headersFrame2, promise2, listener);
+        Stream stream2 = promise2.get(5, TimeUnit.SECONDS);
+
+        int streamId = session.priority(new PriorityFrame(stream1.getId(), stream2.getId(), 13, false), Callback.NOOP);
+        Assert.assertEquals(stream1.getId(), streamId);
+
+        // Give time to the PRIORITY frame to arrive to server.
+        Thread.sleep(1000);
+        beforeRequests.countDown();
+
+        Assert.assertTrue(afterRequests.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(responses.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testHeadersWithPriority() throws Exception
+    {
+        PriorityFrame priorityFrame = new PriorityFrame(13, 200, true);
+        CountDownLatch latch = new CountDownLatch(2);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                PriorityFrame priority = frame.getPriority();
+                Assert.assertNotNull(priority);
+                Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId());
+                Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight());
+                Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive());
+                latch.countDown();
+
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData metaData = newRequest("GET", "/one", new HttpFields());
+        HeadersFrame headersFrame = new HeadersFrame(metaData, priorityFrame, true);
+        session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java
new file mode 100644
index 0000000..1ec1566
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java
@@ -0,0 +1,121 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.ProxyConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProxyProtocolTest
+{
+    private Server server;
+    private ServerConnector connector;
+    private HTTP2Client client;
+
+    public void startServer(Handler handler) throws Exception
+    {
+        server = new Server();
+        HttpConfiguration configuration = new HttpConfiguration();
+        connector = new ServerConnector(server, new ProxyConnectionFactory(), new HTTP2CServerConnectionFactory(configuration));
+        server.addConnector(connector);
+        server.setHandler(handler);
+
+        client = new HTTP2Client();
+        server.addBean(client, true);
+
+        server.start();
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (server != null)
+            server.stop();
+    }
+
+    @Test
+    public void test_PROXY_GET() throws Exception
+    {
+        startServer(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+            }
+        });
+
+        String request1 = "PROXY TCP4 1.2.3.4 5.6.7.8 1111 2222\r\n";
+        SocketChannel channel = SocketChannel.open();
+        channel.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
+        channel.write(ByteBuffer.wrap(request1.getBytes(StandardCharsets.UTF_8)));
+
+        FuturePromise<Session> promise = new FuturePromise<>();
+        client.accept(null, channel, new Session.Listener.Adapter(), promise);
+        Session session = promise.get(5, TimeUnit.SECONDS);
+
+        HttpFields fields = new HttpFields();
+        String uri = "http://localhost:" + connector.getLocalPort() + "/";
+        MetaData.Request metaData = new MetaData.Request("GET", new HttpURI(uri), HttpVersion.HTTP_2, fields);
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        CountDownLatch latch = new CountDownLatch(1);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+                if (frame.isEndStream())
+                    latch.countDown();
+            }
+        });
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java
new file mode 100644
index 0000000..629d593
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyTest.java
@@ -0,0 +1,196 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.proxy.AsyncProxyServlet;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ProxyTest
+{
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+    private HTTP2Client client;
+    private Server proxy;
+    private ServerConnector proxyConnector;
+    private Server server;
+    private ServerConnector serverConnector;
+
+    private void startServer(HttpServlet servlet) throws Exception
+    {
+        QueuedThreadPool serverPool = new QueuedThreadPool();
+        serverPool.setName("server");
+        server = new Server(serverPool);
+        serverConnector = new ServerConnector(server);
+        server.addConnector(serverConnector);
+
+        ServletContextHandler appCtx = new ServletContextHandler(server, "/", true, false);
+        ServletHolder appServletHolder = new ServletHolder(servlet);
+        appCtx.addServlet(appServletHolder, "/*");
+
+        server.start();
+    }
+
+    private void startProxy(HttpServlet proxyServlet, Map<String, String> initParams) throws Exception
+    {
+        QueuedThreadPool proxyPool = new QueuedThreadPool();
+        proxyPool.setName("proxy");
+        proxy = new Server(proxyPool);
+
+        HttpConfiguration configuration = new HttpConfiguration();
+        configuration.setSendDateHeader(false);
+        configuration.setSendServerVersion(false);
+        String value = initParams.get("outputBufferSize");
+        if (value != null)
+            configuration.setOutputBufferSize(Integer.valueOf(value));
+        proxyConnector = new ServerConnector(proxy, new HTTP2ServerConnectionFactory(configuration));
+        proxy.addConnector(proxyConnector);
+
+        ServletContextHandler proxyContext = new ServletContextHandler(proxy, "/", true, false);
+        ServletHolder proxyServletHolder = new ServletHolder(proxyServlet);
+        proxyServletHolder.setInitParameters(initParams);
+        proxyContext.addServlet(proxyServletHolder, "/*");
+
+        proxy.start();
+    }
+
+    private void startClient() throws Exception
+    {
+        QueuedThreadPool clientExecutor = new QueuedThreadPool();
+        clientExecutor.setName("client");
+        client = new HTTP2Client();
+        client.setExecutor(clientExecutor);
+        client.start();
+    }
+
+    private Session newClient(Session.Listener listener) throws Exception
+    {
+        String host = "localhost";
+        int port = proxyConnector.getLocalPort();
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        FuturePromise<Session> promise = new FuturePromise<>();
+        client.connect(address, listener, promise);
+        return promise.get(5, TimeUnit.SECONDS);
+    }
+
+    private MetaData.Request newRequest(String method, String path, HttpFields fields)
+    {
+        String host = "localhost";
+        int port = proxyConnector.getLocalPort();
+        String authority = host + ":" + port;
+        return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields);
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        client.stop();
+        proxy.stop();
+        server.stop();
+    }
+
+    @Test
+    public void testServerBigDownloadSlowClient() throws Exception
+    {
+        final CountDownLatch serverLatch = new CountDownLatch(1);
+        final byte[] content = new byte[1024 * 1024];
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                response.getOutputStream().write(content);
+                serverLatch.countDown();
+            }
+        });
+        Map<String, String> params = new HashMap<>();
+        params.put("proxyTo", "http://localhost:" + serverConnector.getLocalPort());
+        startProxy(new AsyncProxyServlet.Transparent()
+        {
+            @Override
+            protected void sendProxyRequest(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest)
+            {
+                proxyRequest.version(HttpVersion.HTTP_1_1);
+                super.sendProxyRequest(clientRequest, proxyResponse, proxyRequest);
+            }
+        }, params);
+        startClient();
+
+        final CountDownLatch clientLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter());
+        MetaData.Request metaData = newRequest("GET", "/", new HttpFields());
+        HeadersFrame frame = new HeadersFrame(metaData, null, true);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                try
+                {
+                    TimeUnit.MILLISECONDS.sleep(1);
+                    callback.succeeded();
+                    if (frame.isEndStream())
+                        clientLatch.countDown();
+                }
+                catch (InterruptedException x)
+                {
+                    callback.failed(x);
+                }
+            }
+        });
+
+        Assert.assertTrue(serverLatch.await(15, TimeUnit.SECONDS));
+        Assert.assertTrue(clientLatch.await(15, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java
new file mode 100644
index 0000000..53a0c8e
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PushCacheFilterTest.java
@@ -0,0 +1,727 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.EnumSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlets.PushCacheFilter;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PushCacheFilterTest extends AbstractTest
+{
+    @Override
+    protected void customizeContext(ServletContextHandler context)
+    {
+        context.addFilter(PushCacheFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
+    }
+
+    @Test
+    public void testPush() throws Exception
+    {
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.png";
+        final byte[] secondaryData = "SECONDARY".getBytes("UTF-8");
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                String requestURI = req.getRequestURI();
+                ServletOutputStream output = resp.getOutputStream();
+                if (requestURI.endsWith(primaryResource))
+                    output.print("<html><head></head><body>PRIMARY</body></html>");
+                else if (requestURI.endsWith(secondaryResource))
+                    output.write(secondaryData);
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary and secondary resource to build the cache.
+        final String referrerURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, referrerURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onData(Stream stream, DataFrame frame, Callback callback)
+                        {
+                            warmupLatch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        // Request again the primary resource, we should get the secondary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        callback.succeeded();
+                        if (frame.isEndStream())
+                            pushLatch.countDown();
+                    }
+                };
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+        });
+        Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPushReferrerNoPath() throws Exception
+    {
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.png";
+        final byte[] secondaryData = "SECONDARY".getBytes("UTF-8");
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                String requestURI = req.getRequestURI();
+                ServletOutputStream output = resp.getOutputStream();
+                if (requestURI.endsWith(primaryResource))
+                    output.print("<html><head></head><body>PRIMARY</body></html>");
+                else if (requestURI.endsWith(secondaryResource))
+                    output.write(secondaryData);
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary and secondary resource to build the cache.
+        // The referrerURI does not point to the primary resource, so there will be no
+        // resource association with the primary resource and therefore won't be pushed.
+        final String referrerURI = "http://localhost:" + connector.getLocalPort();
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, referrerURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onData(Stream stream, DataFrame frame, Callback callback)
+                        {
+                            warmupLatch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        // Request again the primary resource, we should not get the secondary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        callback.succeeded();
+                        if (frame.isEndStream())
+                            pushLatch.countDown();
+                    }
+                };
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+        });
+        Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPushIsReset() throws Exception
+    {
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.png";
+        final byte[] secondaryData = "SECONDARY".getBytes("UTF-8");
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                String requestURI = req.getRequestURI();
+                ServletOutputStream output = resp.getOutputStream();
+                if (requestURI.endsWith(primaryResource))
+                    output.print("<html><head></head><body>PRIMARY</body></html>");
+                else if (requestURI.endsWith(secondaryResource))
+                    output.write(secondaryData);
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary and secondary resource to build the cache.
+        final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, primaryURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onData(Stream stream, DataFrame frame, Callback callback)
+                        {
+                            warmupLatch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        // Request again the primary resource, we should get the secondary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                // Reset the stream as soon as we see the push.
+                ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.REFUSED_STREAM_ERROR.code);
+                stream.reset(resetFrame, Callback.NOOP);
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        pushLatch.countDown();
+                    }
+                };
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+        });
+        // We should not receive pushed data that we reset.
+        Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+
+        // Make sure the session is sane by requesting the secondary resource.
+        HttpFields secondaryFields = new HttpFields();
+        secondaryFields.put(HttpHeader.REFERER, primaryURI);
+        MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+        final CountDownLatch secondaryResponseLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                if (frame.isEndStream())
+                    secondaryResponseLatch.countDown();
+            }
+        });
+        Assert.assertTrue(secondaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPushWithoutPrimaryResponseContent() throws Exception
+    {
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.png";
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                String requestURI = request.getRequestURI();
+                final ServletOutputStream output = response.getOutputStream();
+                if (requestURI.endsWith(secondaryResource))
+                    output.write("SECONDARY".getBytes(StandardCharsets.UTF_8));
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary and secondary resource to build the cache.
+        final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, primaryURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onData(Stream stream, DataFrame frame, Callback callback)
+                        {
+                            warmupLatch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        Thread.sleep(1000);
+
+        // Request again the primary resource, we should get the secondary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        callback.succeeded();
+                        if (frame.isEndStream())
+                            pushLatch.countDown();
+                    }
+                };
+            }
+        });
+        Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testRecursivePush() throws Exception
+    {
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.css";
+        final String tertiaryResource = "/tertiary.png";
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                String requestURI = request.getRequestURI();
+                final ServletOutputStream output = response.getOutputStream();
+                if (requestURI.endsWith(primaryResource))
+                    output.print("<html><head></head><body>PRIMARY</body></html>");
+                else if (requestURI.endsWith(secondaryResource))
+                    output.print("body { background-image: url(\"" + tertiaryResource + "\"); }");
+                if (requestURI.endsWith(tertiaryResource))
+                    output.write("TERTIARY".getBytes(StandardCharsets.UTF_8));
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary, secondary and tertiary resource to build the cache.
+        final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    final String secondaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + secondaryResource;
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, primaryURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onData(Stream stream, DataFrame frame, Callback callback)
+                        {
+                            callback.succeeded();
+                            if (frame.isEndStream())
+                            {
+                                // Request for the tertiary resource.
+                                HttpFields tertiaryFields = new HttpFields();
+                                tertiaryFields.put(HttpHeader.REFERER, secondaryURI);
+                                MetaData.Request tertiaryRequest = newRequest("GET", tertiaryResource, tertiaryFields);
+                                session.newStream(new HeadersFrame(tertiaryRequest, null, true), new Promise.Adapter<>(), new Adapter()
+                                {
+                                    @Override
+                                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                                    {
+                                        if (frame.isEndStream())
+                                            warmupLatch.countDown();
+                                    }
+                                });
+                            }
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        Thread.sleep(1000);
+
+        // Request again the primary resource, we should get the secondary and tertiary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(2);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        callback.succeeded();
+                        if (frame.isEndStream())
+                            pushLatch.countDown();
+                    }
+
+                    @Override
+                    public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+                    {
+                        return this;
+                    }
+                };
+            }
+        });
+        Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testSelfPush() throws Exception
+    {
+        // The test case is that of a login page, for example.
+        // When the user sends the credentials to the login page,
+        // the login may fail and redirect to the same login page,
+        // perhaps with different query parameters.
+        // In this case a request for the login page will push
+        // the login page itself, which will generate the pushed
+        // request for the login page, which will push the login
+        // page itself, etc. which is not the desired behavior.
+
+        final String primaryResource = "/login.html";
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                ServletOutputStream output = response.getOutputStream();
+                String credentials = request.getParameter("credentials");
+                if (credentials == null)
+                {
+                    output.print("<html><head></head><body>LOGIN</body></html>");
+                }
+                else if ("secret".equals(credentials))
+                {
+                    output.print("<html><head></head><body>OK</body></html>");
+                }
+                else
+                {
+                    response.setStatus(HttpStatus.TEMPORARY_REDIRECT_307);
+                    response.setHeader(HttpHeader.LOCATION.asString(), primaryResource);
+                }
+            }
+        });
+        final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Login with the wrong credentials, causing a redirect to self.
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource + "?credentials=wrong", primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                {
+                    MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                    if (response.getStatus() == HttpStatus.TEMPORARY_REDIRECT_307)
+                    {
+                        // Follow the redirect.
+                        String location = response.getFields().get(HttpHeader.LOCATION);
+                        HttpFields redirectFields = new HttpFields();
+                        redirectFields.put(HttpHeader.REFERER, primaryURI);
+                        MetaData.Request redirectRequest = newRequest("GET", location, redirectFields);
+                        session.newStream(new HeadersFrame(redirectRequest, null, true), new Promise.Adapter<>(), new Adapter()
+                        {
+                            @Override
+                            public void onData(Stream stream, DataFrame frame, Callback callback)
+                            {
+                                if (frame.isEndStream())
+                                    warmupLatch.countDown();
+                            }
+                        });
+                    }
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        Thread.sleep(1000);
+
+        // Login with the right credentials, there must be no push.
+        primaryRequest = newRequest("GET", primaryResource + "?credentials=secret", primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                pushLatch.countDown();
+                return null;
+            }
+        });
+        Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPushWithQueryParameters() throws Exception
+    {
+        String name = "foo";
+        String value = "bar";
+        final String primaryResource = "/primary.html";
+        final String secondaryResource = "/secondary.html?" + name + "=" + value;
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                String requestURI = request.getRequestURI();
+                if (requestURI.endsWith(primaryResource))
+                {
+                    response.setStatus(HttpStatus.OK_200);
+                }
+                else if (requestURI.endsWith(secondaryResource))
+                {
+                    String param = request.getParameter(name);
+                    if (param == null)
+                        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
+                    else
+                        response.setStatus(HttpStatus.OK_200);
+                }
+            }
+        });
+
+        final Session session = newClient(new Session.Listener.Adapter());
+
+        // Request for the primary and secondary resource to build the cache.
+        final String primaryURI = "http://localhost:" + connector.getLocalPort() + servletPath + primaryResource;
+        HttpFields primaryFields = new HttpFields();
+        MetaData.Request primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch warmupLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                {
+                    // Request for the secondary resource.
+                    HttpFields secondaryFields = new HttpFields();
+                    secondaryFields.put(HttpHeader.REFERER, primaryURI);
+                    MetaData.Request secondaryRequest = newRequest("GET", secondaryResource, secondaryFields);
+                    session.newStream(new HeadersFrame(secondaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                    {
+                        @Override
+                        public void onHeaders(Stream stream, HeadersFrame frame)
+                        {
+                            if (frame.isEndStream())
+                                warmupLatch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+        Assert.assertTrue(warmupLatch.await(5, TimeUnit.SECONDS));
+
+        Thread.sleep(1000);
+
+        // Request again the primary resource, we should get the secondary resource pushed.
+        primaryRequest = newRequest("GET", primaryResource, primaryFields);
+        final CountDownLatch primaryResponseLatch = new CountDownLatch(1);
+        final CountDownLatch pushLatch = new CountDownLatch(1);
+        session.newStream(new HeadersFrame(primaryRequest, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                MetaData metaData = frame.getMetaData();
+                Assert.assertTrue(metaData instanceof MetaData.Request);
+                MetaData.Request pushedRequest = (MetaData.Request)metaData;
+                Assert.assertEquals(servletPath + secondaryResource, pushedRequest.getURI().getPathQuery());
+                return new Adapter()
+                {
+                    @Override
+                    public void onHeaders(Stream stream, HeadersFrame frame)
+                    {
+                        if (frame.isEndStream())
+                        {
+                            MetaData.Response response = (MetaData.Response)frame.getMetaData();
+                            if (response.getStatus() == HttpStatus.OK_200)
+                                pushLatch.countDown();
+                        }
+                    }
+                };
+            }
+
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    primaryResponseLatch.countDown();
+            }
+        });
+        Assert.assertTrue(pushLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(primaryResponseLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java
new file mode 100644
index 0000000..1b6c60a
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java
@@ -0,0 +1,123 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SessionFailureTest extends AbstractTest
+{
+    @Test
+    public void testWrongPreface() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+                latch.countDown();
+            }
+        });
+
+        try (Socket socket = new Socket("localhost", connector.getLocalPort()))
+        {
+            // Preface starts with byte 0x50, send something different.
+            OutputStream output = socket.getOutputStream();
+            output.write(0x0);
+            output.flush();
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
+            // The server will reply with a GOAWAY frame, and then shutdown.
+            // Read until EOF.
+            socket.setSoTimeout(1000);
+            InputStream input = socket.getInputStream();
+            while (true)
+            {
+                if (input.read() < 0)
+                    break;
+            }
+        }
+    }
+
+    @Test
+    public void testWriteFailure() throws Exception
+    {
+        final CountDownLatch writeLatch = new CountDownLatch(1);
+        final CountDownLatch serverFailureLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                // Forcibly close the connection.
+                ((HTTP2Session)stream.getSession()).getEndPoint().close();
+                // Now try to write something: it should fail.
+                stream.headers(frame, new Callback()
+                {
+                    @Override
+                    public void failed(Throwable x)
+                    {
+                        writeLatch.countDown();
+                    }
+                });
+                return null;
+            }
+
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+                serverFailureLatch.countDown();
+            }
+        });
+
+        final CountDownLatch clientFailureLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+                clientFailureLatch.countDown();
+            }
+        });
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        Promise<Stream> promise = new Promise.Adapter<>();
+        session.newStream(frame, promise, null);
+
+        Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(serverFailureLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(clientFailureLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertFalse(((HTTP2Session)session).getEndPoint().isOpen());
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java
new file mode 100644
index 0000000..525e16f
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SimpleFlowControlStrategyTest.java
@@ -0,0 +1,31 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client;
+
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.SimpleFlowControlStrategy;
+
+public class SimpleFlowControlStrategyTest extends FlowControlStrategyTest
+{
+    @Override
+    protected FlowControlStrategy newFlowControlStrategy()
+    {
+        return new SimpleFlowControlStrategy();
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java
new file mode 100644
index 0000000..72a6392
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java
@@ -0,0 +1,345 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.HTTP2Stream;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.Promise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StreamCloseTest extends AbstractTest
+{
+    @Test
+    public void testRequestClosedRemotelyClosesStream() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                Assert.assertTrue(((HTTP2Stream)stream).isRemotelyClosed());
+                latch.countDown();
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, null);
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+        Assert.assertTrue(((HTTP2Stream)stream).isLocallyClosed());
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testRequestClosedResponseClosedClosesStream() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(2);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(final Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(response, new Callback()
+                {
+                    @Override
+                    public void succeeded()
+                    {
+                        Assert.assertTrue(stream.isClosed());
+                        Assert.assertEquals(0, stream.getSession().getStreams().size());
+                        latch.countDown();
+                    }
+                });
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                // The stream promise may not be notified yet here.
+                latch.countDown();
+            }
+        });
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(stream.isClosed());
+    }
+
+    @Test
+    public void testRequestDataClosedResponseDataClosedClosesStream() throws Exception
+    {
+        final CountDownLatch serverDataLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame response = new HeadersFrame(stream.getId(), metaData, null, false);
+                stream.headers(response, Callback.NOOP);
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(final Stream stream, DataFrame frame, final Callback callback)
+                    {
+                        Assert.assertTrue(((HTTP2Stream)stream).isRemotelyClosed());
+                        stream.data(frame, new Callback()
+                        {
+                            @Override
+                            public void succeeded()
+                            {
+                                Assert.assertTrue(stream.isClosed());
+                                Assert.assertEquals(0, stream.getSession().getStreams().size());
+                                callback.succeeded();
+                                serverDataLatch.countDown();
+                            }
+                        });
+                    }
+                };
+            }
+        });
+
+        final CountDownLatch completeLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter());
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, false);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        session.newStream(frame, promise, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                // The sent data callback may not be notified yet here.
+                completeLatch.countDown();
+            }
+        });
+        final Stream stream = promise.get(5, TimeUnit.SECONDS);
+        Assert.assertFalse(stream.isClosed());
+        Assert.assertFalse(((HTTP2Stream)stream).isLocallyClosed());
+
+        final CountDownLatch clientDataLatch = new CountDownLatch(1);
+        stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(new byte[512]), true), new Callback()
+        {
+            @Override
+            public void succeeded()
+            {
+                // Here the stream may be just locally closed or fully closed.
+                clientDataLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(clientDataLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(stream.isClosed());
+        Assert.assertEquals(0, stream.getSession().getStreams().size());
+    }
+
+    @Test
+    public void testPushedStreamIsClosed() throws Exception
+    {
+        final CountDownLatch serverLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", new HttpFields()));
+                stream.push(pushFrame, new Promise.Adapter<Stream>()
+                {
+                    @Override
+                    public void succeeded(final Stream pushedStream)
+                    {
+                        // When created, pushed stream must be implicitly remotely closed.
+                        Assert.assertTrue(((HTTP2Stream)pushedStream).isRemotelyClosed());
+                        // Send some data with endStream = true.
+                        pushedStream.data(new DataFrame(pushedStream.getId(), ByteBuffer.allocate(16), true), new Callback()
+                        {
+                            @Override
+                            public void succeeded()
+                            {
+                                Assert.assertTrue(pushedStream.isClosed());
+                                serverLatch.countDown();
+                            }
+                        });
+                    }
+                }, new Stream.Listener.Adapter());
+                HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()), null, true);
+                stream.headers(response, Callback.NOOP);
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        final CountDownLatch clientLatch = new CountDownLatch(1);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(Stream pushedStream, PushPromiseFrame frame)
+            {
+                Assert.assertTrue(((HTTP2Stream)pushedStream).isLocallyClosed());
+                return new Adapter()
+                {
+                    @Override
+                    public void onData(Stream pushedStream, DataFrame frame, Callback callback)
+                    {
+                        Assert.assertTrue(pushedStream.isClosed());
+                        callback.succeeded();
+                        clientLatch.countDown();
+                    }
+                };
+            }
+        });
+
+        Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testPushedStreamResetIsClosed() throws Exception
+    {
+        final CountDownLatch serverLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(final Stream stream, HeadersFrame frame)
+            {
+                PushPromiseFrame pushFrame = new PushPromiseFrame(stream.getId(), 0, newRequest("GET", new HttpFields()));
+                stream.push(pushFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onReset(Stream pushedStream, ResetFrame frame)
+                    {
+                        Assert.assertTrue(pushedStream.isReset());
+                        Assert.assertTrue(pushedStream.isClosed());
+                        HeadersFrame response = new HeadersFrame(stream.getId(), new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields()), null, true);
+                        stream.headers(response, Callback.NOOP);
+                        serverLatch.countDown();
+                    }
+                });
+                return null;
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+        HeadersFrame frame = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        final CountDownLatch clientLatch = new CountDownLatch(2);
+        session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public Stream.Listener onPush(final Stream pushedStream, PushPromiseFrame frame)
+            {
+                pushedStream.reset(new ResetFrame(pushedStream.getId(), ErrorCode.REFUSED_STREAM_ERROR.code), new Callback()
+                {
+                    @Override
+                    public void succeeded()
+                    {
+                        Assert.assertTrue(pushedStream.isReset());
+                        Assert.assertTrue(pushedStream.isClosed());
+                        clientLatch.countDown();
+                    }
+                });
+                return null;
+            }
+
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                clientLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testFailedSessionClosesIdleStream() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final List<Stream> streams = new ArrayList<>();
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                streams.add(stream);
+                MetaData.Request request = (MetaData.Request)frame.getMetaData();
+                if ("GET".equals(request.getMethod()))
+                {
+                    ((HTTP2Session)stream.getSession()).getEndPoint().close();
+                    // Try to write something to force an error.
+                    stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(1024), true), Callback.NOOP);
+                }
+                return null;
+            }
+
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+                Assert.assertEquals(0, session.getStreams().size());
+                for (Stream stream : streams)
+                    Assert.assertTrue(stream.isClosed());
+                latch.countDown();
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        // First stream will be idle on server.
+        HeadersFrame request1 = new HeadersFrame(newRequest("HEAD", new HttpFields()), null, true);
+        session.newStream(request1, new Promise.Adapter<>(), new Stream.Listener.Adapter());
+
+        // Second stream will fail on server.
+        HeadersFrame request2 = new HeadersFrame(newRequest("GET", new HttpFields()), null, true);
+        session.newStream(request2, new Promise.Adapter<>(), new Stream.Listener.Adapter());
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java
new file mode 100644
index 0000000..b81e9a2
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCountTest.java
@@ -0,0 +1,188 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StreamCountTest extends AbstractTest
+{
+    @Test
+    public void testServerAllowsOneStreamEnforcedByClient() throws Exception
+    {
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                Map<Integer, Integer> settings = new HashMap<>();
+                settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, 1);
+                return settings;
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        if (frame.isEndStream())
+                        {
+                            HttpFields fields = new HttpFields();
+                            MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
+                            stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback);
+                        }
+                    }
+                };
+            }
+        });
+
+        final CountDownLatch settingsLatch = new CountDownLatch(1);
+        Session session = newClient(new Session.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+                settingsLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame1 = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
+        final CountDownLatch responseLatch = new CountDownLatch(1);
+        session.newStream(frame1, streamPromise1, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    responseLatch.countDown();
+            }
+        });
+        Stream stream1 = streamPromise1.get(5, TimeUnit.SECONDS);
+
+        HeadersFrame frame2 = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise2 = new FuturePromise<>();
+        session.newStream(frame2, streamPromise2, new Stream.Listener.Adapter());
+
+        try
+        {
+            streamPromise2.get(5, TimeUnit.SECONDS);
+            Assert.fail();
+        }
+        catch (ExecutionException x)
+        {
+            // Expected
+        }
+
+        stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), Callback.NOOP);
+        Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testServerAllowsOneStreamEnforcedByServer() throws Exception
+    {
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                HTTP2Session session = (HTTP2Session)stream.getSession();
+                session.setMaxRemoteStreams(1);
+
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        if (frame.isEndStream())
+                        {
+                            HttpFields fields = new HttpFields();
+                            MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, fields);
+                            stream.headers(new HeadersFrame(stream.getId(), metaData, null, true), callback);
+                        }
+                    }
+                };
+            }
+        });
+
+        Session session = newClient(new Session.Listener.Adapter());
+
+        HttpFields fields = new HttpFields();
+        MetaData.Request metaData = newRequest("GET", fields);
+        HeadersFrame frame1 = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise1 = new FuturePromise<>();
+        final CountDownLatch responseLatch = new CountDownLatch(1);
+        session.newStream(frame1, streamPromise1, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                if (frame.isEndStream())
+                    responseLatch.countDown();
+            }
+        });
+
+        Stream stream1 = streamPromise1.get(5, TimeUnit.SECONDS);
+
+        HeadersFrame frame2 = new HeadersFrame(metaData, null, false);
+        FuturePromise<Stream> streamPromise2 = new FuturePromise<>();
+        session.newStream(frame2, streamPromise2, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onReset(Stream stream, ResetFrame frame)
+            {
+                resetLatch.countDown();
+            }
+        });
+
+        streamPromise2.get(5, TimeUnit.SECONDS);
+        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+
+        stream1.data(new DataFrame(stream1.getId(), BufferUtil.EMPTY_BUFFER, true), Callback.NOOP);
+        Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java
new file mode 100644
index 0000000..ba19238
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java
@@ -0,0 +1,351 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.server.HttpOutput;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FutureCallback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StreamResetTest extends AbstractTest
+{
+    @Test
+    public void testStreamSendingResetIsRemoved() throws Exception
+    {
+        start(new ServerSessionListener.Adapter());
+
+        Session client = newClient(new Session.Listener.Adapter());
+        MetaData.Request request = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(request, null, false);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+        ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
+        FutureCallback resetCallback = new FutureCallback();
+        stream.reset(resetFrame, resetCallback);
+        resetCallback.get(5, TimeUnit.SECONDS);
+        // After reset the stream should be gone.
+        Assert.assertEquals(0, client.getStreams().size());
+    }
+
+    @Test
+    public void testStreamReceivingResetIsRemoved() throws Exception
+    {
+        final AtomicReference<Stream> streamRef = new AtomicReference<>();
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onReset(Stream stream, ResetFrame frame)
+                    {
+                        Assert.assertNotNull(stream);
+                        Assert.assertTrue(stream.isReset());
+                        streamRef.set(stream);
+                        resetLatch.countDown();
+                    }
+                };
+            }
+        });
+
+        Session client = newClient(new Session.Listener.Adapter());
+        MetaData.Request request = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame = new HeadersFrame(request, null, false);
+        FuturePromise<Stream> promise = new FuturePromise<>();
+        client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
+        Stream stream = promise.get(5, TimeUnit.SECONDS);
+        ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
+        stream.reset(resetFrame, Callback.NOOP);
+
+        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+
+        // Wait a while to let the server remove the
+        // stream after returning from onReset().
+        Thread.sleep(1000);
+
+        Stream serverStream = streamRef.get();
+        Assert.assertEquals(0, serverStream.getSession().getStreams().size());
+    }
+
+    @Test
+    public void testStreamResetDoesNotCloseConnection() throws Exception
+    {
+        final CountDownLatch serverResetLatch = new CountDownLatch(1);
+        final CountDownLatch serverDataLatch = new CountDownLatch(1);
+        start(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame)
+            {
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false);
+                stream.headers(responseFrame, Callback.NOOP);
+                return new Stream.Listener.Adapter()
+                {
+                    @Override
+                    public void onData(Stream stream, DataFrame frame, Callback callback)
+                    {
+                        callback.succeeded();
+                        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), Callback.NOOP);
+                        serverDataLatch.countDown();
+                    }
+
+                    @Override
+                    public void onReset(Stream stream, ResetFrame frame)
+                    {
+                        // Simulate that there is pending data to send.
+                        stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), new Callback()
+                        {
+                            @Override
+                            public void failed(Throwable x)
+                            {
+                                serverResetLatch.countDown();
+                            }
+                        });
+                    }
+                };
+            }
+        });
+
+        Session client = newClient(new Session.Listener.Adapter());
+        MetaData.Request request1 = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame1 = new HeadersFrame(request1, null, false);
+        FuturePromise<Stream> promise1 = new FuturePromise<>();
+        final CountDownLatch stream1HeadersLatch = new CountDownLatch(1);
+        final CountDownLatch stream1DataLatch = new CountDownLatch(1);
+        client.newStream(requestFrame1, promise1, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                stream1HeadersLatch.countDown();
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                stream1DataLatch.countDown();
+            }
+        });
+        Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
+        Assert.assertTrue(stream1HeadersLatch.await(5, TimeUnit.SECONDS));
+
+        MetaData.Request request2 = newRequest("GET", new HttpFields());
+        HeadersFrame requestFrame2 = new HeadersFrame(request2, null, false);
+        FuturePromise<Stream> promise2 = new FuturePromise<>();
+        final CountDownLatch stream2DataLatch = new CountDownLatch(1);
+        client.newStream(requestFrame2, promise2, new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                stream2DataLatch.countDown();
+            }
+        });
+        Stream stream2 = promise2.get(5, TimeUnit.SECONDS);
+
+        ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
+        stream1.reset(resetFrame, Callback.NOOP);
+
+        Assert.assertTrue(serverResetLatch.await(5, TimeUnit.SECONDS));
+        // Stream MUST NOT receive data sent by server after reset.
+        Assert.assertFalse(stream1DataLatch.await(1, TimeUnit.SECONDS));
+
+        // The other stream should still be working.
+        stream2.data(new DataFrame(stream2.getId(), ByteBuffer.allocate(16), true), Callback.NOOP);
+        Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS));
+        Assert.assertTrue(stream2DataLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testBlockingWriteAfterStreamReceivingReset() throws Exception
+    {
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                Charset charset = StandardCharsets.UTF_8;
+                byte[] data = "AFTER RESET".getBytes(charset);
+
+                response.setStatus(200);
+                response.setContentType("text/plain;charset=" + charset.name());
+                response.setContentLength(data.length*10);
+                response.flushBuffer();
+
+                try
+                {
+                    // Wait for the reset to happen.
+                    Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+                }
+                catch (InterruptedException x)
+                {
+                    throw new InterruptedIOException();
+                }
+
+                try
+                {
+                    // Write some content after the stream has
+                    // been reset, it should throw an exception.
+                    for (int i=0;i<10;i++)
+                    {
+                        Thread.sleep(500);
+                        response.getOutputStream().write(data);
+                        response.flushBuffer();
+                    }
+                }
+                catch (InterruptedException x)
+                {
+
+                }
+                catch (IOException x)
+                {
+                    dataLatch.countDown();
+                }
+            }
+        });
+
+        Session client = newClient(new Session.Listener.Adapter());
+        MetaData.Request request = newRequest("GET", new HttpFields());
+        HeadersFrame frame = new HeadersFrame(request, null, true);
+        client.newStream(frame, new FuturePromise<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+                resetLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testAsyncWriteAfterStreamReceivingReset() throws Exception
+    {
+        final CountDownLatch resetLatch = new CountDownLatch(1);
+        final CountDownLatch dataLatch = new CountDownLatch(1);
+        start(new HttpServlet()
+        {
+            @Override
+            protected void doGet(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+            {
+                Charset charset = StandardCharsets.UTF_8;
+                final ByteBuffer data = ByteBuffer.wrap("AFTER RESET".getBytes(charset));
+
+                response.setStatus(200);
+                response.setContentType("text/plain;charset=" + charset.name());
+                response.setContentLength(data.remaining());
+                response.flushBuffer();
+
+                try
+                {
+                    // Wait for the reset to happen.
+                    Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
+                    // Wait for the reset to arrive to the server and be processed.
+                    Thread.sleep(1000);
+                }
+                catch (InterruptedException x)
+                {
+                    throw new InterruptedIOException();
+                }
+
+                // Write some content asynchronously after the stream has been reset.
+                final AsyncContext context = request.startAsync();
+                new Thread()
+                {
+                    @Override
+                    public void run()
+                    {
+                        try
+                        {
+                            // Wait for the request thread to exit
+                            // doGet() so this is really asynchronous.
+                            Thread.sleep(1000);
+
+                            HttpOutput output = (HttpOutput)response.getOutputStream();
+                            output.sendContent(data, new Callback()
+                            {
+                                @Override
+                                public void failed(Throwable x)
+                                {
+                                    context.complete();
+                                    dataLatch.countDown();
+                                }
+                            });
+                        }
+                        catch (Throwable x)
+                        {
+                            x.printStackTrace();
+                        }
+                    }
+                }.start();
+            }
+        });
+
+        Session client = newClient(new Session.Listener.Adapter());
+        MetaData.Request request = newRequest("GET", new HttpFields());
+        HeadersFrame frame = new HeadersFrame(request, null, true);
+        client.newStream(frame, new FuturePromise<>(), new Stream.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+                stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+                resetLatch.countDown();
+            }
+        });
+
+        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
+    }
+}
diff --git a/jetty-http2/http2-client/src/test/resources/jetty-logging.properties b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..b7185f0
--- /dev/null
+++ b/jetty-http2/http2-client/src/test/resources/jetty-logging.properties
@@ -0,0 +1,4 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.LEVEL=DEBUG
+#org.eclipse.jetty.servlets.LEVEL=DEBUG
diff --git a/jetty-http2/http2-common/pom.xml b/jetty-http2/http2-common/pom.xml
new file mode 100644
index 0000000..f4359f4
--- /dev/null
+++ b/jetty-http2/http2-common/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.http2</groupId>
+    <artifactId>http2-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>http2-common</artifactId>
+  <name>Jetty :: HTTP2 :: Common</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-hpack</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-jmx</artifactId>
+      <version>${project.version}</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.common</bundle-symbolic-name>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <executions>
+          <execution>
+            <goals>
+              <goal>manifest</goal>
+            </goals>
+            <configuration>
+              <instructions>
+                <Export-Package>org.eclipse.jetty.http2.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";</Export-Package>
+              </instructions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java
new file mode 100644
index 0000000..8a1b6f9
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java
@@ -0,0 +1,244 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.ManagedOperation;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+@ManagedObject
+public abstract class AbstractFlowControlStrategy implements FlowControlStrategy, Dumpable
+{
+    protected static final Logger LOG = Log.getLogger(FlowControlStrategy.class);
+
+    private final AtomicLong sessionStall = new AtomicLong();
+    private final AtomicLong sessionStallTime = new AtomicLong();
+    private final Map<IStream, Long> streamsStalls = new ConcurrentHashMap<>();
+    private final AtomicLong streamsStallTime = new AtomicLong();
+    private int initialStreamSendWindow;
+    private int initialStreamRecvWindow;
+
+    public AbstractFlowControlStrategy(int initialStreamSendWindow)
+    {
+        this.initialStreamSendWindow = initialStreamSendWindow;
+        this.initialStreamRecvWindow = DEFAULT_WINDOW_SIZE;
+    }
+
+    @ManagedAttribute(value = "The initial size of stream's flow control send window", readonly = true)
+    public int getInitialStreamSendWindow()
+    {
+        return initialStreamSendWindow;
+    }
+
+    @ManagedAttribute(value = "The initial size of stream's flow control receive window", readonly = true)
+    public int getInitialStreamRecvWindow()
+    {
+        return initialStreamRecvWindow;
+    }
+
+    @Override
+    public void onStreamCreated(IStream stream)
+    {
+        stream.updateSendWindow(initialStreamSendWindow);
+        stream.updateRecvWindow(initialStreamRecvWindow);
+    }
+
+    @Override
+    public void onStreamDestroyed(IStream stream)
+    {
+    }
+
+    @Override
+    public void updateInitialStreamWindow(ISession session, int initialStreamWindow, boolean local)
+    {
+        int previousInitialStreamWindow;
+        if (local)
+        {
+            previousInitialStreamWindow = getInitialStreamRecvWindow();
+            this.initialStreamRecvWindow = initialStreamWindow;
+        }
+        else
+        {
+            previousInitialStreamWindow = getInitialStreamSendWindow();
+            this.initialStreamSendWindow = initialStreamWindow;
+        }
+        int delta = initialStreamWindow - previousInitialStreamWindow;
+
+        // SPEC: updates of the initial window size only affect stream windows, not session's.
+        for (Stream stream : session.getStreams())
+        {
+            if (local)
+            {
+                ((IStream)stream).updateRecvWindow(delta);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Updated initial stream recv window {} -> {} for {}", previousInitialStreamWindow, initialStreamWindow, stream);
+            }
+            else
+            {
+                session.onWindowUpdate((IStream)stream, new WindowUpdateFrame(stream.getId(), delta));
+            }
+        }
+    }
+
+    @Override
+    public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame)
+    {
+        int delta = frame.getWindowDelta();
+        if (frame.getStreamId() > 0)
+        {
+            // The stream may have been removed concurrently.
+            if (stream != null)
+            {
+                int oldSize = stream.updateSendWindow(delta);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Updated stream send window {} -> {} for {}", oldSize, oldSize + delta, stream);
+                if (oldSize <= 0)
+                    onStreamUnstalled(stream);
+            }
+        }
+        else
+        {
+            int oldSize = session.updateSendWindow(delta);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Updated session send window {} -> {} for {}", oldSize, oldSize + delta, session);
+            if (oldSize <= 0)
+                onSessionUnstalled(session);
+        }
+    }
+
+    @Override
+    public void onDataReceived(ISession session, IStream stream, int length)
+    {
+        int oldSize = session.updateRecvWindow(-length);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Data received, updated session recv window {} -> {} for {}", oldSize, oldSize - length, session);
+
+        if (stream != null)
+        {
+            oldSize = stream.updateRecvWindow(-length);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Data received, updated stream recv window {} -> {} for {}", oldSize, oldSize - length, stream);
+        }
+    }
+
+    @Override
+    public void windowUpdate(ISession session, IStream stream, WindowUpdateFrame frame)
+    {
+    }
+
+    @Override
+    public void onDataSending(IStream stream, int length)
+    {
+        if (length == 0)
+            return;
+
+        ISession session = stream.getSession();
+        int oldSessionWindow = session.updateSendWindow(-length);
+        int newSessionWindow = oldSessionWindow - length;
+        if (LOG.isDebugEnabled())
+            LOG.debug("Sending, session send window {} -> {} for {}", oldSessionWindow, newSessionWindow, session);
+        if (newSessionWindow <= 0)
+            onSessionStalled(session);
+
+        int oldStreamWindow = stream.updateSendWindow(-length);
+        int newStreamWindow = oldStreamWindow - length;
+        if (LOG.isDebugEnabled())
+            LOG.debug("Sending, stream send window {} -> {} for {}", oldStreamWindow, newStreamWindow, stream);
+        if (newStreamWindow <= 0)
+            onStreamStalled(stream);
+    }
+
+    @Override
+    public void onDataSent(IStream stream, int length)
+    {
+    }
+
+    protected void onSessionStalled(ISession session)
+    {
+        sessionStall.set(System.nanoTime());
+        if (LOG.isDebugEnabled())
+            LOG.debug("Session stalled {}", session);
+    }
+
+    protected void onStreamStalled(IStream stream)
+    {
+        streamsStalls.put(stream, System.nanoTime());
+        if (LOG.isDebugEnabled())
+            LOG.debug("Stream stalled {}", stream);
+    }
+
+    protected void onSessionUnstalled(ISession session)
+    {
+        sessionStallTime.addAndGet(System.nanoTime() - sessionStall.getAndSet(0));
+        if (LOG.isDebugEnabled())
+            LOG.debug("Session unstalled {}", session);
+    }
+
+    protected void onStreamUnstalled(IStream stream)
+    {
+        Long time = streamsStalls.remove(stream);
+        if (time != null)
+            streamsStallTime.addAndGet(System.nanoTime() - time);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Stream unstalled {}", stream);
+    }
+
+    @ManagedAttribute(value = "The time, in milliseconds, that the session flow control has stalled", readonly = true)
+    public long getSessionStallTime()
+    {
+        return TimeUnit.NANOSECONDS.toMillis(sessionStallTime.get());
+    }
+
+    @ManagedAttribute(value = "The time, in milliseconds, that the streams flow control has stalled", readonly = true)
+    public long getStreamsStallTime()
+    {
+        return TimeUnit.NANOSECONDS.toMillis(streamsStallTime.get());
+    }
+
+    @ManagedOperation(value = "Resets the statistics", impact = "ACTION")
+    public void reset()
+    {
+        sessionStallTime.set(0);
+        streamsStallTime.set(0);
+    }
+
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        out.append(toString()).append(System.lineSeparator());
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
new file mode 100644
index 0000000..482f5ab
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
@@ -0,0 +1,212 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.util.Atomics;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+
+/**
+ * <p>A flow control strategy that accumulates updates and emits window control
+ * frames when the accumulated value reaches a threshold.</p>
+ * <p>The sender flow control window is represented in the receiver as two
+ * buckets: a bigger bucket, initially full, that is drained when data is
+ * received, and a smaller bucket, initially empty, that is filled when data is
+ * consumed. Only the smaller bucket can refill the bigger bucket.</p>
+ * <p>The smaller bucket is defined as a fraction of the bigger bucket.</p>
+ * <p>For a more visual representation, see the
+ * <a href="http://en.wikipedia.org/wiki/Shishi-odoshi">rocking bamboo fountain</a>.</p>
+ * <p>The algorithm works in this way.</p>
+ * <p>The initial bigger bucket (BB) capacity is 100, and let's imagine the smaller
+ * bucket (SB) being 40% of the bigger bucket: 40.</p>
+ * <p>The receiver receives a data frame of 60, so now BB=40; the data frame is
+ * passed to the application that consumes 25, so now SB=25. Since SB is not full,
+ * no window control frames are emitted.</p>
+ * <p>The application consumes other 20, so now SB=45. Since SB is full, its 45
+ * are transferred to BB, which is now BB=85, and a window control frame is sent
+ * with delta=45.</p>
+ * <p>The application consumes the remaining 15, so now SB=15, and no window
+ * control frame is emitted.</p>
+ */
+@ManagedObject
+public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
+{
+    private final AtomicInteger maxSessionRecvWindow = new AtomicInteger(DEFAULT_WINDOW_SIZE);
+    private final AtomicInteger sessionLevel = new AtomicInteger();
+    private final Map<IStream, AtomicInteger> streamLevels = new ConcurrentHashMap<>();
+    private float bufferRatio;
+
+    public BufferingFlowControlStrategy(float bufferRatio)
+    {
+        this(DEFAULT_WINDOW_SIZE, bufferRatio);
+    }
+
+    public BufferingFlowControlStrategy(int initialStreamSendWindow, float bufferRatio)
+    {
+        super(initialStreamSendWindow);
+        this.bufferRatio = bufferRatio;
+    }
+
+    @ManagedAttribute("The ratio between the receive buffer and the consume buffer")
+    public float getBufferRatio()
+    {
+        return bufferRatio;
+    }
+
+    public void setBufferRatio(float bufferRatio)
+    {
+        this.bufferRatio = bufferRatio;
+    }
+
+    @Override
+    public void onStreamCreated(IStream stream)
+    {
+        super.onStreamCreated(stream);
+        streamLevels.put(stream, new AtomicInteger());
+    }
+
+    @Override
+    public void onStreamDestroyed(IStream stream)
+    {
+        streamLevels.remove(stream);
+        super.onStreamDestroyed(stream);
+    }
+
+    @Override
+    public void onDataConsumed(ISession session, IStream stream, int length)
+    {
+        if (length <= 0)
+            return;
+
+        float ratio = bufferRatio;
+
+        WindowUpdateFrame windowFrame = null;
+        int level = sessionLevel.addAndGet(length);
+        int maxLevel = (int)(maxSessionRecvWindow.get() * ratio);
+        if (level > maxLevel)
+        {
+            level = sessionLevel.getAndSet(0);
+            session.updateRecvWindow(level);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Data consumed, updated session recv window by {}/{} for {}", level, maxLevel, session);
+            windowFrame = new WindowUpdateFrame(0, level);
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Data consumed, session recv window level {}/{} for {}", level, maxLevel, session);
+        }
+
+        Frame[] windowFrames = Frame.EMPTY_ARRAY;
+        if (stream != null)
+        {
+            if (stream.isClosed())
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Data consumed, ignoring update stream recv window by {} for closed {}", length, stream);
+            }
+            else
+            {
+                AtomicInteger streamLevel = streamLevels.get(stream);
+                if (streamLevel != null)
+                {
+                    level = streamLevel.addAndGet(length);
+                    maxLevel = (int)(getInitialStreamRecvWindow() * ratio);
+                    if (level > maxLevel)
+                    {
+                        level = streamLevel.getAndSet(0);
+                        stream.updateRecvWindow(level);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Data consumed, updated stream recv window by {}/{} for {}", level, maxLevel, stream);
+                        WindowUpdateFrame frame = new WindowUpdateFrame(stream.getId(), level);
+                        if (windowFrame == null)
+                            windowFrame = frame;
+                        else
+                            windowFrames = new Frame[]{frame};
+                    }
+                    else
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Data consumed, stream recv window level {}/{} for {}", level, maxLevel, session);
+                    }
+                }
+            }
+        }
+
+        if (windowFrame != null)
+            session.frames(stream, Callback.NOOP, windowFrame, windowFrames);
+    }
+
+    @Override
+    public void windowUpdate(ISession session, IStream stream, WindowUpdateFrame frame)
+    {
+        super.windowUpdate(session, stream, frame);
+
+        // Window updates cannot be negative.
+        // The SettingsFrame.INITIAL_WINDOW_SIZE setting
+        // only influences the *stream* window size.
+        // Therefore the session window can only be enlarged,
+        // and here we keep track of its max value.
+
+        // Updating the max session recv window is done here
+        // so that if a peer decides to send an unilateral
+        // window update to enlarge the session window,
+        // without the corresponding data consumption, here
+        // we can track it.
+        // Note that it is not perfect, since there is a time
+        // window between the session recv window being updated
+        // before the window update frame is sent, and the
+        // invocation of this method: in between data may arrive
+        // and reduce the session recv window size.
+        // But eventually the max value will be seen.
+
+        // Note that we cannot avoid the time window described
+        // above by updating the session recv window from here
+        // because there is a race between the sender and the
+        // receiver: the sender may receive a window update and
+        // send more data, while this method has not yet been
+        // invoked; when the data is received the session recv
+        // window may become negative and the connection will
+        // be closed (per specification).
+
+        if (frame.getStreamId() == 0)
+        {
+            int sessionWindow = session.updateRecvWindow(0);
+            Atomics.updateMax(maxSessionRecvWindow, sessionWindow);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x[ratio=%.2f,sessionStallTime=%dms,streamsStallTime=%dms]",
+                getClass().getSimpleName(),
+                hashCode(),
+                bufferRatio,
+                getSessionStallTime(),
+                getStreamsStallTime());
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java
new file mode 100644
index 0000000..8085ba4
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/CloseState.java
@@ -0,0 +1,24 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+public enum CloseState
+{
+    NOT_CLOSED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
new file mode 100644
index 0000000..e5a69b1
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum ErrorCode
+{
+    NO_ERROR(0),
+    PROTOCOL_ERROR(1),
+    INTERNAL_ERROR(2),
+    FLOW_CONTROL_ERROR(3),
+    SETTINGS_TIMEOUT_ERROR(4),
+    STREAM_CLOSED_ERROR(5),
+    FRAME_SIZE_ERROR(6),
+    REFUSED_STREAM_ERROR(7),
+    CANCEL_STREAM_ERROR(8),
+    COMPRESSION_ERROR(9),
+    HTTP_CONNECT_ERROR(10),
+    ENHANCE_YOUR_CALM_ERROR(11),
+    INADEQUATE_SECURITY_ERROR(12),
+    HTTP_1_1_REQUIRED_ERROR(13);
+
+    public final int code;
+
+    private ErrorCode(int code)
+    {
+        this.code = code;
+        Codes.codes.put(code, this);
+    }
+
+    public static ErrorCode from(int error)
+    {
+        return Codes.codes.get(error);
+    }
+
+    private static class Codes
+    {
+        private static final Map<Integer, ErrorCode> codes = new HashMap<>();
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java
new file mode 100644
index 0000000..7c7ef6d
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/Flags.java
@@ -0,0 +1,29 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+public interface Flags
+{
+    public static final int NONE = 0x00;
+    public static final int END_STREAM = 0x01;
+    public static final int ACK = 0x01;
+    public static final int END_HEADERS = 0x04;
+    public static final int PADDING = 0x08;
+    public static final int PRIORITY = 0x20;
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java
new file mode 100644
index 0000000..5ba3f48
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/FlowControlStrategy.java
@@ -0,0 +1,49 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+
+public interface FlowControlStrategy
+{
+    public static int DEFAULT_WINDOW_SIZE = 65535;
+
+    public void onStreamCreated(IStream stream);
+
+    public void onStreamDestroyed(IStream stream);
+
+    public void updateInitialStreamWindow(ISession session, int initialStreamWindow, boolean local);
+
+    public void onWindowUpdate(ISession session, IStream stream, WindowUpdateFrame frame);
+
+    public void onDataReceived(ISession session, IStream stream, int length);
+
+    public void onDataConsumed(ISession session, IStream stream, int length);
+
+    public void windowUpdate(ISession session, IStream stream, WindowUpdateFrame frame);
+
+    public void onDataSending(IStream stream, int length);
+
+    public void onDataSent(IStream stream, int length);
+
+    public interface Factory
+    {
+        public FlowControlStrategy newFlowControlStrategy();
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java
new file mode 100644
index 0000000..4eb1c5e
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java
@@ -0,0 +1,356 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.util.Comparator;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.Trie;
+
+public class HTTP2Cipher
+{
+    public static final Comparator<String> COMPARATOR = new CipherComparator();
+
+    private final static Trie<Boolean> __blackProtocols = new ArrayTrie<>(6*5);
+    private final static Trie<Boolean> __blackCiphers = new ArrayTrie<>(275*40);
+
+    static
+    {
+        for (String p : new String[]
+        {
+                "TLSv1.2","TLSv1.1", "TLSv1", "SSL", "SSLv2", "SSLv3"
+        })
+        {
+            __blackProtocols.put(p,Boolean.TRUE);
+        }
+
+        for (String c : new String[]
+        {
+            "TLS_NULL_WITH_NULL_NULL",
+            "TLS_RSA_WITH_NULL_MD5",
+            "TLS_RSA_WITH_NULL_SHA",
+            "TLS_RSA_EXPORT_WITH_RC4_40_MD5",
+            "TLS_RSA_WITH_RC4_128_MD5",
+            "TLS_RSA_WITH_RC4_128_SHA",
+            "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+            "TLS_RSA_WITH_IDEA_CBC_SHA",
+            "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_RSA_WITH_DES_CBC_SHA",
+            "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_DH_DSS_WITH_DES_CBC_SHA",
+            "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_DH_RSA_WITH_DES_CBC_SHA",
+            "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_DHE_DSS_WITH_DES_CBC_SHA",
+            "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_DHE_RSA_WITH_DES_CBC_SHA",
+            "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
+            "TLS_DH_anon_WITH_RC4_128_MD5",
+            "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+            "TLS_DH_anon_WITH_DES_CBC_SHA",
+            "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
+            "TLS_KRB5_WITH_DES_CBC_SHA",
+            "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
+            "TLS_KRB5_WITH_RC4_128_SHA",
+            "TLS_KRB5_WITH_IDEA_CBC_SHA",
+            "TLS_KRB5_WITH_DES_CBC_MD5",
+            "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
+            "TLS_KRB5_WITH_RC4_128_MD5",
+            "TLS_KRB5_WITH_IDEA_CBC_MD5",
+            "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
+            "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
+            "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
+            "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
+            "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
+            "TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
+            "TLS_PSK_WITH_NULL_SHA",
+            "TLS_DHE_PSK_WITH_NULL_SHA",
+            "TLS_RSA_PSK_WITH_NULL_SHA",
+            "TLS_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
+            "TLS_DH_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+            "TLS_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_DH_DSS_WITH_AES_256_CBC_SHA",
+            "TLS_DH_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_DH_anon_WITH_AES_256_CBC_SHA",
+            "TLS_RSA_WITH_NULL_SHA256",
+            "TLS_RSA_WITH_AES_128_CBC_SHA256",
+            "TLS_RSA_WITH_AES_256_CBC_SHA256",
+            "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
+            "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
+            "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+            "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
+            "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+            "TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
+            "TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
+            "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+            "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+            "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+            "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+            "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
+            "TLS_PSK_WITH_RC4_128_SHA",
+            "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
+            "TLS_PSK_WITH_AES_128_CBC_SHA",
+            "TLS_PSK_WITH_AES_256_CBC_SHA",
+            "TLS_DHE_PSK_WITH_RC4_128_SHA",
+            "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
+            "TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
+            "TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
+            "TLS_RSA_PSK_WITH_RC4_128_SHA",
+            "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
+            "TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
+            "TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
+            "TLS_RSA_WITH_SEED_CBC_SHA",
+            "TLS_DH_DSS_WITH_SEED_CBC_SHA",
+            "TLS_DH_RSA_WITH_SEED_CBC_SHA",
+            "TLS_DHE_DSS_WITH_SEED_CBC_SHA",
+            "TLS_DHE_RSA_WITH_SEED_CBC_SHA",
+            "TLS_DH_anon_WITH_SEED_CBC_SHA",
+            "TLS_RSA_WITH_AES_128_GCM_SHA256",
+            "TLS_RSA_WITH_AES_256_GCM_SHA384",
+            "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
+            "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
+            "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
+            "TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
+            "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
+            "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
+            "TLS_PSK_WITH_AES_128_GCM_SHA256",
+            "TLS_PSK_WITH_AES_256_GCM_SHA384",
+            "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
+            "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
+            "TLS_PSK_WITH_AES_128_CBC_SHA256",
+            "TLS_PSK_WITH_AES_256_CBC_SHA384",
+            "TLS_PSK_WITH_NULL_SHA256",
+            "TLS_PSK_WITH_NULL_SHA384",
+            "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
+            "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
+            "TLS_DHE_PSK_WITH_NULL_SHA256",
+            "TLS_DHE_PSK_WITH_NULL_SHA384",
+            "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
+            "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
+            "TLS_RSA_PSK_WITH_NULL_SHA256",
+            "TLS_RSA_PSK_WITH_NULL_SHA384",
+            "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
+            "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+            "TLS_ECDH_ECDSA_WITH_NULL_SHA",
+            "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+            "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+            "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+            "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+            "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+            "TLS_ECDH_RSA_WITH_NULL_SHA",
+            "TLS_ECDH_RSA_WITH_RC4_128_SHA",
+            "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_ECDHE_RSA_WITH_NULL_SHA",
+            "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+            "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_ECDH_anon_WITH_NULL_SHA",
+            "TLS_ECDH_anon_WITH_RC4_128_SHA",
+            "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+            "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+            "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
+            "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
+            "TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
+            "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
+            "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
+            "TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
+            "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
+            "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
+            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+            "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+            "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+            "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+            "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+            "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+            "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+            "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+            "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+            "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+            "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+            "TLS_ECDHE_PSK_WITH_RC4_128_SHA",
+            "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
+            "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
+            "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
+            "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
+            "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
+            "TLS_ECDHE_PSK_WITH_NULL_SHA",
+            "TLS_ECDHE_PSK_WITH_NULL_SHA256",
+            "TLS_ECDHE_PSK_WITH_NULL_SHA384",
+            "TLS_RSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_RSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384",
+            "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
+            "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
+            "TLS_RSA_WITH_ARIA_128_GCM_SHA256",
+            "TLS_RSA_WITH_ARIA_256_GCM_SHA384",
+            "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
+            "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
+            "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
+            "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
+            "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256",
+            "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384",
+            "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
+            "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
+            "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
+            "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
+            "TLS_PSK_WITH_ARIA_128_CBC_SHA256",
+            "TLS_PSK_WITH_ARIA_256_CBC_SHA384",
+            "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
+            "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
+            "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
+            "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
+            "TLS_PSK_WITH_ARIA_128_GCM_SHA256",
+            "TLS_PSK_WITH_ARIA_256_GCM_SHA384",
+            "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
+            "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
+            "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
+            "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
+            "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
+            "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
+            "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+            "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+            "TLS_RSA_WITH_AES_128_CCM",
+            "TLS_RSA_WITH_AES_256_CCM",
+            "TLS_RSA_WITH_AES_128_CCM_8",
+            "TLS_RSA_WITH_AES_256_CCM_8",
+            "TLS_PSK_WITH_AES_128_CCM",
+            "TLS_PSK_WITH_AES_256_CCM",
+            "TLS_PSK_WITH_AES_128_CCM_8",
+            "TLS_PSK_WITH_AES_256_CCM_8"
+        })
+        {
+            __blackCiphers.put(c,Boolean.TRUE);
+        }
+    }
+
+    public static boolean isBlackListProtocol(String tlsProtocol)
+    {
+        Boolean b = __blackProtocols.get(tlsProtocol);
+        return b != null && b;
+    }
+
+    public static boolean isBlackListCipher(String tlsCipher)
+    {
+        Boolean b = __blackCiphers.get(tlsCipher);
+        return b != null && b;
+    }
+
+    /**
+     * Comparator that orders non blacklisted ciphers before blacklisted ones.
+     */
+    public static class CipherComparator implements Comparator<String>
+    {
+        @Override
+        public int compare(String c1, String c2)
+        {
+            boolean b1=isBlackListCipher(c1);
+            boolean b2=isBlackListCipher(c2);
+            if (b1==b2)
+                return 0;
+            if (b1)
+                return 1;
+            return -1;
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
new file mode 100644
index 0000000..034922f
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
@@ -0,0 +1,208 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.AbstractConnection;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ExecutionStrategy;
+
+public class HTTP2Connection extends AbstractConnection
+{
+    protected static final Logger LOG = Log.getLogger(HTTP2Connection.class);
+
+    private final Queue<Runnable> tasks = new ConcurrentArrayQueue<>();
+    private final ByteBufferPool byteBufferPool;
+    private final Parser parser;
+    private final ISession session;
+    private final int bufferSize;
+    private final HTTP2Producer producer = new HTTP2Producer();
+    private final ExecutionStrategy executionStrategy;
+
+    public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, ISession session, int bufferSize)
+    {
+        super(endPoint, executor);
+        this.byteBufferPool = byteBufferPool;
+        this.parser = parser;
+        this.session = session;
+        this.bufferSize = bufferSize;
+        this.executionStrategy = ExecutionStrategy.Factory.instanceFor(producer, executor);
+    }
+
+    public ISession getSession()
+    {
+        return session;
+    }
+
+
+    protected Parser getParser()
+    {
+        return parser;
+    }
+
+    protected void setInputBuffer(ByteBuffer buffer)
+    {
+        producer.buffer = buffer;
+    }
+
+    @Override
+    public void onOpen()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP2 Open {} ", this);
+        super.onOpen();
+        executionStrategy.execute();
+    }
+
+    @Override
+    public void onClose()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP2 Close {} ", this);
+        super.onClose();
+    }
+
+    @Override
+    public void onFillable()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP2 onFillable {} ", this);
+        executionStrategy.execute();
+    }
+
+    private int fill(EndPoint endPoint, ByteBuffer buffer)
+    {
+        try
+        {
+            if (endPoint.isInputShutdown())
+                return -1;
+            return endPoint.fill(buffer);
+        }
+        catch (IOException x)
+        {
+            LOG.debug("Could not read from " + endPoint, x);
+            return -1;
+        }
+    }
+
+    @Override
+    public boolean onIdleExpired()
+    {
+        boolean close = session.onIdleTimeout();
+        boolean idle = isFillInterested();
+        if (close && idle)
+            session.close(ErrorCode.NO_ERROR.code, "idle_timeout", Callback.NOOP);
+        return false;
+    }
+
+    protected void offerTask(Runnable task, boolean dispatch)
+    {
+        tasks.offer(task);
+        if (dispatch)
+            executionStrategy.dispatch();
+        else
+            executionStrategy.execute();
+    }
+
+    @Override
+    public void close()
+    {
+        // We don't call super from here, otherwise we close the
+        // endPoint and we're not able to read or write anymore.
+        session.close(ErrorCode.NO_ERROR.code, "close", Callback.NOOP);
+    }
+
+    protected class HTTP2Producer implements ExecutionStrategy.Producer
+    {
+        private ByteBuffer buffer;
+
+        @Override
+        public Runnable produce()
+        {
+            Runnable task = tasks.poll();
+            if (LOG.isDebugEnabled())
+                LOG.debug("Dequeued task {}", task);
+            if (task != null)
+                return task;
+
+            if (isFillInterested())
+                return null;
+
+            if (buffer == null)
+                buffer = byteBufferPool.acquire(bufferSize, false); // TODO: make directness customizable
+            boolean looping = BufferUtil.hasContent(buffer);
+            while (true)
+            {
+                if (looping)
+                {
+                    while (buffer.hasRemaining())
+                        parser.parse(buffer);
+
+                    task = tasks.poll();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Dequeued task {}", task);
+                    if (task != null)
+                    {
+                        release();
+                        return task;
+                    }
+                }
+
+                int filled = fill(getEndPoint(), buffer);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Filled {} bytes", filled);
+
+                if (filled == 0)
+                {
+                    release();
+                    fillInterested();
+                    return null;
+                }
+                else if (filled < 0)
+                {
+                    release();
+                    session.onShutdown();
+                    return null;
+                }
+
+                looping = true;
+            }
+        }
+
+        private void release()
+        {
+            if (buffer != null && !buffer.hasRemaining())
+            {
+                byteBufferPool.release(buffer);
+                buffer = null;
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java
new file mode 100644
index 0000000..10b4e3f
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Flusher.java
@@ -0,0 +1,408 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.util.ArrayQueue;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.IteratingCallback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class HTTP2Flusher extends IteratingCallback
+{
+    private static final Logger LOG = Log.getLogger(HTTP2Flusher.class);
+
+    private final Queue<WindowEntry> windows = new ArrayDeque<>();
+    private final ArrayQueue<Entry> frames = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH, this);
+    private final Map<IStream, Integer> streams = new HashMap<>();
+    private final List<Entry> resets = new ArrayList<>();
+    private final List<Entry> actives = new ArrayList<>();
+    private final Queue<Entry> completes = new ArrayDeque<>();
+    private final HTTP2Session session;
+    private final ByteBufferPool.Lease lease;
+
+    public HTTP2Flusher(HTTP2Session session)
+    {
+        this.session = session;
+        this.lease = new ByteBufferPool.Lease(session.getGenerator().getByteBufferPool());
+    }
+
+    public void window(IStream stream, WindowUpdateFrame frame)
+    {
+        boolean added = false;
+        synchronized (this)
+        {
+            if (!isClosed())
+                added = windows.offer(new WindowEntry(stream, frame));
+        }
+        // Flush stalled data.
+        if (added)
+            iterate();
+    }
+
+    public boolean prepend(Entry entry)
+    {
+        boolean fail = false;
+        synchronized (this)
+        {
+            if (isClosed())
+            {
+                fail = true;
+            }
+            else
+            {
+                frames.add(0, entry);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Prepended {}, frames={}", entry, frames.size());
+            }
+        }
+        if (fail)
+            closed(entry, new ClosedChannelException());
+        return !fail;
+    }
+
+    public boolean append(Entry entry)
+    {
+        boolean fail = false;
+        synchronized (this)
+        {
+            if (isClosed())
+            {
+                fail = true;
+            }
+            else
+            {
+                frames.offer(entry);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Appended {}, frames={}", entry, frames.size());
+            }
+        }
+        if (fail)
+            closed(entry, new ClosedChannelException());
+        return !fail;
+    }
+
+    private Entry remove(int index)
+    {
+        synchronized (this)
+        {
+            if (index == 0)
+                return frames.pollUnsafe();
+            else
+                return frames.remove(index);
+        }
+    }
+
+    public int getQueueSize()
+    {
+        synchronized (this)
+        {
+            return frames.size();
+        }
+    }
+
+    @Override
+    protected Action process() throws Exception
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Flushing {}", session);
+
+        synchronized (this)
+        {
+            // First thing, update the window sizes, so we can
+            // reason about the frames to remove from the queue.
+            while (!windows.isEmpty())
+            {
+                WindowEntry entry = windows.poll();
+                entry.perform();
+            }
+
+            // Now the window sizes cannot change.
+            // Window updates that happen concurrently will
+            // be queued and processed on the next iteration.
+            int sessionWindow = session.getSendWindow();
+
+            int index = 0;
+            int size = frames.size();
+            while (index < size)
+            {
+                Entry entry = frames.get(index);
+                IStream stream = entry.stream;
+
+                // If the stream has been reset, don't send the frame.
+                if (stream != null && stream.isReset() && !entry.isProtocol())
+                {
+                    remove(index);
+                    --size;
+                    resets.add(entry);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Gathered for reset {}", entry);
+                    continue;
+                }
+
+                // Check if the frame fits in the flow control windows.
+                int remaining = entry.dataRemaining();
+                if (remaining > 0)
+                {
+                    if (sessionWindow <= 0)
+                    {
+                        ++index;
+                        // There may be *non* flow controlled frames to send.
+                        continue;
+                    }
+
+                    if (stream != null)
+                    {
+                        // The stream may have a smaller window than the session.
+                        Integer streamWindow = streams.get(stream);
+                        if (streamWindow == null)
+                        {
+                            streamWindow = stream.updateSendWindow(0);
+                            streams.put(stream, streamWindow);
+                        }
+
+                        // Is it a frame belonging to an already stalled stream ?
+                        if (streamWindow <= 0)
+                        {
+                            ++index;
+                            // There may be *non* flow controlled frames to send.
+                            continue;
+                        }
+                    }
+
+                    // The frame fits both flow control windows, reduce them.
+                    sessionWindow -= remaining;
+                    if (stream != null)
+                        streams.put(stream, streams.get(stream) - remaining);
+                }
+
+                // The frame will be written, remove it from the queue.
+                remove(index);
+                --size;
+                actives.add(entry);
+
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Gathered for write {}", entry);
+            }
+            streams.clear();
+        }
+
+        // Perform resets outside the sync block.
+        for (int i = 0; i < resets.size(); ++i)
+        {
+            Entry entry = resets.get(i);
+            entry.reset();
+        }
+        resets.clear();
+
+        if (actives.isEmpty())
+        {
+            if (isClosed())
+                fail(new ClosedChannelException(), true);
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Flushed {}", session);
+
+            return Action.IDLE;
+        }
+
+        for (int i = 0; i < actives.size(); ++i)
+        {
+            Entry entry = actives.get(i);
+            Throwable failure = entry.generate(lease);
+            if (failure != null)
+            {
+                // Failure to generate the entry is catastrophic.
+                failed(failure);
+                return Action.SUCCEEDED;
+            }
+        }
+
+        List<ByteBuffer> byteBuffers = lease.getByteBuffers();
+        if (LOG.isDebugEnabled())
+            LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), actives.size(), actives);
+        session.getEndPoint().write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()]));
+        return Action.SCHEDULED;
+    }
+
+    @Override
+    public void succeeded()
+    {
+        lease.recycle();
+
+        // Transfer active items to avoid reentrancy.
+        for (int i = 0; i < actives.size(); ++i)
+            completes.add(actives.get(i));
+        actives.clear();
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Written {} frames for {}", completes.size(), completes);
+
+        // Drain the frames one by one to avoid reentrancy.
+        while (!completes.isEmpty())
+        {
+            Entry entry = completes.poll();
+            entry.succeeded();
+        }
+
+        super.succeeded();
+    }
+
+    @Override
+    protected void onCompleteSuccess()
+    {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    protected void onCompleteFailure(Throwable x)
+    {
+        lease.recycle();
+
+        // Transfer active items to avoid reentrancy.
+        for (int i = 0; i < actives.size(); ++i)
+            completes.add(actives.get(i));
+        actives.clear();
+
+        // Drain the frames one by one to avoid reentrancy.
+        while (!completes.isEmpty())
+        {
+            Entry entry = completes.poll();
+            entry.failed(x);
+        }
+
+        fail(x, isClosed());
+    }
+
+    private void fail(Throwable x, boolean closed)
+    {
+        Queue<Entry> queued;
+        synchronized (this)
+        {
+            queued = new ArrayDeque<>(frames);
+            frames.clear();
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{}, queued={}", closed ? "Closing" : "Failing", queued.size());
+
+        for (Entry entry : queued)
+            entry.failed(x);
+
+        if (!closed)
+            session.abort(x);
+    }
+
+    private void closed(Entry entry, Throwable failure)
+    {
+        entry.failed(failure);
+    }
+
+    public static abstract class Entry implements Callback
+    {
+        protected final Frame frame;
+        protected final IStream stream;
+        protected final Callback callback;
+
+        protected Entry(Frame frame, IStream stream, Callback callback)
+        {
+            this.frame = frame;
+            this.stream = stream;
+            this.callback = callback;
+        }
+
+        public int dataRemaining()
+        {
+            return 0;
+        }
+
+        public Throwable generate(ByteBufferPool.Lease lease)
+        {
+            return null;
+        }
+
+        public void reset()
+        {
+            failed(new EofException("reset"));
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            if (stream != null)
+            {
+                stream.close();
+                stream.getSession().removeStream(stream);
+            }
+            callback.failed(x);
+        }
+
+        public boolean isProtocol()
+        {
+            switch (frame.getType())
+            {
+                case PRIORITY:
+                case RST_STREAM:
+                case GO_AWAY:
+                case WINDOW_UPDATE:
+                case DISCONNECT:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        @Override
+        public String toString()
+        {
+            return frame.toString();
+        }
+    }
+
+    private class WindowEntry
+    {
+        private final IStream stream;
+        private final WindowUpdateFrame frame;
+
+        public WindowEntry(IStream stream, WindowUpdateFrame frame)
+        {
+            this.stream = stream;
+            this.frame = frame;
+        }
+
+        public void perform()
+        {
+            FlowControlStrategy flowControl = session.getFlowControlStrategy();
+            flowControl.onWindowUpdate(session, stream, frame);
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java
new file mode 100644
index 0000000..54b087a
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java
@@ -0,0 +1,1254 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.DisconnectFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.Atomics;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.CountingCallback;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+@ManagedObject
+public abstract class HTTP2Session extends ContainerLifeCycle implements ISession, Parser.Listener
+{
+    private static final Logger LOG = Log.getLogger(HTTP2Session.class);
+
+    private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
+    private final AtomicInteger streamIds = new AtomicInteger();
+    private final AtomicInteger lastStreamId = new AtomicInteger();
+    private final AtomicInteger localStreamCount = new AtomicInteger();
+    private final AtomicInteger remoteStreamCount = new AtomicInteger();
+    private final AtomicInteger sendWindow = new AtomicInteger();
+    private final AtomicInteger recvWindow = new AtomicInteger();
+    private final AtomicReference<CloseState> closed = new AtomicReference<>(CloseState.NOT_CLOSED);
+    private final Scheduler scheduler;
+    private final EndPoint endPoint;
+    private final Generator generator;
+    private final Session.Listener listener;
+    private final FlowControlStrategy flowControl;
+    private final HTTP2Flusher flusher;
+    private int maxLocalStreams;
+    private int maxRemoteStreams;
+    private long streamIdleTimeout;
+    private boolean pushEnabled;
+
+    public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId)
+    {
+        this.scheduler = scheduler;
+        this.endPoint = endPoint;
+        this.generator = generator;
+        this.listener = listener;
+        this.flowControl = flowControl;
+        this.flusher = new HTTP2Flusher(this);
+        this.maxLocalStreams = -1;
+        this.maxRemoteStreams = -1;
+        this.streamIds.set(initialStreamId);
+        this.streamIdleTimeout = endPoint.getIdleTimeout();
+        this.sendWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
+        this.pushEnabled = true; // SPEC: by default, push is enabled.
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        addBean(flowControl);
+        super.doStart();
+    }
+
+    @ManagedAttribute(value = "The flow control strategy", readonly = true)
+    public FlowControlStrategy getFlowControlStrategy()
+    {
+        return flowControl;
+    }
+
+    public int getMaxLocalStreams()
+    {
+        return maxLocalStreams;
+    }
+
+    public void setMaxLocalStreams(int maxLocalStreams)
+    {
+        this.maxLocalStreams = maxLocalStreams;
+    }
+
+    public int getMaxRemoteStreams()
+    {
+        return maxRemoteStreams;
+    }
+
+    public void setMaxRemoteStreams(int maxRemoteStreams)
+    {
+        this.maxRemoteStreams = maxRemoteStreams;
+    }
+
+    @ManagedAttribute("The stream's idle timeout")
+    public long getStreamIdleTimeout()
+    {
+        return streamIdleTimeout;
+    }
+
+    public void setStreamIdleTimeout(long streamIdleTimeout)
+    {
+        this.streamIdleTimeout = streamIdleTimeout;
+    }
+
+    public EndPoint getEndPoint()
+    {
+        return endPoint;
+    }
+
+    public Generator getGenerator()
+    {
+        return generator;
+    }
+
+    @Override
+    public void onData(final DataFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        int streamId = frame.getStreamId();
+        final IStream stream = getStream(streamId);
+
+        // SPEC: the session window must be updated even if the stream is null.
+        // The flow control length includes the padding bytes.
+        final int flowControlLength = frame.remaining() + frame.padding();
+        flowControl.onDataReceived(this, stream, flowControlLength);
+
+        if (stream != null)
+        {
+            if (getRecvWindow() < 0)
+            {
+                close(ErrorCode.FLOW_CONTROL_ERROR.code, "session_window_exceeded", Callback.NOOP);
+            }
+            else
+            {
+                stream.process(frame, new Callback()
+                {
+                    @Override
+                    public void succeeded()
+                    {
+                        flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength);
+                    }
+
+                    @Override
+                    public void failed(Throwable x)
+                    {
+                        // Consume also in case of failures, to free the
+                        // session flow control window for other streams.
+                        flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength);
+                    }
+                });
+            }
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Ignoring {}, stream #{} not found", frame, streamId);
+            // We must enlarge the session flow control window,
+            // otherwise other requests will be stalled.
+            flowControl.onDataConsumed(this, null, flowControlLength);
+        }
+    }
+
+    @Override
+    public abstract void onHeaders(HeadersFrame frame);
+
+    @Override
+    public void onPriority(PriorityFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+    }
+
+    @Override
+    public void onReset(ResetFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        IStream stream = getStream(frame.getStreamId());
+        if (stream != null)
+            stream.process(frame, Callback.NOOP);
+        else
+            notifyReset(this, frame);
+    }
+
+    @Override
+    public void onSettings(SettingsFrame frame)
+    {
+        // SPEC: SETTINGS frame MUST be replied.
+        onSettings(frame, true);
+    }
+
+    public void onSettings(SettingsFrame frame, boolean reply)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        if (frame.isReply())
+            return;
+
+        // Iterate over all settings
+        for (Map.Entry<Integer, Integer> entry : frame.getSettings().entrySet())
+        {
+            int key = entry.getKey();
+            int value = entry.getValue();
+            switch (key)
+            {
+                case SettingsFrame.HEADER_TABLE_SIZE:
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Update HPACK header table size to {}", value);
+                    generator.setHeaderTableSize(value);
+                    break;
+                }
+                case SettingsFrame.ENABLE_PUSH:
+                {
+                    // SPEC: check the value is sane.
+                    if (value != 0 && value != 1)
+                    {
+                        onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_enable_push");
+                        return;
+                    }
+                    pushEnabled = value == 1;
+                    break;
+                }
+                case SettingsFrame.MAX_CONCURRENT_STREAMS:
+                {
+                    maxLocalStreams = value;
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Update max local concurrent streams to {}", maxLocalStreams);
+                    break;
+                }
+                case SettingsFrame.INITIAL_WINDOW_SIZE:
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Update initial window size to {}", value);
+                    flowControl.updateInitialStreamWindow(this, value, false);
+                    break;
+                }
+                case SettingsFrame.MAX_FRAME_SIZE:
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Update max frame size to {}", value);
+                    // SPEC: check the max frame size is sane.
+                    if (value < Frame.DEFAULT_MAX_LENGTH || value > Frame.MAX_MAX_LENGTH)
+                    {
+                        onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_max_frame_size");
+                        return;
+                    }
+                    generator.setMaxFrameSize(value);
+                    break;
+                }
+                case SettingsFrame.MAX_HEADER_LIST_SIZE:
+                {
+                    // TODO implement
+                    LOG.warn("NOT IMPLEMENTED max header list size to {}", value);
+                    break;
+                }
+                default:
+                {
+                    LOG.debug("Unknown setting {}:{}", key, value);
+                    break;
+                }
+            }
+        }
+        notifySettings(this, frame);
+
+        if (reply)
+        {
+            SettingsFrame replyFrame = new SettingsFrame(Collections.<Integer, Integer>emptyMap(), true);
+            settings(replyFrame, Callback.NOOP);
+        }
+    }
+
+    @Override
+    public void onPing(PingFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        if (frame.isReply())
+        {
+            notifyPing(this, frame);
+        }
+        else
+        {
+            PingFrame reply = new PingFrame(frame.getPayload(), true);
+            control(null, Callback.NOOP, reply);
+        }
+    }
+
+    /**
+     * This method is called when receiving a GO_AWAY from the other peer.
+     * We check the close state to act appropriately:
+     *
+     * * NOT_CLOSED: we move to REMOTELY_CLOSED and queue a disconnect, so
+     *   that the content of the queue is written, and then the connection
+     *   closed. We notify the application after being terminated.
+     *   See <code>HTTP2Session.ControlEntry#succeeded()</code>
+     *
+     * * In all other cases, we do nothing since other methods are already
+     *   performing their actions.
+     *
+     * @param frame the GO_AWAY frame that has been received.
+     * @see #close(int, String, Callback)
+     * @see #onShutdown()
+     * @see #onIdleTimeout()
+     */
+    @Override
+    public void onGoAway(final GoAwayFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        while (true)
+        {
+            CloseState current = closed.get();
+            switch (current)
+            {
+                case NOT_CLOSED:
+                {
+                    if (closed.compareAndSet(current, CloseState.REMOTELY_CLOSED))
+                    {
+                        // We received a GO_AWAY, so try to write
+                        // what's in the queue and then disconnect.
+                        control(null, new Callback()
+                        {
+                            @Override
+                            public void succeeded()
+                            {
+                                notifyClose(HTTP2Session.this, frame);
+                            }
+
+                            @Override
+                            public void failed(Throwable x)
+                            {
+                                notifyClose(HTTP2Session.this, frame);
+                            }
+                        }, new DisconnectFrame());
+                        return;
+                    }
+                    break;
+                }
+                default:
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Ignored {}, already closed", frame);
+                    return;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onWindowUpdate(WindowUpdateFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        int streamId = frame.getStreamId();
+        if (streamId > 0)
+        {
+            IStream stream = getStream(streamId);
+            if (stream != null)
+                onWindowUpdate(stream, frame);
+        }
+        else
+        {
+            onWindowUpdate(null, frame);
+        }
+    }
+
+    @Override
+    public void onConnectionFailure(int error, String reason)
+    {
+        close(error, reason, Callback.NOOP);
+        notifyFailure(this, new IOException(String.format("%d/%s", error, reason)));
+    }
+
+    @Override
+    public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
+    {
+        // Synchronization is necessary to atomically create
+        // the stream id and enqueue the frame to be sent.
+        boolean queued;
+        synchronized (this)
+        {
+            int streamId = frame.getStreamId();
+            if (streamId <= 0)
+            {
+                streamId = streamIds.getAndAdd(2);
+                PriorityFrame priority = frame.getPriority();
+                priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(),
+                        priority.getWeight(), priority.isExclusive());
+                frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
+            }
+            final IStream stream = createLocalStream(streamId, promise);
+            if (stream == null)
+                return;
+            stream.setListener(listener);
+
+            ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream));
+            queued = flusher.append(entry);
+        }
+        // Iterate outside the synchronized block.
+        if (queued)
+            flusher.iterate();
+    }
+
+    @Override
+    public int priority(PriorityFrame frame, Callback callback)
+    {
+        int streamId = frame.getStreamId();
+        IStream stream = streams.get(streamId);
+        if (stream == null)
+        {
+            streamId = streamIds.getAndAdd(2);
+            frame = new PriorityFrame(streamId, frame.getParentStreamId(),
+                    frame.getWeight(), frame.isExclusive());
+        }
+        control(stream, callback, frame);
+        return streamId;
+    }
+
+    @Override
+    public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener)
+    {
+        // Synchronization is necessary to atomically create
+        // the stream id and enqueue the frame to be sent.
+        boolean queued;
+        synchronized (this)
+        {
+            int streamId = streamIds.getAndAdd(2);
+            frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
+
+            final IStream pushStream = createLocalStream(streamId, promise);
+            if (pushStream == null)
+                return;
+            pushStream.setListener(listener);
+
+            ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
+            queued = flusher.append(entry);
+        }
+        // Iterate outside the synchronized block.
+        if (queued)
+            flusher.iterate();
+    }
+
+
+    @Override
+    public void settings(SettingsFrame frame, Callback callback)
+    {
+        control(null, callback, frame);
+    }
+
+    @Override
+    public void ping(PingFrame frame, Callback callback)
+    {
+        if (frame.isReply())
+            callback.failed(new IllegalArgumentException());
+        else
+            control(null, callback, frame);
+    }
+
+    protected void reset(ResetFrame frame, Callback callback)
+    {
+        control(getStream(frame.getStreamId()), callback, frame);
+    }
+
+    /**
+     * Invoked internally and by applications to send a GO_AWAY frame to the
+     * other peer. We check the close state to act appropriately:
+     *
+     * * NOT_CLOSED: we move to LOCALLY_CLOSED and queue a GO_AWAY. When the
+     *   GO_AWAY has been written, it will only cause the output to be shut
+     *   down (not the connection closed), so that the application can still
+     *   read frames arriving from the other peer.
+     *   Ideally the other peer will notice the GO_AWAY and close the connection.
+     *   When that happen, we close the connection from {@link #onShutdown()}.
+     *   Otherwise, the idle timeout mechanism will close the connection, see
+     *   {@link #onIdleTimeout()}.
+     *
+     * * In all other cases, we do nothing since other methods are already
+     *   performing their actions.
+     *
+     * @param error the error code
+     * @param reason the reason
+     * @param callback the callback to invoke when the operation is complete
+     * @see #onGoAway(GoAwayFrame)
+     * @see #onShutdown()
+     * @see #onIdleTimeout()
+     */
+    @Override
+    public boolean close(int error, String reason, Callback callback)
+    {
+        while (true)
+        {
+            CloseState current = closed.get();
+            switch (current)
+            {
+                case NOT_CLOSED:
+                {
+                    if (closed.compareAndSet(current, CloseState.LOCALLY_CLOSED))
+                    {
+                        byte[] payload = null;
+                        if (reason != null)
+                        {
+                            // Trim the reason to avoid attack vectors.
+                            reason = reason.substring(0, Math.min(reason.length(), 32));
+                            payload = reason.getBytes(StandardCharsets.UTF_8);
+                        }
+                        GoAwayFrame frame = new GoAwayFrame(lastStreamId.get(), error, payload);
+                        control(null, callback, frame);
+                        return true;
+                    }
+                    break;
+                }
+                default:
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Ignoring close {}/{}, already closed", error, reason);
+                    callback.succeeded();
+                    return false;
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean isClosed()
+    {
+        return closed.get() != CloseState.NOT_CLOSED;
+    }
+
+    private void control(IStream stream, Callback callback, Frame frame)
+    {
+        frames(stream, callback, frame, Frame.EMPTY_ARRAY);
+    }
+
+    @Override
+    public void frames(IStream stream, Callback callback, Frame frame, Frame... frames)
+    {
+        // We want to generate as late as possible to allow re-prioritization;
+        // generation will happen while processing the entries.
+
+        // The callback needs to be notified only when the last frame completes.
+
+        int length = frames.length;
+        if (length == 0)
+        {
+            frame(new ControlEntry(frame, stream, callback), true);
+        }
+        else
+        {
+            callback = new CountingCallback(callback, 1 + length);
+            frame(new ControlEntry(frame, stream, callback), false);
+            for (int i = 1; i <= length; ++i)
+                frame(new ControlEntry(frames[i - 1], stream, callback), i == length);
+        }
+    }
+
+    @Override
+    public void data(IStream stream, Callback callback, DataFrame frame)
+    {
+        // We want to generate as late as possible to allow re-prioritization.
+        frame(new DataEntry(frame, stream, callback), true);
+    }
+
+    private void frame(HTTP2Flusher.Entry entry, boolean flush)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Sending {}", entry.frame);
+        // Ping frames are prepended to process them as soon as possible.
+        boolean queued = entry.frame.getType() == FrameType.PING ? flusher.prepend(entry) : flusher.append(entry);
+        if (queued && flush)
+            flusher.iterate();
+    }
+
+    protected IStream createLocalStream(int streamId, Promise<Stream> promise)
+    {
+        while (true)
+        {
+            int localCount = localStreamCount.get();
+            int maxCount = maxLocalStreams;
+            if (maxCount >= 0 && localCount >= maxCount)
+            {
+                promise.failed(new IllegalStateException("Max local stream count " + maxCount + " exceeded"));
+                return null;
+            }
+            if (localStreamCount.compareAndSet(localCount, localCount + 1))
+                break;
+        }
+
+        IStream stream = newStream(streamId, true);
+        if (streams.putIfAbsent(streamId, stream) == null)
+        {
+            stream.setIdleTimeout(getStreamIdleTimeout());
+            flowControl.onStreamCreated(stream);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Created local {}", stream);
+            return stream;
+        }
+        else
+        {
+            promise.failed(new IllegalStateException("Duplicate stream " + streamId));
+            return null;
+        }
+    }
+
+    protected IStream createRemoteStream(int streamId)
+    {
+        // SPEC: exceeding max concurrent streams is treated as stream error.
+        while (true)
+        {
+            int remoteCount = remoteStreamCount.get();
+            int maxCount = getMaxRemoteStreams();
+            if (maxCount >= 0 && remoteCount >= maxCount)
+            {
+                reset(new ResetFrame(streamId, ErrorCode.REFUSED_STREAM_ERROR.code), Callback.NOOP);
+                return null;
+            }
+            if (remoteStreamCount.compareAndSet(remoteCount, remoteCount + 1))
+                break;
+        }
+
+        IStream stream = newStream(streamId, false);
+
+        // SPEC: duplicate stream is treated as connection error.
+        if (streams.putIfAbsent(streamId, stream) == null)
+        {
+            updateLastStreamId(streamId);
+            stream.setIdleTimeout(getStreamIdleTimeout());
+            flowControl.onStreamCreated(stream);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Created remote {}", stream);
+            return stream;
+        }
+        else
+        {
+            close(ErrorCode.PROTOCOL_ERROR.code, "duplicate_stream", Callback.NOOP);
+            return null;
+        }
+    }
+
+    protected IStream newStream(int streamId, boolean local)
+    {
+        return new HTTP2Stream(scheduler, this, streamId, local);
+    }
+
+    @Override
+    public void removeStream(IStream stream)
+    {
+        IStream removed = streams.remove(stream.getId());
+        if (removed != null)
+        {
+            assert removed == stream;
+
+            boolean local = stream.isLocal();
+            if (local)
+                localStreamCount.decrementAndGet();
+            else
+                remoteStreamCount.decrementAndGet();
+
+            flowControl.onStreamDestroyed(stream);
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Removed {} {}", local ? "local" : "remote", stream);
+        }
+    }
+
+    @Override
+    public Collection<Stream> getStreams()
+    {
+        List<Stream> result = new ArrayList<>();
+        result.addAll(streams.values());
+        return result;
+    }
+
+    @ManagedAttribute("The number of active streams")
+    public int getStreamCount()
+    {
+        return streams.size();
+    }
+
+    @Override
+    public IStream getStream(int streamId)
+    {
+        return streams.get(streamId);
+    }
+
+    @ManagedAttribute(value = "The flow control send window", readonly = true)
+    public int getSendWindow()
+    {
+        return sendWindow.get();
+    }
+
+    @ManagedAttribute(value = "The flow control receive window", readonly = true)
+    public int getRecvWindow()
+    {
+        return recvWindow.get();
+    }
+
+    @Override
+    public int updateSendWindow(int delta)
+    {
+        return sendWindow.getAndAdd(delta);
+    }
+
+    @Override
+    public int updateRecvWindow(int delta)
+    {
+        return recvWindow.getAndAdd(delta);
+    }
+
+    @Override
+    public void onWindowUpdate(IStream stream, WindowUpdateFrame frame)
+    {
+        // WindowUpdateFrames arrive concurrently with writes.
+        // Increasing (or reducing) the window size concurrently
+        // with writes requires coordination with the flusher, that
+        // decides how many frames to write depending on the available
+        // window sizes. If the window sizes vary concurrently, the
+        // flusher may take non-optimal or wrong decisions.
+        // Here, we "queue" window updates to the flusher, so it will
+        // be the only component responsible for window updates, for
+        // both increments and reductions.
+        flusher.window(stream, frame);
+    }
+
+    @Override
+    @ManagedAttribute(value = "Whether HTTP/2 push is enabled", readonly = true)
+    public boolean isPushEnabled()
+    {
+        return pushEnabled;
+    }
+
+    /**
+     * A typical close by a remote peer involves a GO_AWAY frame followed by TCP FIN.
+     * This method is invoked when the TCP FIN is received, or when an exception is
+     * thrown while reading, and we check the close state to act appropriately:
+     *
+     * * NOT_CLOSED: means that the remote peer did not send a GO_AWAY (abrupt close)
+     *   or there was an exception while reading, and therefore we terminate.
+     *
+     * * LOCALLY_CLOSED: we have sent the GO_AWAY to the remote peer, which received
+     *   it and closed the connection; we queue a disconnect to close the connection
+     *   on the local side.
+     *   The GO_AWAY just shutdown the output, so we need this step to make sure the
+     *   connection is closed. See {@link #close(int, String, Callback)}.
+     *
+     * * REMOTELY_CLOSED: we received the GO_AWAY, and the TCP FIN afterwards, so we
+     *   do nothing since the handling of the GO_AWAY will take care of closing the
+     *   connection. See {@link #onGoAway(GoAwayFrame)}.
+     *
+     * @see #onGoAway(GoAwayFrame)
+     * @see #close(int, String, Callback)
+     * @see #onIdleTimeout()
+     */
+    @Override
+    public void onShutdown()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Shutting down {}", this);
+
+        switch (closed.get())
+        {
+            case NOT_CLOSED:
+            {
+                // The other peer did not send a GO_AWAY, no need to be gentle.
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Abrupt close for {}", this);
+                abort(new ClosedChannelException());
+                break;
+            }
+            case LOCALLY_CLOSED:
+            {
+                // We have closed locally, and only shutdown
+                // the output; now queue a disconnect.
+                control(null, Callback.NOOP, new DisconnectFrame());
+                break;
+            }
+            case REMOTELY_CLOSED:
+            {
+                // Nothing to do, the GO_AWAY frame we
+                // received will close the connection.
+                break;
+            }
+            default:
+            {
+                break;
+            }
+        }
+    }
+
+    /**
+     * This method is invoked when the idle timeout triggers. We check the close state
+     * to act appropriately:
+     *
+     * * NOT_CLOSED: it's a real idle timeout, we just initiate a close, see
+     *   {@link #close(int, String, Callback)}.
+     *
+     * * LOCALLY_CLOSED: we have sent a GO_AWAY and only shutdown the output, but the
+     *   other peer did not close the connection so we never received the TCP FIN, and
+     *   therefore we terminate.
+     *
+     * * REMOTELY_CLOSED: the other peer sent us a GO_AWAY, we should have queued a
+     *   disconnect, but for some reason it was not processed (for example, queue was
+     *   stuck because of TCP congestion), therefore we terminate.
+     *   See {@link #onGoAway(GoAwayFrame)}.
+     *
+     * @return true if the session should be closed, false otherwise
+     * @see #onGoAway(GoAwayFrame)
+     * @see #close(int, String, Callback)
+     * @see #onShutdown()
+     */
+    @Override
+    public boolean onIdleTimeout()
+    {
+        switch (closed.get())
+        {
+            case NOT_CLOSED:
+            {
+                return notifyIdleTimeout(this);
+            }
+            case LOCALLY_CLOSED:
+            case REMOTELY_CLOSED:
+            {
+                abort(new TimeoutException());
+                return false;
+            }
+            default:
+            {
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public void onFrame(Frame frame)
+    {
+        onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "upgrade");
+    }
+
+    public void disconnect()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Disconnecting {}", this);
+        endPoint.close();
+    }
+
+    private void terminate()
+    {
+        while (true)
+        {
+            CloseState current = closed.get();
+            switch (current)
+            {
+                case NOT_CLOSED:
+                case LOCALLY_CLOSED:
+                case REMOTELY_CLOSED:
+                {
+                    if (closed.compareAndSet(current, CloseState.CLOSED))
+                    {
+                        flusher.close();
+                        for (IStream stream : streams.values())
+                            stream.close();
+                        streams.clear();
+                        disconnect();
+                        return;
+                    }
+                    break;
+                }
+                default:
+                {
+                    return;
+                }
+            }
+        }
+    }
+
+    protected void abort(Throwable failure)
+    {
+        terminate();
+        notifyFailure(this, failure);
+    }
+
+    public boolean isDisconnected()
+    {
+        return !endPoint.isOpen();
+    }
+
+    private void updateLastStreamId(int streamId)
+    {
+        Atomics.updateMax(lastStreamId, streamId);
+    }
+
+    protected Stream.Listener notifyNewStream(Stream stream, HeadersFrame frame)
+    {
+        try
+        {
+            return listener.onNewStream(stream, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+            return null;
+        }
+    }
+
+    protected void notifySettings(Session session, SettingsFrame frame)
+    {
+        try
+        {
+            listener.onSettings(session, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyPing(Session session, PingFrame frame)
+    {
+        try
+        {
+            listener.onPing(session, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyReset(Session session, ResetFrame frame)
+    {
+        try
+        {
+            listener.onReset(session, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyClose(Session session, GoAwayFrame frame)
+    {
+        try
+        {
+            listener.onClose(session, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected boolean notifyIdleTimeout(Session session)
+    {
+        try
+        {
+            return listener.onIdleTimeout(session);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+            return true;
+        }
+    }
+
+    protected void notifyFailure(Session session, Throwable failure)
+    {
+        try
+        {
+            listener.onFailure(session, failure);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x{l:%s <-> r:%s,queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d,%s}",
+                getClass().getSimpleName(),
+                hashCode(),
+                getEndPoint().getLocalAddress(),
+                getEndPoint().getRemoteAddress(),
+                flusher.getQueueSize(),
+                sendWindow,
+                recvWindow,
+                streams.size(),
+                closed);
+    }
+
+    private class ControlEntry extends HTTP2Flusher.Entry
+    {
+        private ControlEntry(Frame frame, IStream stream, Callback callback)
+        {
+            super(frame, stream, callback);
+        }
+
+        public Throwable generate(ByteBufferPool.Lease lease)
+        {
+            try
+            {
+                generator.control(lease, frame);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Generated {}", frame);
+                prepare();
+                return null;
+            }
+            catch (Throwable x)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Failure generating frame " + frame, x);
+                return x;
+            }
+        }
+
+        /**
+         * <p>Performs actions just before writing the frame to the network.</p>
+         * <p>Some frame, when sent over the network, causes the receiver
+         * to react and send back frames that may be processed by the original
+         * sender *before* {@link #succeeded()} is called.
+         * <p>If the action to perform updates some state, this update may
+         * not be seen by the received frames and cause errors.</p>
+         * <p>For example, suppose the action updates the stream window to a
+         * larger value; the sender sends the frame; the receiver is now entitled
+         * to send back larger data; when the data is received by the original
+         * sender, the action may have not been performed yet, causing the larger
+         * data to be rejected, when it should have been accepted.</p>
+         */
+        private void prepare()
+        {
+            switch (frame.getType())
+            {
+                case SETTINGS:
+                {
+                    SettingsFrame settingsFrame = (SettingsFrame)frame;
+                    Integer initialWindow = settingsFrame.getSettings().get(SettingsFrame.INITIAL_WINDOW_SIZE);
+                    if (initialWindow != null)
+                        flowControl.updateInitialStreamWindow(HTTP2Session.this, initialWindow, true);
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+            }
+        }
+
+        @Override
+        public void succeeded()
+        {
+            switch (frame.getType())
+            {
+                case HEADERS:
+                {
+                    HeadersFrame headersFrame = (HeadersFrame)frame;
+                    if (stream.updateClose(headersFrame.isEndStream(), true))
+                        removeStream(stream);
+                    break;
+                }
+                case RST_STREAM:
+                {
+                    if (stream != null)
+                    {
+                        stream.close();
+                        removeStream(stream);
+                    }
+                    break;
+                }
+                case PUSH_PROMISE:
+                {
+                    // Pushed streams are implicitly remotely closed.
+                    // They are closed when sending an end-stream DATA frame.
+                    stream.updateClose(true, false);
+                    break;
+                }
+                case GO_AWAY:
+                {
+                    // We just sent a GO_AWAY, only shutdown the
+                    // output without closing yet, to allow reads.
+                    getEndPoint().shutdownOutput();
+                    break;
+                }
+                case WINDOW_UPDATE:
+                {
+                    flowControl.windowUpdate(HTTP2Session.this, stream, (WindowUpdateFrame)frame);
+                    break;
+                }
+                case DISCONNECT:
+                {
+                    terminate();
+                    break;
+                }
+                default:
+                {
+                    break;
+                }
+            }
+            callback.succeeded();
+        }
+    }
+
+    private class DataEntry extends HTTP2Flusher.Entry
+    {
+        private int length;
+
+        private DataEntry(DataFrame frame, IStream stream, Callback callback)
+        {
+            super(frame, stream, callback);
+        }
+
+        @Override
+        public int dataRemaining()
+        {
+            // We don't do any padding, so the flow control length is
+            // always the data remaining. This simplifies the handling
+            // of data frames that cannot be completely written due to
+            // the flow control window exhausting, since in that case
+            // we would have to count the padding only once.
+            return ((DataFrame)frame).remaining();
+        }
+
+        public Throwable generate(ByteBufferPool.Lease lease)
+        {
+            try
+            {
+                int flowControlLength = dataRemaining();
+
+                int sessionSendWindow = getSendWindow();
+                if (sessionSendWindow < 0)
+                    throw new IllegalStateException();
+
+                int streamSendWindow = stream.updateSendWindow(0);
+                if (streamSendWindow < 0)
+                    throw new IllegalStateException();
+
+                int window = Math.min(streamSendWindow, sessionSendWindow);
+
+                int length = this.length = Math.min(flowControlLength, window);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Generated {}, length/window={}/{}", frame, length, window);
+
+                generator.data(lease, (DataFrame)frame, length);
+                flowControl.onDataSending(stream, length);
+                return null;
+            }
+            catch (Throwable x)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Failure generating frame " + frame, x);
+                return x;
+            }
+        }
+
+        @Override
+        public void succeeded()
+        {
+            flowControl.onDataSent(stream, length);
+            // Do we have more to send ?
+            DataFrame dataFrame = (DataFrame)frame;
+            if (dataFrame.remaining() > 0)
+            {
+                // We have written part of the frame, but there is more to write.
+                // We need to keep the correct ordering of frames, to avoid that other
+                // frames for the same stream are written before this one is finished.
+                flusher.prepend(this);
+            }
+            else
+            {
+                // Only now we can update the close state
+                // and eventually remove the stream.
+                if (stream.updateClose(dataFrame.isEndStream(), true))
+                    removeStream(stream);
+                callback.succeeded();
+            }
+        }
+    }
+
+    private static class PromiseCallback<C> implements Callback
+    {
+        private final Promise<C> promise;
+        private final C value;
+
+        private PromiseCallback(Promise<C> promise, C value)
+        {
+            this.promise = promise;
+            this.value = value;
+        }
+
+        @Override
+        public void succeeded()
+        {
+            promise.succeeded(value);
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            promise.failed(x);
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java
new file mode 100644
index 0000000..6a9b096
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java
@@ -0,0 +1,414 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.io.IdleTimeout;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+public class HTTP2Stream extends IdleTimeout implements IStream
+{
+    private static final Logger LOG = Log.getLogger(HTTP2Stream.class);
+
+    private final AtomicReference<ConcurrentMap<String, Object>> attributes = new AtomicReference<>();
+    private final AtomicReference<CloseState> closeState = new AtomicReference<>(CloseState.NOT_CLOSED);
+    private final AtomicInteger sendWindow = new AtomicInteger();
+    private final AtomicInteger recvWindow = new AtomicInteger();
+    private final ISession session;
+    private final int streamId;
+    private final boolean local;
+    private volatile Listener listener;
+    private volatile boolean localReset;
+    private volatile boolean remoteReset;
+
+    public HTTP2Stream(Scheduler scheduler, ISession session, int streamId, boolean local)
+    {
+        super(scheduler);
+        this.session = session;
+        this.streamId = streamId;
+        this.local = local;
+    }
+
+    @Override
+    public int getId()
+    {
+        return streamId;
+    }
+
+    @Override
+    public boolean isLocal()
+    {
+        return local;
+    }
+
+    @Override
+    public ISession getSession()
+    {
+        return session;
+    }
+
+    @Override
+    public void headers(HeadersFrame frame, Callback callback)
+    {
+        notIdle();
+        session.frames(this, callback, frame, Frame.EMPTY_ARRAY);
+    }
+
+    @Override
+    public void push(PushPromiseFrame frame, Promise<Stream> promise, Listener listener)
+    {
+        notIdle();
+        session.push(this, promise, frame, listener);
+    }
+
+    @Override
+    public void data(DataFrame frame, Callback callback)
+    {
+        notIdle();
+        session.data(this, callback, frame);
+    }
+
+    @Override
+    public void reset(ResetFrame frame, Callback callback)
+    {
+        if (isReset())
+            return;
+        notIdle();
+        localReset = true;
+        session.frames(this, callback, frame, Frame.EMPTY_ARRAY);
+    }
+
+    @Override
+    public Object getAttribute(String key)
+    {
+        return attributes().get(key);
+    }
+
+    @Override
+    public void setAttribute(String key, Object value)
+    {
+        attributes().put(key, value);
+    }
+
+    @Override
+    public Object removeAttribute(String key)
+    {
+        return attributes().remove(key);
+    }
+
+    @Override
+    public boolean isReset()
+    {
+        return localReset || remoteReset;
+    }
+
+    @Override
+    public boolean isClosed()
+    {
+        return closeState.get() == CloseState.CLOSED;
+    }
+
+    public boolean isRemotelyClosed()
+    {
+        return closeState.get() == CloseState.REMOTELY_CLOSED;
+    }
+
+    public boolean isLocallyClosed()
+    {
+        return closeState.get() == CloseState.LOCALLY_CLOSED;
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return !isClosed();
+    }
+
+    @Override
+    protected void onIdleExpired(TimeoutException timeout)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Idle timeout {}ms expired on {}", getIdleTimeout(), this);
+
+        // The stream is now gone, we must close it to
+        // avoid that its idle timeout is rescheduled.
+        close();
+
+        // Tell the other peer that we timed out.
+        reset(new ResetFrame(getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+
+        // Notify the application.
+        notifyTimeout(this, timeout);
+    }
+
+    private ConcurrentMap<String, Object> attributes()
+    {
+        ConcurrentMap<String, Object> map = attributes.get();
+        if (map == null)
+        {
+            map = new ConcurrentHashMap<>();
+            if (!attributes.compareAndSet(null, map))
+            {
+                map = attributes.get();
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public Listener getListener()
+    {
+        return listener;
+    }
+
+    @Override
+    public void setListener(Listener listener)
+    {
+        this.listener = listener;
+    }
+
+    @Override
+    public void process(Frame frame, Callback callback)
+    {
+        notIdle();
+        switch (frame.getType())
+        {
+            case HEADERS:
+            {
+                onHeaders((HeadersFrame)frame, callback);
+                break;
+            }
+            case DATA:
+            {
+                onData((DataFrame)frame, callback);
+                break;
+            }
+            case RST_STREAM:
+            {
+                onReset((ResetFrame)frame, callback);
+                break;
+            }
+            case PUSH_PROMISE:
+            {
+                onPush((PushPromiseFrame)frame, callback);
+                break;
+            }
+            default:
+            {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+
+    private void onHeaders(HeadersFrame frame, Callback callback)
+    {
+        if (updateClose(frame.isEndStream(), false))
+            session.removeStream(this);
+        callback.succeeded();
+    }
+
+    private void onData(DataFrame frame, Callback callback)
+    {
+        if (getRecvWindow() < 0)
+        {
+            // It's a bad client, it does not deserve to be
+            // treated gently by just resetting the stream.
+            session.close(ErrorCode.FLOW_CONTROL_ERROR.code, "stream_window_exceeded", Callback.NOOP);
+            callback.failed(new IOException("stream_window_exceeded"));
+            return;
+        }
+
+        // SPEC: remotely closed streams must be replied with a reset.
+        if (isRemotelyClosed())
+        {
+            reset(new ResetFrame(streamId, ErrorCode.STREAM_CLOSED_ERROR.code), Callback.NOOP);
+            callback.failed(new EOFException("stream_closed"));
+            return;
+        }
+
+        if (isReset())
+        {
+            // Just drop the frame.
+            callback.failed(new IOException("stream_reset"));
+            return;
+        }
+
+        if (updateClose(frame.isEndStream(), false))
+            session.removeStream(this);
+        notifyData(this, frame, callback);
+    }
+
+    private void onReset(ResetFrame frame, Callback callback)
+    {
+        remoteReset = true;
+        close();
+        session.removeStream(this);
+        callback.succeeded();
+        notifyReset(this, frame);
+    }
+
+    private void onPush(PushPromiseFrame frame, Callback callback)
+    {
+        // Pushed streams are implicitly locally closed.
+        // They are closed when receiving an end-stream DATA frame.
+        updateClose(true, true);
+        callback.succeeded();
+    }
+
+    @Override
+    public boolean updateClose(boolean update, boolean local)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Update close for {} close={} local={}", this, update, local);
+
+        if (!update)
+            return false;
+
+        while (true)
+        {
+            CloseState current = closeState.get();
+            switch (current)
+            {
+                case NOT_CLOSED:
+                {
+                    CloseState newValue = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED;
+                    if (closeState.compareAndSet(current, newValue))
+                        return false;
+                    break;
+                }
+                case LOCALLY_CLOSED:
+                {
+                    if (local)
+                        return false;
+                    close();
+                    return true;
+                }
+                case REMOTELY_CLOSED:
+                {
+                    if (!local)
+                        return false;
+                    close();
+                    return true;
+                }
+                default:
+                {
+                    return false;
+                }
+            }
+        }
+    }
+
+    public int getSendWindow()
+    {
+        return sendWindow.get();
+    }
+
+    public int getRecvWindow()
+    {
+        return recvWindow.get();
+    }
+
+    @Override
+    public int updateSendWindow(int delta)
+    {
+        return sendWindow.getAndAdd(delta);
+    }
+
+    @Override
+    public int updateRecvWindow(int delta)
+    {
+        return recvWindow.getAndAdd(delta);
+    }
+
+    @Override
+    public void close()
+    {
+        closeState.set(CloseState.CLOSED);
+        onClose();
+    }
+
+    private void notifyData(Stream stream, DataFrame frame, Callback callback)
+    {
+        final Listener listener = this.listener;
+        if (listener == null)
+            return;
+        try
+        {
+            listener.onData(stream, frame, callback);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    private void notifyReset(Stream stream, ResetFrame frame)
+    {
+        final Listener listener = this.listener;
+        if (listener == null)
+            return;
+        try
+        {
+            listener.onReset(stream, frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    private void notifyTimeout(Stream stream, Throwable failure)
+    {
+        Listener listener = this.listener;
+        if (listener == null)
+            return;
+        try
+        {
+            listener.onTimeout(stream, failure);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x#%d{sendWindow=%s,recvWindow=%s,reset=%b,%s}", getClass().getSimpleName(),
+                hashCode(), getId(), sendWindow, recvWindow, isReset(), closeState);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
new file mode 100644
index 0000000..81eea91
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
@@ -0,0 +1,130 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+
+/**
+ * <p>The SPI interface for implementing a HTTP/2 session.</p>
+ * <p>This class extends {@link Session} by adding the methods required to
+ * implement the HTTP/2 session functionalities.</p>
+ */
+public interface ISession extends Session
+{
+    @Override
+    public IStream getStream(int streamId);
+
+    /**
+     * <p>Removes the given {@code stream}.</p>
+     *
+     * @param stream the stream to remove
+     */
+    public void removeStream(IStream stream);
+
+    /**
+     * <p>Enqueues the given frames to be written to the connection.</p>
+     *
+     * @param stream   the stream the frames belong to
+     * @param callback the callback that gets notified when the frames have been sent
+     * @param frame    the first frame to enqueue
+     * @param frames   additional frames to enqueue
+     */
+    public void frames(IStream stream, Callback callback, Frame frame, Frame... frames);
+
+    /**
+     * <p>Enqueues the given PUSH_PROMISE frame to be written to the connection.</p>
+     * <p>Differently from {@link #frames(IStream, Callback, Frame, Frame...)}, this method
+     * generates atomically the stream id for the pushed stream.</p>
+     *
+     * @param stream   the stream associated to the pushed stream
+     * @param promise  the promise that gets notified of the pushed stream creation
+     * @param frame    the PUSH_PROMISE frame to enqueue
+     * @param listener the listener that gets notified of pushed stream events
+     */
+    public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener);
+
+    /**
+     * <p>Enqueues the given DATA frame to be written to the connection.</p>
+     *
+     * @param stream   the stream the data frame belongs to
+     * @param callback the callback that gets notified when the frame has been sent
+     * @param frame    the DATA frame to send
+     */
+    public void data(IStream stream, Callback callback, DataFrame frame);
+
+    /**
+     * <p>Updates the session send window by the given {@code delta}.</p>
+     *
+     * @param delta the delta value (positive or negative) to add to the session send window
+     * @return the previous value of the session send window
+     */
+    public int updateSendWindow(int delta);
+
+    /**
+     * <p>Updates the session receive window by the given {@code delta}.</p>
+     *
+     * @param delta the delta value (positive or negative) to add to the session receive window
+     * @return the previous value of the session receive window
+     */
+    public int updateRecvWindow(int delta);
+
+    /**
+     * <p>Callback method invoked when a WINDOW_UPDATE frame has been received.</p>
+     *
+     * @param stream the stream the window update belongs to, or null if the window update belongs to the session
+     * @param frame  the WINDOW_UPDATE frame received
+     */
+    public void onWindowUpdate(IStream stream, WindowUpdateFrame frame);
+
+    /**
+     * @return whether the push functionality is enabled
+     */
+    public boolean isPushEnabled();
+
+    /**
+     * <p>Callback invoked when the connection reads -1.</p>
+     *
+     * @see #onIdleTimeout()
+     * @see #close(int, String, Callback)
+     */
+    public void onShutdown();
+
+    /**
+     * <p>Callback invoked when the idle timeout expires.</p>
+     *
+     * @see #onShutdown()
+     * @see #close(int, String, Callback)
+     */
+    public boolean onIdleTimeout();
+
+    /**
+     * <p>Callback method invoked during an HTTP/1.1 to HTTP/2 upgrade requests
+     * to process the given synthetic frame.</p>
+     *
+     * @param frame the synthetic frame to process
+     */
+    public void onFrame(Frame frame);
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java
new file mode 100644
index 0000000..32b2f8e
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java
@@ -0,0 +1,102 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import java.io.Closeable;
+
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.util.Callback;
+
+/**
+ * <p>The SPI interface for implementing a HTTP/2 stream.</p>
+ * <p>This class extends {@link Stream} by adding the methods required to
+ * implement the HTTP/2 stream functionalities.</p>
+ */
+public interface IStream extends Stream, Closeable
+{
+    /**
+     * <p>The constant used as attribute key to store/retrieve the HTTP
+     * channel associated with this stream</p>
+     *
+     * @see #setAttribute(String, Object)
+     */
+    public static final String CHANNEL_ATTRIBUTE = IStream.class.getName() + ".channel";
+
+    /**
+     * @return whether this stream is local or remote
+     */
+    public boolean isLocal();
+
+    @Override
+    public ISession getSession();
+
+    /**
+     * @return the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream
+     * @see #setListener(Listener)
+     */
+    public Listener getListener();
+
+    /**
+     * @param listener the {@link org.eclipse.jetty.http2.api.Stream.Listener} associated with this stream
+     * @see #getListener()
+     */
+    public void setListener(Listener listener);
+
+    /**
+     * <p>Processes the given {@code frame}, belonging to this stream.</p>
+     *
+     * @param frame the frame to process
+     * @param callback the callback to complete when frame has been processed
+     */
+    public void process(Frame frame, Callback callback);
+
+    /**
+     * <p>Updates the close state of this stream.</p>
+     *
+     * @param update whether to update the close state
+     * @param local  whether the update comes from a local operation
+     *               (such as sending a frame that ends the stream)
+     *               or a remote operation (such as receiving a frame
+     * @return whether the stream has been fully closed by this invocation
+     */
+    public boolean updateClose(boolean update, boolean local);
+
+    /**
+     * <p>Forcibly closes this stream.</p>
+     */
+    @Override
+    public void close();
+
+    /**
+     * <p>Updates the stream send window by the given {@code delta}.</p>
+     *
+     * @param delta the delta value (positive or negative) to add to the stream send window
+     * @return the previous value of the stream send window
+     */
+    public int updateSendWindow(int delta);
+
+    /**
+     * <p>Updates the stream receive window by the given {@code delta}.</p>
+     *
+     * @param delta the delta value (positive or negative) to add to the stream receive window
+     * @return the previous value of the stream receive window
+     */
+    public int updateRecvWindow(int delta);
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java
new file mode 100644
index 0000000..002ffef
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/SimpleFlowControlStrategy.java
@@ -0,0 +1,72 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.util.Callback;
+
+public class SimpleFlowControlStrategy extends AbstractFlowControlStrategy
+{
+    public SimpleFlowControlStrategy()
+    {
+        this(DEFAULT_WINDOW_SIZE);
+    }
+
+    public SimpleFlowControlStrategy(int initialStreamSendWindow)
+    {
+        super(initialStreamSendWindow);
+    }
+
+    @Override
+    public void onDataConsumed(ISession session, IStream stream, int length)
+    {
+        if (length <= 0)
+            return;
+
+        // This is the simple algorithm for flow control.
+        // This method is called when a whole flow controlled frame has been consumed.
+        // We send a WindowUpdate every time, even if the frame was very small.
+
+        WindowUpdateFrame sessionFrame = new WindowUpdateFrame(0, length);
+        session.updateRecvWindow(length);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Data consumed, increased session recv window by {} for {}", length, session);
+
+        Frame[] streamFrame = Frame.EMPTY_ARRAY;
+        if (stream != null)
+        {
+            if (stream.isClosed())
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Data consumed, ignoring update stream recv window by {} for closed {}", length, stream);
+            }
+            else
+            {
+                streamFrame = new Frame[1];
+                streamFrame[0] = new WindowUpdateFrame(stream.getId(), length);
+                stream.updateRecvWindow(length);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Data consumed, increased stream recv window by {} for {}", length, stream);
+            }
+        }
+
+        session.frames(stream, Callback.NOOP, sessionFrame, streamFrame);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java
new file mode 100644
index 0000000..eabcfad
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java
@@ -0,0 +1,267 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.api;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+
+/**
+ * <p>A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.</p>
+ * <p>Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:</p>
+ * <pre>
+ * Session session = ...;
+ * HeadersFrame frame = ...;
+ * Promise&lt;Stream&gt; promise = ...
+ * session.newStream(frame, promise, new Stream.Listener.Adapter()
+ * {
+ *     public void onHeaders(Stream stream, HeadersFrame frame)
+ *     {
+ *         // Reply received
+ *     }
+ * });
+ * </pre>
+ * <p>A {@link Session} is the active part of the endpoint, and by calling its API applications can generate
+ * events on the connection; conversely {@link Session.Listener} is the passive part of the endpoint, and
+ * has callbacks that are invoked when events happen on the connection.</p>
+ *
+ * @see Session.Listener
+ */
+public interface Session
+{
+    /**
+     * <p>Sends the given HEADERS {@code frame} to create a new {@link Stream}.</p>
+     *
+     * @param frame    the HEADERS frame containing the HTTP headers
+     * @param promise  the promise that gets notified of the stream creation
+     * @param listener the listener that gets notified of stream events
+     */
+    public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener);
+
+    /**
+     * <p>Sends the given PRIORITY {@code frame}.</p>
+     * <p>If the {@code frame} references a {@code streamId} that does not exist
+     * (for example {@code 0}), then a new {@code streamId} will be allocated, to
+     * support <em>unused anchor streams</em> that act as parent for other streams.</p>
+     *
+     * @param frame    the PRIORITY frame to send
+     * @param callback the callback that gets notified when the frame has been sent
+     * @return         the new stream id generated by the PRIORITY frame, or the stream id
+     *                 that it is already referencing
+     */
+    public int priority(PriorityFrame frame, Callback callback);
+
+    /**
+     * <p>Sends the given SETTINGS {@code frame} to configure the session.</p>
+     *
+     * @param frame    the SETTINGS frame to send
+     * @param callback the callback that gets notified when the frame has been sent
+     */
+    public void settings(SettingsFrame frame, Callback callback);
+
+    /**
+     * <p>Sends the given PING {@code frame}.</p>
+     * <p>PING frames may be used to test the connection integrity and to measure
+     * round-trip time.</p>
+     *
+     * @param frame    the PING frame to send
+     * @param callback the callback that gets notified when the frame has been sent
+     */
+    public void ping(PingFrame frame, Callback callback);
+
+    /**
+     * <p>Closes the session by sending a GOAWAY frame with the given error code
+     * and payload.</p>
+     * <p>The GOAWAY frame is sent only once; subsequent or concurrent attempts to
+     * close the session will have no effect.</p>
+     *
+     * @param error    the error code
+     * @param payload  an optional payload (may be null)
+     * @param callback the callback that gets notified when the frame has been sent
+     * @return true if the frame is being sent, false if the session was already closed
+     */
+    public boolean close(int error, String payload, Callback callback);
+
+    /**
+     * @return whether the session is not open
+     */
+    public boolean isClosed();
+
+    /**
+     * @return a snapshot of all the streams currently belonging to this session
+     */
+    public Collection<Stream> getStreams();
+
+    /**
+     * <p>Retrieves the stream with the given {@code streamId}.</p>
+     *
+     * @param streamId the stream id of the stream looked for
+     * @return the stream with the given id, or null if no such stream exist
+     */
+    public Stream getStream(int streamId);
+
+    /**
+     * <p>A {@link Listener} is the passive counterpart of a {@link Session} and
+     * receives events happening on a HTTP/2 connection.</p>
+     *
+     * @see Session
+     */
+    public interface Listener
+    {
+        /**
+         * <p>Callback method invoked:</p>
+         * <ul>
+         *     <li>for clients, just before the preface is sent, to gather the
+         *     SETTINGS configuration options the client wants to send to the server;</li>
+         *     <li>for servers, just after having received the preface, to gather
+         *     the SETTINGS configuration options the server wants to send to the
+         *     client.</li>
+         * </ul>
+         *
+         * @param session the session
+         * @return a (possibly empty or null) map containing SETTINGS configuration
+         * options to send.
+         */
+        public Map<Integer, Integer> onPreface(Session session);
+
+        /**
+         * <p>Callback method invoked when a new stream is being created upon
+         * receiving a HEADERS frame representing a HTTP request.</p>
+         * <p>Applications should implement this method to process HTTP requests,
+         * typically providing a HTTP response via
+         * {@link Stream#headers(HeadersFrame, Callback)}.</p>
+         * <p>Applications can detect whether request DATA frames will be arriving
+         * by testing {@link HeadersFrame#isEndStream()}. If the application is
+         * interested in processing the DATA frames, it must return a
+         * {@link Stream.Listener} implementation that overrides
+         * {@link Stream.Listener#onData(Stream, DataFrame, Callback)}.</p>
+         *
+         * @param stream the newly created stream
+         * @param frame  the HEADERS frame received
+         * @return a {@link Stream.Listener} that will be notified of stream events
+         */
+        public Stream.Listener onNewStream(Stream stream, HeadersFrame frame);
+
+        /**
+         * <p>Callback method invoked when a SETTINGS frame has been received.</p>
+         *
+         * @param session the session
+         * @param frame   the SETTINGS frame received
+         */
+        public void onSettings(Session session, SettingsFrame frame);
+
+        /**
+         * <p>Callback method invoked when a PING frame has been received.</p>
+         *
+         * @param session the session
+         * @param frame   the PING frame received
+         */
+        public void onPing(Session session, PingFrame frame);
+
+        /**
+         * <p>Callback method invoked when a RST_STREAM frame has been received for an unknown stream.</p>
+         *
+         * @param session the session
+         * @param frame   the RST_STREAM frame received
+         * @see Stream.Listener#onReset(Stream, ResetFrame)
+         */
+        public void onReset(Session session, ResetFrame frame);
+
+        /**
+         * <p>Callback method invoked when a GOAWAY frame has been received.</p>
+         *
+         * @param session the session
+         * @param frame   the GOAWAY frame received
+         */
+        public void onClose(Session session, GoAwayFrame frame);
+
+        /**
+         * <p>Callback method invoked when the idle timeout expired.</p>
+         * @param session the session
+         * @return whether the session should be closed
+         */
+        public boolean onIdleTimeout(Session session);
+
+        /**
+         * <p>Callback method invoked when a failure has been detected for this session.</p>
+         *
+         * @param session the session
+         * @param failure the failure
+         */
+        public void onFailure(Session session, Throwable failure);
+
+        /**
+         * <p>Empty implementation of {@link Stream.Listener}.</p>
+         */
+        public static class Adapter implements Session.Listener
+        {
+            @Override
+            public Map<Integer, Integer> onPreface(Session session)
+            {
+                return null;
+            }
+
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                return null;
+            }
+
+            @Override
+            public void onSettings(Session session, SettingsFrame frame)
+            {
+            }
+
+            @Override
+            public void onPing(Session session, PingFrame frame)
+            {
+            }
+
+            @Override
+            public void onReset(Session session, ResetFrame frame)
+            {
+            }
+
+            @Override
+            public void onClose(Session session, GoAwayFrame frame)
+            {
+            }
+
+            @Override
+            public boolean onIdleTimeout(Session session)
+            {
+                return true;
+            }
+
+            @Override
+            public void onFailure(Session session, Throwable failure)
+            {
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java
new file mode 100644
index 0000000..bbde6f4
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java
@@ -0,0 +1,217 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.api;
+
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+
+/**
+ * <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p>
+ * <p>Differently from socket streams, where the input and output streams are permanently associated
+ * with the socket (and hence with the connection that the socket represents), there can be multiple
+ * HTTP/2 streams present concurrent for a HTTP/2 session.</p>
+ * <p>A {@link Stream} maps to a HTTP request/response cycle, and after the request/response cycle is
+ * completed, the stream is closed and removed from the session.</p>
+ * <p>Like {@link Session}, {@link Stream} is the active part and by calling its API applications
+ * can generate events on the stream; conversely, {@link Stream.Listener} is the passive part, and
+ * its callbacks are invoked when events happen on the stream.</p>
+ *
+ * @see Stream.Listener
+ */
+public interface Stream
+{
+    /**
+     * @return the stream unique id
+     */
+    public int getId();
+
+    /**
+     * @return the session this stream is associated to
+     */
+    public Session getSession();
+
+    /**
+     * <p>Sends the given HEADERS {@code frame} representing a HTTP response.</p>
+     *
+     * @param frame    the HEADERS frame to send
+     * @param callback the callback that gets notified when the frame has been sent
+     */
+    public void headers(HeadersFrame frame, Callback callback);
+
+    /**
+     * <p>Sends the given PUSH_PROMISE {@code frame}.</p>
+     *
+     * @param frame   the PUSH_PROMISE frame to send
+     * @param promise the promise that gets notified of the pushed stream creation
+     * @param listener the listener that gets notified of stream events
+     */
+    public void push(PushPromiseFrame frame, Promise<Stream> promise, Listener listener);
+
+    /**
+     * <p>Sends the given DATA {@code frame}.</p>
+     *
+     * @param frame    the DATA frame to send
+     * @param callback the callback that gets notified when the frame has been sent
+     */
+    public void data(DataFrame frame, Callback callback);
+
+    /**
+     * <p>Sends the given RST_STREAM {@code frame}.</p>
+     *
+     * @param frame    the RST_FRAME to send
+     * @param callback the callback that gets notified when the frame has been sent
+     */
+    public void reset(ResetFrame frame, Callback callback);
+
+    /**
+     * @param key the attribute key
+     * @return an arbitrary object associated with the given key to this stream
+     * or null if no object can be found for the given key.
+     * @see #setAttribute(String, Object)
+     */
+    public Object getAttribute(String key);
+
+    /**
+     * @param key   the attribute key
+     * @param value an arbitrary object to associate with the given key to this stream
+     * @see #getAttribute(String)
+     * @see #removeAttribute(String)
+     */
+    public void setAttribute(String key, Object value);
+
+    /**
+     * @param key the attribute key
+     * @return the arbitrary object associated with the given key to this stream
+     * @see #setAttribute(String, Object)
+     */
+    public Object removeAttribute(String key);
+
+    /**
+     * @return whether this stream has been reset
+     */
+    public boolean isReset();
+
+    /**
+     * @return whether this stream is closed, both locally and remotely.
+     */
+    public boolean isClosed();
+
+    /**
+     * @return the stream idle timeout
+     * @see #setIdleTimeout(long)
+     */
+    public long getIdleTimeout();
+
+    /**
+     * @param idleTimeout the stream idle timeout
+     * @see #getIdleTimeout()
+     * @see Stream.Listener#onTimeout(Stream, Throwable)
+     */
+    public void setIdleTimeout(long idleTimeout);
+
+    /**
+     * <p>A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives
+     * events happening on a HTTP/2 stream.</p>
+     *
+     * @see Stream
+     */
+    public interface Listener
+    {
+        /**
+         * <p>Callback method invoked when a HEADERS frame representing the HTTP response has been received.</p>
+         *
+         * @param stream the stream
+         * @param frame  the HEADERS frame received
+         */
+        public void onHeaders(Stream stream, HeadersFrame frame);
+
+        /**
+         * <p>Callback method invoked when a PUSH_PROMISE frame has been received.</p>
+         *
+         * @param stream the stream
+         * @param frame  the PUSH_PROMISE frame received
+         * @return a {@link Stream.Listener} that will be notified of pushed stream events
+         */
+        public Listener onPush(Stream stream, PushPromiseFrame frame);
+
+        /**
+         * <p>Callback method invoked when a DATA frame has been received.</p>
+         *
+         * @param stream   the stream
+         * @param frame    the DATA frame received
+         * @param callback the callback to complete when the bytes of the DATA frame have been consumed
+         */
+        public void onData(Stream stream, DataFrame frame, Callback callback);
+
+        /**
+         * <p>Callback method invoked when a RST_STREAM frame has been received for this stream.</p>
+         *
+         * @param stream the stream
+         * @param frame  the RST_FRAME received
+         * @see Session.Listener#onReset(Session, ResetFrame)
+         */
+        public void onReset(Stream stream, ResetFrame frame);
+
+        /**
+         * <p>Callback method invoked when the stream exceeds its idle timeout.</p>
+         *
+         * @param stream the stream
+         * @param x      the timeout failure
+         * @see #getIdleTimeout()
+         */
+        public void onTimeout(Stream stream, Throwable x);
+
+        /**
+         * <p>Empty implementation of {@link Listener}</p>
+         */
+        public static class Adapter implements Listener
+        {
+            @Override
+            public void onHeaders(Stream stream, HeadersFrame frame)
+            {
+            }
+
+            @Override
+            public Listener onPush(Stream stream, PushPromiseFrame frame)
+            {
+                return null;
+            }
+
+            @Override
+            public void onData(Stream stream, DataFrame frame, Callback callback)
+            {
+                callback.succeeded();
+            }
+
+            @Override
+            public void onReset(Stream stream, ResetFrame frame)
+            {
+            }
+
+            @Override
+            public void onTimeout(Stream stream, Throwable x)
+            {
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java
new file mode 100644
index 0000000..38d8a2b
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java
@@ -0,0 +1,44 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.api.server;
+
+import org.eclipse.jetty.http2.api.Session;
+
+/**
+ * <p>Server-side extension of {@link org.eclipse.jetty.http2.api.Session.Listener} that exposes additional events.</p>
+ */
+public interface ServerSessionListener extends Session.Listener
+{
+    /**
+     * <p>Callback method invoked when a connection has been accepted by the server.</p>
+     * @param session the session
+     */
+    public void onAccept(Session session);
+
+    /**
+     * <p>Empty implementation of {@link ServerSessionListener}</p>
+     */
+    public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener
+    {
+        @Override
+        public void onAccept(Session session)
+        {
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java
new file mode 100644
index 0000000..1cbd308
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DataFrame.java
@@ -0,0 +1,80 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+
+public class DataFrame extends Frame
+{
+    private final int streamId;
+    private final ByteBuffer data;
+    private final boolean endStream;
+    private final int padding;
+
+    public DataFrame(int streamId, ByteBuffer data, boolean endStream)
+    {
+        this(streamId, data, endStream, 0);
+    }
+
+    public DataFrame(int streamId, ByteBuffer data, boolean endStream, int padding)
+    {
+        super(FrameType.DATA);
+        this.streamId = streamId;
+        this.data = data;
+        this.endStream = endStream;
+        this.padding = padding;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public ByteBuffer getData()
+    {
+        return data;
+    }
+
+    public boolean isEndStream()
+    {
+        return endStream;
+    }
+
+    /**
+     * @return the number of data bytes remaining.
+     */
+    public int remaining()
+    {
+        return data.remaining();
+    }
+
+    /**
+     * @return the number of bytes used for padding that count towards flow control.
+     */
+    public int padding()
+    {
+        return padding;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s#%d{length:%d,end=%b}", super.toString(), streamId, data.remaining(), endStream);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java
new file mode 100644
index 0000000..94bfcd8
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/DisconnectFrame.java
@@ -0,0 +1,27 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+public class DisconnectFrame extends Frame
+{
+    public DisconnectFrame()
+    {
+        super(FrameType.DISCONNECT);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java
new file mode 100644
index 0000000..fde153f
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/Frame.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+public abstract class Frame
+{
+    public static final int HEADER_LENGTH = 9;
+    public static final int DEFAULT_MAX_LENGTH = 0x40_00;
+    public static final int MAX_MAX_LENGTH = 0xFF_FF_FF;
+    public static final Frame[] EMPTY_ARRAY = new Frame[0];
+
+    private final FrameType type;
+
+    protected Frame(FrameType type)
+    {
+        this.type = type;
+    }
+
+    public FrameType getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x", getClass().getSimpleName(), hashCode());
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java
new file mode 100644
index 0000000..b75bb4e
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/FrameType.java
@@ -0,0 +1,62 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum FrameType
+{
+    DATA(0),
+    HEADERS(1),
+    PRIORITY(2),
+    RST_STREAM(3),
+    SETTINGS(4),
+    PUSH_PROMISE(5),
+    PING(6),
+    GO_AWAY(7),
+    WINDOW_UPDATE(8),
+    CONTINUATION(9),
+    // Synthetic frames only needed by the implementation.
+    PREFACE(10),
+    DISCONNECT(11);
+
+    public static FrameType from(int type)
+    {
+        return Types.types.get(type);
+    }
+
+    private final int type;
+
+    private FrameType(int type)
+    {
+        this.type = type;
+        Types.types.put(type, this);
+    }
+
+    public int getType()
+    {
+        return type;
+    }
+
+    private static class Types
+    {
+        private static final Map<Integer, FrameType> types = new HashMap<>();
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java
new file mode 100644
index 0000000..f327860
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/GoAwayFrame.java
@@ -0,0 +1,74 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.BufferUtil;
+
+public class GoAwayFrame extends Frame
+{
+    private final int lastStreamId;
+    private final int error;
+    private final byte[] payload;
+
+    public GoAwayFrame(int lastStreamId, int error, byte[] payload)
+    {
+        super(FrameType.GO_AWAY);
+        this.lastStreamId = lastStreamId;
+        this.error = error;
+        this.payload = payload;
+    }
+
+    public int getLastStreamId()
+    {
+        return lastStreamId;
+    }
+
+    public int getError()
+    {
+        return error;
+    }
+
+    public byte[] getPayload()
+    {
+        return payload;
+    }
+
+    public String tryConvertPayload()
+    {
+        if (payload == null)
+            return "";
+        ByteBuffer buffer = BufferUtil.toBuffer(payload);
+        try
+        {
+            return BufferUtil.toUTF8String(buffer);
+        }
+        catch (Throwable x)
+        {
+            return BufferUtil.toDetailString(buffer);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s,%d/%s", super.toString(), error, tryConvertPayload());
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java
new file mode 100644
index 0000000..f514f52
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/HeadersFrame.java
@@ -0,0 +1,88 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.frames;
+
+import org.eclipse.jetty.http.MetaData;
+
+public class HeadersFrame extends Frame
+{
+    private final int streamId;
+    private final MetaData metaData;
+    private final PriorityFrame priority;
+    private final boolean endStream;
+
+    /**
+     * <p>Creates a new {@code HEADERS} frame with an unspecified stream {@code id}.</p>
+     * <p>The stream {@code id} will be generated by the implementation while sending
+     * this frame to the other peer.</p>
+     *
+     * @param metaData  the metadata containing HTTP request information
+     * @param priority  the PRIORITY frame associated with this HEADERS frame
+     * @param endStream whether this frame ends the stream
+     */
+    public HeadersFrame(MetaData metaData, PriorityFrame priority, boolean endStream)
+    {
+        this(0, metaData, priority, endStream);
+    }
+
+    /**
+     * <p>Creates a new {@code HEADERS} frame with the specified stream {@code id}.</p>
+     * <p>{@code HEADERS} frames with a specific stream {@code id} are typically used
+     * in responses to request {@code HEADERS} frames.</p>
+     *
+     * @param streamId  the stream id
+     * @param metaData  the metadata containing HTTP request/response information
+     * @param priority  the PRIORITY frame associated with this HEADERS frame
+     * @param endStream whether this frame ends the stream
+     */
+    public HeadersFrame(int streamId, MetaData metaData, PriorityFrame priority, boolean endStream)
+    {
+        super(FrameType.HEADERS);
+        this.streamId = streamId;
+        this.metaData = metaData;
+        this.priority = priority;
+        this.endStream = endStream;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public MetaData getMetaData()
+    {
+        return metaData;
+    }
+
+    public PriorityFrame getPriority()
+    {
+        return priority;
+    }
+
+    public boolean isEndStream()
+    {
+        return endStream;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s#%d{end=%b}", super.toString(), streamId, endStream);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java
new file mode 100644
index 0000000..cde9836
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PingFrame.java
@@ -0,0 +1,103 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.util.Objects;
+
+public class PingFrame extends Frame
+{
+    public static final int PING_LENGTH = 8;
+    private static final byte[] EMPTY_PAYLOAD = new byte[8];
+
+    private final byte[] payload;
+    private final boolean reply;
+
+    /**
+     * Creates a PING frame with an empty payload.
+     *
+     * @param reply whether this PING frame is a reply
+     */
+    public PingFrame(boolean reply)
+    {
+        this(EMPTY_PAYLOAD, reply);
+    }
+
+    /**
+     * Creates a PING frame with the given {@code long} {@code value} as payload.
+     *
+     * @param value the value to use as a payload for this PING frame
+     * @param reply whether this PING frame is a reply
+     */
+    public PingFrame(long value, boolean reply)
+    {
+        this(toBytes(value), reply);
+    }
+
+    /**
+     * Creates a PING frame with the given {@code payload}.
+     *
+     * @param payload the payload for this PING frame
+     * @param reply whether this PING frame is a reply
+     */
+    public PingFrame(byte[] payload, boolean reply)
+    {
+        super(FrameType.PING);
+        this.payload = Objects.requireNonNull(payload);
+        if (payload.length != PING_LENGTH)
+            throw new IllegalArgumentException("PING payload must be 8 bytes");
+        this.reply = reply;
+    }
+
+    public byte[] getPayload()
+    {
+        return payload;
+    }
+
+    public long getPayloadAsLong()
+    {
+        return toLong(payload);
+    }
+
+    public boolean isReply()
+    {
+        return reply;
+    }
+
+    private static byte[] toBytes(long value)
+    {
+        byte[] result = new byte[8];
+        for (int i = result.length - 1; i >= 0; --i)
+        {
+            result[i] = (byte)(value & 0xFF);
+            value >>= 8;
+        }
+        return result;
+    }
+
+    private static long toLong(byte[] payload)
+    {
+        long result = 0;
+        for (int i = 0; i < 8; ++i)
+        {
+            result <<= 8;
+            result |= (payload[i] & 0xFF);
+        }
+        return result;
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java
new file mode 100644
index 0000000..d3f5ff7
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PrefaceFrame.java
@@ -0,0 +1,48 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.charset.StandardCharsets;
+
+public class PrefaceFrame extends Frame
+{
+    /**
+     * The bytes of the HTTP/2 preface that form a legal HTTP/1.1
+     * request, used in the direct upgrade.
+     */
+    public static final byte[] PREFACE_PREAMBLE_BYTES = (
+            "PRI * HTTP/2.0\r\n" +
+            "\r\n"
+    ).getBytes(StandardCharsets.US_ASCII);
+
+    /**
+     * The HTTP/2 preface bytes.
+     */
+    public static final byte[] PREFACE_BYTES = (
+            "PRI * HTTP/2.0\r\n" +
+            "\r\n" +
+            "SM\r\n" +
+            "\r\n"
+    ).getBytes(StandardCharsets.US_ASCII);
+
+    public PrefaceFrame()
+    {
+        super(FrameType.PREFACE);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java
new file mode 100644
index 0000000..78b80f9
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PriorityFrame.java
@@ -0,0 +1,78 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+public class PriorityFrame extends Frame
+{
+    public static final int PRIORITY_LENGTH = 5;
+
+    private final int streamId;
+    private final int parentStreamId;
+    private final int weight;
+    private final boolean exclusive;
+
+    public PriorityFrame(int parentStreamId, int weight, boolean exclusive)
+    {
+        this(0, parentStreamId, weight, exclusive);
+    }
+
+    public PriorityFrame(int streamId, int parentStreamId, int weight, boolean exclusive)
+    {
+        super(FrameType.PRIORITY);
+        this.streamId = streamId;
+        this.parentStreamId = parentStreamId;
+        this.weight = weight;
+        this.exclusive = exclusive;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    /**
+     * @deprecated use {@link #getParentStreamId()} instead.
+     */
+    @Deprecated
+    public int getDependentStreamId()
+    {
+        return getParentStreamId();
+    }
+
+    public int getParentStreamId()
+    {
+        return parentStreamId;
+    }
+
+    public int getWeight()
+    {
+        return weight;
+    }
+
+    public boolean isExclusive()
+    {
+        return exclusive;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s#%d/#%d{weight=%d,exclusive=%b}", super.toString(), streamId, parentStreamId, weight, exclusive);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java
new file mode 100644
index 0000000..bf74d79
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/PushPromiseFrame.java
@@ -0,0 +1,57 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import org.eclipse.jetty.http.MetaData;
+
+public class PushPromiseFrame extends Frame
+{
+    private final int streamId;
+    private final int promisedStreamId;
+    private final MetaData metaData;
+
+    public PushPromiseFrame(int streamId, int promisedStreamId, MetaData metaData)
+    {
+        super(FrameType.PUSH_PROMISE);
+        this.streamId = streamId;
+        this.promisedStreamId = promisedStreamId;
+        this.metaData = metaData;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public int getPromisedStreamId()
+    {
+        return promisedStreamId;
+    }
+
+    public MetaData getMetaData()
+    {
+        return metaData;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s#%d/#%d", super.toString(), streamId, promisedStreamId);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java
new file mode 100644
index 0000000..ec49700
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java
@@ -0,0 +1,52 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import org.eclipse.jetty.http2.ErrorCode;
+
+public class ResetFrame extends Frame
+{
+    private final int streamId;
+    private final int error;
+
+    public ResetFrame(int streamId, int error)
+    {
+        super(FrameType.RST_STREAM);
+        this.streamId = streamId;
+        this.error = error;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public int getError()
+    {
+        return error;
+    }
+
+    @Override
+    public String toString()
+    {
+        ErrorCode errorCode = ErrorCode.from(error);
+        String reason = errorCode == null ? "error=" + error : errorCode.name().toLowerCase();
+        return String.format("%s#%d{%s}", super.toString(), streamId, reason);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java
new file mode 100644
index 0000000..ba098da
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/SettingsFrame.java
@@ -0,0 +1,57 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.util.Map;
+
+public class SettingsFrame extends Frame
+{
+    public static final int HEADER_TABLE_SIZE = 1;
+    public static final int ENABLE_PUSH = 2;
+    public static final int MAX_CONCURRENT_STREAMS = 3;
+    public static final int INITIAL_WINDOW_SIZE = 4;
+    public static final int MAX_FRAME_SIZE = 5;
+    public static final int MAX_HEADER_LIST_SIZE = 6;
+    
+    private final Map<Integer, Integer> settings;
+    private final boolean reply;
+
+    public SettingsFrame(Map<Integer, Integer> settings, boolean reply)
+    {
+        super(FrameType.SETTINGS);
+        this.settings = settings;
+        this.reply = reply;
+    }
+
+    public Map<Integer, Integer> getSettings()
+    {
+        return settings;
+    }
+
+    public boolean isReply()
+    {
+        return reply;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s,reply=%b:%s", super.toString(), reply, settings);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java
new file mode 100644
index 0000000..20013a8
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java
@@ -0,0 +1,48 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+public class WindowUpdateFrame extends Frame
+{
+    private final int streamId;
+    private final int windowDelta;
+
+    public WindowUpdateFrame(int streamId, int windowDelta)
+    {
+        super(FrameType.WINDOW_UPDATE);
+        this.streamId = streamId;
+        this.windowDelta = windowDelta;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public int getWindowDelta()
+    {
+        return windowDelta;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s#%d,delta=%d", super.toString(), streamId, windowDelta);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java
new file mode 100644
index 0000000..b859ec6
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java
@@ -0,0 +1,93 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class DataGenerator
+{
+    private final HeaderGenerator headerGenerator;
+
+    public DataGenerator(HeaderGenerator headerGenerator)
+    {
+        this.headerGenerator = headerGenerator;
+    }
+
+    public void generate(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
+    {
+        generateData(lease, frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength);
+    }
+
+    public void generateData(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last, int maxLength)
+    {
+        if (streamId < 0)
+            throw new IllegalArgumentException("Invalid stream id: " + streamId);
+
+        int dataLength = data.remaining();
+        int maxFrameSize = headerGenerator.getMaxFrameSize();
+        if (dataLength <= maxLength && dataLength <= maxFrameSize)
+        {
+            // Single frame.
+            generateFrame(lease, streamId, data, last);
+            return;
+        }
+
+        // Other cases, we need to slice the original buffer into multiple frames.
+
+        int length = Math.min(maxLength, dataLength);
+        int frames = length / maxFrameSize;
+        if (frames * maxFrameSize != length)
+            ++frames;
+
+        int begin = data.position();
+        int end = data.limit();
+        for (int i = 1; i <= frames; ++i)
+        {
+            int limit = begin + Math.min(maxFrameSize * i, length);
+            data.limit(limit);
+            ByteBuffer slice = data.slice();
+            data.position(limit);
+            generateFrame(lease, streamId, slice, i == frames && last && limit == end);
+        }
+        data.limit(end);
+    }
+
+    private void generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last)
+    {
+        int length = data.remaining();
+
+        int flags = Flags.NONE;
+        if (last)
+            flags |= Flags.END_STREAM;
+
+        ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId);
+
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+
+        lease.append(data, false);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java
new file mode 100644
index 0000000..03a9d09
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java
@@ -0,0 +1,35 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.io.ByteBufferPool;
+
+public class DisconnectGenerator extends FrameGenerator
+{
+    public DisconnectGenerator()
+    {
+        super(null);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java
new file mode 100644
index 0000000..486f32f
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java
@@ -0,0 +1,47 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.io.ByteBufferPool;
+
+public abstract class FrameGenerator
+{
+    private final HeaderGenerator headerGenerator;
+
+    protected FrameGenerator(HeaderGenerator headerGenerator)
+    {
+        this.headerGenerator = headerGenerator;
+    }
+
+    public abstract void generate(ByteBufferPool.Lease lease, Frame frame);
+
+    protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId)
+    {
+        return headerGenerator.generate(lease, frameType, Frame.HEADER_LENGTH + length, length, flags, streamId);
+    }
+
+    public int getMaxFrameSize()
+    {
+        return headerGenerator.getMaxFrameSize();
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java
new file mode 100644
index 0000000..961e2de
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java
@@ -0,0 +1,87 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.hpack.HpackEncoder;
+import org.eclipse.jetty.io.ByteBufferPool;
+
+public class Generator
+{
+    private final ByteBufferPool byteBufferPool;
+    private final HeaderGenerator headerGenerator;
+    private final HpackEncoder hpackEncoder;
+    private final FrameGenerator[] generators;
+    private final DataGenerator dataGenerator;
+
+    public Generator(ByteBufferPool byteBufferPool)
+    {
+        this(byteBufferPool, 4096, 0);
+    }
+
+    public Generator(ByteBufferPool byteBufferPool, int maxDynamicTableSize, int maxHeaderBlockFragment)
+    {
+        this.byteBufferPool = byteBufferPool;
+
+        headerGenerator = new HeaderGenerator();
+        hpackEncoder = new HpackEncoder(maxDynamicTableSize);
+
+        this.generators = new FrameGenerator[FrameType.values().length];
+        this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, hpackEncoder, maxHeaderBlockFragment);
+        this.generators[FrameType.PRIORITY.getType()] = new PriorityGenerator(headerGenerator);
+        this.generators[FrameType.RST_STREAM.getType()] = new ResetGenerator(headerGenerator);
+        this.generators[FrameType.SETTINGS.getType()] = new SettingsGenerator(headerGenerator);
+        this.generators[FrameType.PUSH_PROMISE.getType()] = new PushPromiseGenerator(headerGenerator, hpackEncoder);
+        this.generators[FrameType.PING.getType()] = new PingGenerator(headerGenerator);
+        this.generators[FrameType.GO_AWAY.getType()] = new GoAwayGenerator(headerGenerator);
+        this.generators[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateGenerator(headerGenerator);
+        this.generators[FrameType.CONTINUATION.getType()] = null; // Never generated explicitly.
+        this.generators[FrameType.PREFACE.getType()] = new PrefaceGenerator();
+        this.generators[FrameType.DISCONNECT.getType()] = new DisconnectGenerator();
+
+        this.dataGenerator = new DataGenerator(headerGenerator);
+    }
+
+    public ByteBufferPool getByteBufferPool()
+    {
+        return byteBufferPool;
+    }
+
+    public void setHeaderTableSize(int headerTableSize)
+    {
+        hpackEncoder.setRemoteMaxDynamicTableSize(headerTableSize);
+    }
+
+    public void setMaxFrameSize(int maxFrameSize)
+    {
+        headerGenerator.setMaxFrameSize(maxFrameSize);
+    }
+
+    public void control(ByteBufferPool.Lease lease, Frame frame)
+    {
+        generators[frame.getType().getType()].generate(lease, frame);
+    }
+
+    public void data(ByteBufferPool.Lease lease, DataFrame frame, int maxLength)
+    {
+        dataGenerator.generate(lease, frame, maxLength);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java
new file mode 100644
index 0000000..34b3ddb
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java
@@ -0,0 +1,72 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class GoAwayGenerator extends FrameGenerator
+{
+    public GoAwayGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        GoAwayFrame goAwayFrame = (GoAwayFrame)frame;
+        generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload());
+    }
+
+    public void generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload)
+    {
+        if (lastStreamId < 0)
+            throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId);
+
+        // The last streamId + the error code.
+        int fixedLength = 4 + 4;
+
+        // Make sure we don't exceed the default frame max length.
+        int maxPayloadLength = Frame.DEFAULT_MAX_LENGTH - fixedLength;
+        if (payload != null && payload.length > maxPayloadLength)
+            payload = Arrays.copyOfRange(payload, 0, maxPayloadLength);
+
+        int length = fixedLength + (payload != null ? payload.length : 0);
+        ByteBuffer header = generateHeader(lease, FrameType.GO_AWAY, length, Flags.NONE, 0);
+
+        header.putInt(lastStreamId);
+        header.putInt(error);
+
+        if (payload != null)
+        {
+            header.put(payload);
+        }
+
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java
new file mode 100644
index 0000000..a4713ec
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeaderGenerator.java
@@ -0,0 +1,52 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.io.ByteBufferPool;
+
+public class HeaderGenerator
+{
+    private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH;
+
+    public ByteBuffer generate(ByteBufferPool.Lease lease, FrameType frameType, int capacity, int length, int flags, int streamId)
+    {
+        ByteBuffer header = lease.acquire(capacity, true);
+        header.put((byte)((length & 0x00_FF_00_00) >>> 16));
+        header.put((byte)((length & 0x00_00_FF_00) >>> 8));
+        header.put((byte)((length & 0x00_00_00_FF)));
+        header.put((byte)frameType.getType());
+        header.put((byte)flags);
+        header.putInt(streamId);
+        return header;
+    }
+
+    public int getMaxFrameSize()
+    {
+        return maxFrameSize;
+    }
+
+    public void setMaxFrameSize(int maxFrameSize)
+    {
+        this.maxFrameSize = maxFrameSize;
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java
new file mode 100644
index 0000000..7ceab1c
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java
@@ -0,0 +1,139 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.hpack.HpackEncoder;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class HeadersGenerator extends FrameGenerator
+{
+    private final HpackEncoder encoder;
+    private final int maxHeaderBlockFragment;
+    private final PriorityGenerator priorityGenerator;
+
+    public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder)
+    {
+        this(headerGenerator, encoder, 0);
+    }
+
+    public HeadersGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder, int maxHeaderBlockFragment)
+    {
+        super(headerGenerator);
+        this.encoder = encoder;
+        this.maxHeaderBlockFragment = maxHeaderBlockFragment;
+        this.priorityGenerator = new PriorityGenerator(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        HeadersFrame headersFrame = (HeadersFrame)frame;
+        generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream());
+    }
+
+    public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream)
+    {
+        if (streamId < 0)
+            throw new IllegalArgumentException("Invalid stream id: " + streamId);
+
+        int flags = Flags.NONE;
+
+        if (priority != null)
+            flags = Flags.PRIORITY;
+
+        int maxFrameSize = getMaxFrameSize();
+        ByteBuffer hpacked = lease.acquire(maxFrameSize, false);
+        BufferUtil.clearToFill(hpacked);
+        encoder.encode(hpacked, metaData);
+        int hpackedLength = hpacked.position();
+        BufferUtil.flipToFlush(hpacked, 0);
+
+        // Split into CONTINUATION frames if necessary.
+        if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment)
+        {
+            if (endStream)
+                flags |= Flags.END_STREAM;
+
+            int length = maxHeaderBlockFragment;
+            if (priority != null)
+                length += PriorityFrame.PRIORITY_LENGTH;
+
+            ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
+            generatePriority(header, priority);
+            BufferUtil.flipToFlush(header, 0);
+            lease.append(header, true);
+
+            hpacked.limit(maxHeaderBlockFragment);
+            lease.append(hpacked.slice(), false);
+
+            int position = maxHeaderBlockFragment;
+            int limit = position + maxHeaderBlockFragment;
+            while (limit < hpackedLength)
+            {
+                hpacked.position(position).limit(limit);
+                header = generateHeader(lease, FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId);
+                BufferUtil.flipToFlush(header, 0);
+                lease.append(header, true);
+                lease.append(hpacked.slice(), false);
+                position += maxHeaderBlockFragment;
+                limit += maxHeaderBlockFragment;
+            }
+
+            hpacked.position(position).limit(hpackedLength);
+            header = generateHeader(lease, FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId);
+            BufferUtil.flipToFlush(header, 0);
+            lease.append(header, true);
+            lease.append(hpacked, true);
+        }
+        else
+        {
+            flags |= Flags.END_HEADERS;
+            if (endStream)
+                flags |= Flags.END_STREAM;
+
+            int length = hpackedLength;
+            if (priority != null)
+                length += PriorityFrame.PRIORITY_LENGTH;
+
+            ByteBuffer header = generateHeader(lease, FrameType.HEADERS, length, flags, streamId);
+            generatePriority(header, priority);
+            BufferUtil.flipToFlush(header, 0);
+            lease.append(header, true);
+            lease.append(hpacked, true);
+        }
+    }
+
+    private void generatePriority(ByteBuffer header, PriorityFrame priority)
+    {
+        if (priority != null)
+        {
+            priorityGenerator.generatePriorityBody(header, priority.getStreamId(),
+                    priority.getParentStreamId(), priority.getWeight(), priority.isExclusive());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java
new file mode 100644
index 0000000..5058dd6
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java
@@ -0,0 +1,56 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class PingGenerator extends FrameGenerator
+{
+    public PingGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        PingFrame pingFrame = (PingFrame)frame;
+        generatePing(lease, pingFrame.getPayload(), pingFrame.isReply());
+    }
+
+    public void generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply)
+    {
+        if (payload.length != PingFrame.PING_LENGTH)
+            throw new IllegalArgumentException("Invalid payload length: " + payload.length);
+
+        ByteBuffer header = generateHeader(lease, FrameType.PING, PingFrame.PING_LENGTH, reply ? Flags.ACK : Flags.NONE, 0);
+
+        header.put(payload);
+
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java
new file mode 100644
index 0000000..101c948
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java
@@ -0,0 +1,39 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+
+public class PrefaceGenerator extends FrameGenerator
+{
+    public PrefaceGenerator()
+    {
+        super(null);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        lease.append(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java
new file mode 100644
index 0000000..2fc7c10
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class PriorityGenerator extends FrameGenerator
+{
+    public PriorityGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        PriorityFrame priorityFrame = (PriorityFrame)frame;
+        generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getParentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive());
+    }
+
+    public void generatePriority(ByteBufferPool.Lease lease, int streamId, int parentStreamId, int weight, boolean exclusive)
+    {
+        ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, PriorityFrame.PRIORITY_LENGTH, Flags.NONE, streamId);
+        generatePriorityBody(header, streamId, parentStreamId, weight, exclusive);
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+
+    public void generatePriorityBody(ByteBuffer header, int streamId, int parentStreamId, int weight, boolean exclusive)
+    {
+        if (streamId < 0)
+            throw new IllegalArgumentException("Invalid stream id: " + streamId);
+        if (parentStreamId < 0)
+            throw new IllegalArgumentException("Invalid parent stream id: " + parentStreamId);
+        if (parentStreamId == streamId)
+            throw new IllegalArgumentException("Stream " + streamId + " cannot depend on stream " + parentStreamId);
+        if (weight < 1 || weight > 256)
+            throw new IllegalArgumentException("Invalid weight: " + weight);
+
+        if (exclusive)
+            parentStreamId |= 0x80_00_00_00;
+        header.putInt(parentStreamId);
+        header.put((byte)(weight - 1));
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java
new file mode 100644
index 0000000..a6ebb25
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java
@@ -0,0 +1,77 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.hpack.HpackEncoder;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class PushPromiseGenerator extends FrameGenerator
+{
+    private final HpackEncoder encoder;
+
+    public PushPromiseGenerator(HeaderGenerator headerGenerator, HpackEncoder encoder)
+    {
+        super(headerGenerator);
+        this.encoder = encoder;
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        PushPromiseFrame pushPromiseFrame = (PushPromiseFrame)frame;
+        generatePushPromise(lease, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData());
+    }
+
+    public void generatePushPromise(ByteBufferPool.Lease lease, int streamId, int promisedStreamId, MetaData metaData)
+    {
+        if (streamId < 0)
+            throw new IllegalArgumentException("Invalid stream id: " + streamId);
+        if (promisedStreamId < 0)
+            throw new IllegalArgumentException("Invalid promised stream id: " + promisedStreamId);
+
+        int maxFrameSize = getMaxFrameSize();
+        // The promised streamId space.
+        int extraSpace = 4;
+        maxFrameSize -= extraSpace;
+
+        ByteBuffer hpacked = lease.acquire(maxFrameSize, false);
+        BufferUtil.clearToFill(hpacked);
+        encoder.encode(hpacked, metaData);
+        int hpackedLength = hpacked.position();
+        BufferUtil.flipToFlush(hpacked, 0);
+
+        int length = hpackedLength + extraSpace;
+        int flags = Flags.END_HEADERS;
+
+        ByteBuffer header = generateHeader(lease, FrameType.PUSH_PROMISE, length, flags, streamId);
+        header.putInt(promisedStreamId);
+        BufferUtil.flipToFlush(header, 0);
+
+        lease.append(header, true);
+        lease.append(hpacked, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java
new file mode 100644
index 0000000..87758fe
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java
@@ -0,0 +1,56 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class ResetGenerator extends FrameGenerator
+{
+    public ResetGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        ResetFrame resetFrame = (ResetFrame)frame;
+        generateReset(lease, resetFrame.getStreamId(), resetFrame.getError());
+    }
+
+    public void generateReset(ByteBufferPool.Lease lease, int streamId, int error)
+    {
+        if (streamId < 0)
+            throw new IllegalArgumentException("Invalid stream id: " + streamId);
+
+        ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, 4, Flags.NONE, streamId);
+
+        header.putInt(error);
+
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java
new file mode 100644
index 0000000..363d2e1
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class SettingsGenerator extends FrameGenerator
+{
+    public SettingsGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        SettingsFrame settingsFrame = (SettingsFrame)frame;
+        generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply());
+    }
+
+    public void generateSettings(ByteBufferPool.Lease lease, Map<Integer, Integer> settings, boolean reply)
+    {
+        // Two bytes for the identifier, four bytes for the value.
+        int entryLength = 2 + 4;
+        int length = entryLength * settings.size();
+        if (length > getMaxFrameSize())
+            throw new IllegalArgumentException("Invalid settings, too big");
+
+        ByteBuffer header = generateHeader(lease, FrameType.SETTINGS, length, reply ? Flags.ACK : Flags.NONE, 0);
+
+        for (Map.Entry<Integer, Integer> entry : settings.entrySet())
+        {
+            header.putShort(entry.getKey().shortValue());
+            header.putInt(entry.getValue());
+        }
+
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java
new file mode 100644
index 0000000..a047f64
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java
@@ -0,0 +1,54 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.generator;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class WindowUpdateGenerator extends FrameGenerator
+{
+    public WindowUpdateGenerator(HeaderGenerator headerGenerator)
+    {
+        super(headerGenerator);
+    }
+
+    @Override
+    public void generate(ByteBufferPool.Lease lease, Frame frame)
+    {
+        WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame;
+        generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta());
+    }
+
+    public void generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate)
+    {
+        if (windowUpdate < 0)
+            throw new IllegalArgumentException("Invalid window update: " + windowUpdate);
+
+        ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flags.NONE, streamId);
+        header.putInt(windowUpdate);
+        BufferUtil.flipToFlush(header, 0);
+        lease.append(header, true);
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java
new file mode 100644
index 0000000..a3d948b
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java
@@ -0,0 +1,225 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>The base parser for the frame body of HTTP/2 frames.</p>
+ * <p>Subclasses implement {@link #parse(ByteBuffer)} to parse
+ * the frame specific body.</p>
+ *
+ * @see Parser
+ */
+public abstract class BodyParser
+{
+    protected static final Logger LOG = Log.getLogger(BodyParser.class);
+
+    private final HeaderParser headerParser;
+    private final Parser.Listener listener;
+
+    protected BodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        this.headerParser = headerParser;
+        this.listener = listener;
+    }
+
+    /**
+     * <p>Parses the body bytes in the given {@code buffer}; only the body
+     * bytes are consumed, therefore when this method returns, the buffer
+     * may contain unconsumed bytes.</p>
+     *
+     * @param buffer the buffer to parse
+     * @return true if the whole body bytes were parsed, false if not enough
+     * body bytes were present in the buffer
+     */
+    public abstract boolean parse(ByteBuffer buffer);
+
+    protected void emptyBody(ByteBuffer buffer)
+    {
+        connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_frame");
+    }
+
+    protected boolean hasFlag(int bit)
+    {
+        return headerParser.hasFlag(bit);
+    }
+
+    protected boolean isPadding()
+    {
+        return headerParser.hasFlag(Flags.PADDING);
+    }
+
+    protected boolean isEndStream()
+    {
+        return headerParser.hasFlag(Flags.END_STREAM);
+    }
+
+    protected int getStreamId()
+    {
+        return headerParser.getStreamId();
+    }
+
+    protected int getBodyLength()
+    {
+        return headerParser.getLength();
+    }
+
+    protected void notifyData(DataFrame frame)
+    {
+        try
+        {
+            listener.onData(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyHeaders(HeadersFrame frame)
+    {
+        try
+        {
+            listener.onHeaders(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyPriority(PriorityFrame frame)
+    {
+        try
+        {
+            listener.onPriority(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyReset(ResetFrame frame)
+    {
+        try
+        {
+            listener.onReset(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifySettings(SettingsFrame frame)
+    {
+        try
+        {
+            listener.onSettings(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyPushPromise(PushPromiseFrame frame)
+    {
+        try
+        {
+            listener.onPushPromise(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyPing(PingFrame frame)
+    {
+        try
+        {
+            listener.onPing(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyGoAway(GoAwayFrame frame)
+    {
+        try
+        {
+            listener.onGoAway(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected void notifyWindowUpdate(WindowUpdateFrame frame)
+    {
+        try
+        {
+            listener.onWindowUpdate(frame);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    protected boolean connectionFailure(ByteBuffer buffer, int error, String reason)
+    {
+        BufferUtil.clear(buffer);
+        notifyConnectionFailure(error, reason);
+        return false;
+    }
+
+    private void notifyConnectionFailure(int error, String reason)
+    {
+        try
+        {
+            listener.onConnectionFailure(error, reason);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java
new file mode 100644
index 0000000..b23124d
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java
@@ -0,0 +1,114 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+
+public class ContinuationBodyParser extends BodyParser
+{
+    private final HeaderBlockParser headerBlockParser;
+    private final HeaderBlockFragments headerBlockFragments;
+    private State state = State.PREPARE;
+    private int length;
+
+    public ContinuationBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments)
+    {
+        super(headerParser, listener);
+        this.headerBlockParser = headerBlockParser;
+        this.headerBlockFragments = headerBlockFragments;
+    }
+
+    @Override
+    protected void emptyBody(ByteBuffer buffer)
+    {
+        if (hasFlag(Flags.END_HEADERS))
+            onHeaders();
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_frame");
+
+                    if (getStreamId() != headerBlockFragments.getStreamId())
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream");
+
+                    length = getBodyLength();
+                    state = State.FRAGMENT;
+                    break;
+                }
+                case FRAGMENT:
+                {
+                    int remaining = buffer.remaining();
+                    if (remaining < length)
+                    {
+                        headerBlockFragments.storeFragment(buffer, remaining, false);
+                        length -= remaining;
+                    }
+                    else
+                    {
+                        boolean last = hasFlag(Flags.END_HEADERS);
+                        headerBlockFragments.storeFragment(buffer, length, last);
+                        reset();
+                        if (last)
+                            onHeaders();
+                        return true;
+                    }
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private void onHeaders()
+    {
+        ByteBuffer headerBlock = headerBlockFragments.complete();
+        MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining());
+        HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream());
+        notifyHeaders(frame);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        length = 0;
+    }
+
+    private enum State
+    {
+        PREPARE, FRAGMENT
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java
new file mode 100644
index 0000000..ebd5f56
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java
@@ -0,0 +1,145 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class DataBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int padding;
+    private int paddingLength;
+    private int length;
+
+    public DataBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        padding = 0;
+        paddingLength = 0;
+        length = 0;
+    }
+
+    @Override
+    protected void emptyBody(ByteBuffer buffer)
+    {
+        if (isPadding())
+            connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame");
+        else
+            onData(BufferUtil.EMPTY_BUFFER, false, 0);
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        boolean loop = false;
+        while (buffer.hasRemaining() || loop)
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame");
+
+                    length = getBodyLength();
+                    state = isPadding() ? State.PADDING_LENGTH : State.DATA;
+                    break;
+                }
+                case PADDING_LENGTH:
+                {
+                    padding = 1; // We have seen this byte.
+                    paddingLength = buffer.get() & 0xFF;
+                    --length;
+                    length -= paddingLength;
+                    state = State.DATA;
+                    loop = length == 0;
+                    if (length < 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_data_frame_padding");
+                    break;
+                }
+                case DATA:
+                {
+                    int size = Math.min(buffer.remaining(), length);
+                    int position = buffer.position();
+                    int limit = buffer.limit();
+                    buffer.limit(position + size);
+                    ByteBuffer slice = buffer.slice();
+                    buffer.limit(limit);
+                    buffer.position(position + size);
+
+                    length -= size;
+                    if (length == 0)
+                    {
+                        state = State.PADDING;
+                        loop = paddingLength == 0;
+                        // Padding bytes include the bytes that define the
+                        // padding length plus the actual padding bytes.
+                        onData(slice, false, padding + paddingLength);
+                    }
+                    else
+                    {
+                        // We got partial data, simulate a smaller frame, and stay in DATA state.
+                        // No padding for these synthetic frames (even if we have read
+                        // the padding length already), it will be accounted at the end.
+                        onData(slice, true, 0);
+                    }
+                    break;
+                }
+                case PADDING:
+                {
+                    int size = Math.min(buffer.remaining(), paddingLength);
+                    buffer.position(buffer.position() + size);
+                    paddingLength -= size;
+                    if (paddingLength == 0)
+                    {
+                        reset();
+                        return true;
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private void onData(ByteBuffer buffer, boolean fragment, int padding)
+    {
+        DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding);
+        notifyData(frame);
+    }
+
+    private enum State
+    {
+        PREPARE, PADDING_LENGTH, DATA, PADDING
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java
new file mode 100644
index 0000000..5d2363b
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/GoAwayBodyParser.java
@@ -0,0 +1,177 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+
+public class GoAwayBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int cursor;
+    private int length;
+    private int lastStreamId;
+    private int error;
+    private byte[] payload;
+
+    public GoAwayBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        length = 0;
+        lastStreamId = 0;
+        error = 0;
+        payload = null;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    state = State.LAST_STREAM_ID;
+                    length = getBodyLength();
+                    break;
+                }
+                case LAST_STREAM_ID:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        lastStreamId = buffer.getInt();
+                        lastStreamId &= 0x7F_FF_FF_FF;
+                        state = State.ERROR;
+                        length -= 4;
+                        if (length <= 0)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
+                    }
+                    else
+                    {
+                        state = State.LAST_STREAM_ID_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case LAST_STREAM_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    lastStreamId += currByte << (8 * cursor);
+                    --length;
+                    if (cursor > 0 && length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
+                    if (cursor == 0)
+                    {
+                        lastStreamId &= 0x7F_FF_FF_FF;
+                        state = State.ERROR;
+                        if (length == 0)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
+                    }
+                    break;
+                }
+                case ERROR:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        error = buffer.getInt();
+                        state = State.PAYLOAD;
+                        length -= 4;
+                        if (length < 0)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
+                        if (length == 0)
+                            return onGoAway(lastStreamId, error, null);
+                    }
+                    else
+                    {
+                        state = State.ERROR_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case ERROR_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    error += currByte << (8 * cursor);
+                    --length;
+                    if (cursor > 0 && length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
+                    if (cursor == 0)
+                    {
+                        state = State.PAYLOAD;
+                        if (length == 0)
+                            return onGoAway(lastStreamId, error, null);
+                    }
+                    break;
+                }
+                case PAYLOAD:
+                {
+                    payload = new byte[length];
+                    if (buffer.remaining() >= length)
+                    {
+                        buffer.get(payload);
+                        return onGoAway(lastStreamId, error, payload);
+                    }
+                    else
+                    {
+                        state = State.PAYLOAD_BYTES;
+                        cursor = length;
+                    }
+                    break;
+                }
+                case PAYLOAD_BYTES:
+                {
+                    payload[payload.length - cursor] = buffer.get();
+                    --cursor;
+                    if (cursor == 0)
+                        return onGoAway(lastStreamId, error, payload);
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean onGoAway(int lastStreamId, int error, byte[] payload)
+    {
+        GoAwayFrame frame = new GoAwayFrame(lastStreamId, error, payload);
+        reset();
+        notifyGoAway(frame);
+        return true;
+    }
+
+    private enum State
+    {
+        PREPARE, LAST_STREAM_ID, LAST_STREAM_ID_BYTES, ERROR, ERROR_BYTES, PAYLOAD, PAYLOAD_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java
new file mode 100644
index 0000000..a4791f0
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java
@@ -0,0 +1,95 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+
+public class HeaderBlockFragments
+{
+    private PriorityFrame priorityFrame;
+    private boolean endStream;
+    private int streamId;
+    private ByteBuffer storage;
+
+    public void storeFragment(ByteBuffer fragment, int length, boolean last)
+    {
+        if (storage == null)
+        {
+            int space = last ? length : length * 2;
+            storage = ByteBuffer.allocate(space);
+        }
+
+        // Grow the storage if necessary.
+        if (storage.remaining() < length)
+        {
+            int space = last ? length : length * 2;
+            int capacity = storage.position() + space;
+            ByteBuffer newStorage = ByteBuffer.allocate(capacity);
+            storage.flip();
+            newStorage.put(storage);
+            storage = newStorage;
+        }
+
+        // Copy the fragment into the storage.
+        int limit = fragment.limit();
+        fragment.limit(fragment.position() + length);
+        storage.put(fragment);
+        fragment.limit(limit);
+    }
+
+    public PriorityFrame getPriorityFrame()
+    {
+        return priorityFrame;
+    }
+
+    public void setPriorityFrame(PriorityFrame priorityFrame)
+    {
+        this.priorityFrame = priorityFrame;
+    }
+
+    public boolean isEndStream()
+    {
+        return endStream;
+    }
+
+    public void setEndStream(boolean endStream)
+    {
+        this.endStream = endStream;
+    }
+
+    public ByteBuffer complete()
+    {
+        ByteBuffer result = storage;
+        storage = null;
+        result.flip();
+        return result;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    public void setStreamId(int streamId)
+    {
+        this.streamId = streamId;
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java
new file mode 100644
index 0000000..730e87e
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java
@@ -0,0 +1,88 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.hpack.HpackDecoder;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class HeaderBlockParser
+{
+    private final ByteBufferPool byteBufferPool;
+    private final HpackDecoder hpackDecoder;
+    private ByteBuffer blockBuffer;
+
+    public HeaderBlockParser(ByteBufferPool byteBufferPool, HpackDecoder hpackDecoder)
+    {
+        this.byteBufferPool = byteBufferPool;
+        this.hpackDecoder = hpackDecoder;
+    }
+
+    public MetaData parse(ByteBuffer buffer, int blockLength)
+    {
+        // We must wait for the all the bytes of the header block to arrive.
+        // If they are not all available, accumulate them.
+        // When all are available, decode them.
+
+        int accumulated = blockBuffer == null ? 0 : blockBuffer.position();
+        int remaining = blockLength - accumulated;
+
+        if (buffer.remaining() < remaining)
+        {
+            if (blockBuffer == null)
+            {
+                blockBuffer = byteBufferPool.acquire(blockLength, false);
+                BufferUtil.clearToFill(blockBuffer);
+            }
+            blockBuffer.put(buffer);
+            return null;
+        }
+        else
+        {
+            int limit = buffer.limit();
+            buffer.limit(buffer.position() + remaining);
+            ByteBuffer toDecode;
+            if (blockBuffer != null)
+            {
+                blockBuffer.put(buffer);
+                BufferUtil.flipToFlush(blockBuffer, 0);
+                toDecode = blockBuffer;
+            }
+            else
+            {
+                toDecode = buffer;
+            }
+
+            MetaData result = hpackDecoder.decode(toDecode);
+
+            buffer.limit(limit);
+
+            if (blockBuffer != null)
+            {
+                byteBufferPool.release(blockBuffer);
+                blockBuffer = null;
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java
new file mode 100644
index 0000000..64258cb
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java
@@ -0,0 +1,151 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.frames.Frame;
+
+/**
+ * <p>The parser for the frame header of HTTP/2 frames.</p>
+ *
+ * @see Parser
+ */
+public class HeaderParser
+{
+    private State state = State.LENGTH;
+    private int cursor;
+
+    private int length;
+    private int type;
+    private int flags;
+    private int streamId;
+
+    protected void reset()
+    {
+        state = State.LENGTH;
+        cursor = 0;
+
+        length = 0;
+        type = 0;
+        flags = 0;
+        streamId = 0;
+    }
+
+    /**
+     * <p>Parses the header bytes in the given {@code buffer}; only the header
+     * bytes are consumed, therefore when this method returns, the buffer may
+     * contain unconsumed bytes.</p>
+     *
+     * @param buffer the buffer to parse
+     * @return true if the whole header bytes were parsed, false if not enough
+     * header bytes were present in the buffer
+     */
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case LENGTH:
+                {
+                    int octet = buffer.get() & 0xFF;
+                    length = (length << 8) + octet;
+                    if (++cursor == 3)
+                    {
+                        length &= Frame.MAX_MAX_LENGTH;
+                        state = State.TYPE;
+                    }
+                    break;
+                }
+                case TYPE:
+                {
+                    type = buffer.get() & 0xFF;
+                    state = State.FLAGS;
+                    break;
+                }
+                case FLAGS:
+                {
+                    flags = buffer.get() & 0xFF;
+                    state = State.STREAM_ID;
+                    break;
+                }
+                case STREAM_ID:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        streamId = buffer.getInt();
+                        // Most significant bit MUST be ignored as per specification.
+                        streamId &= 0x7F_FF_FF_FF;
+                        return true;
+                    }
+                    else
+                    {
+                        state = State.STREAM_ID_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case STREAM_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    streamId += currByte << (8 * cursor);
+                    if (cursor == 0)
+                    {
+                        // Most significant bit MUST be ignored as per specification.
+                        streamId &= 0x7F_FF_FF_FF;
+                        return true;
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    public int getLength()
+    {
+        return length;
+    }
+
+    public int getFrameType()
+    {
+        return type;
+    }
+
+    public boolean hasFlag(int bit)
+    {
+        return (flags & bit) == bit;
+    }
+
+    public int getStreamId()
+    {
+        return streamId;
+    }
+
+    private enum State
+    {
+        LENGTH, TYPE, FLAGS, STREAM_ID, STREAM_ID_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java
new file mode 100644
index 0000000..87500fb
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java
@@ -0,0 +1,240 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.util.BufferUtil;
+
+public class HeadersBodyParser extends BodyParser
+{
+    private final HeaderBlockParser headerBlockParser;
+    private final HeaderBlockFragments headerBlockFragments;
+    private State state = State.PREPARE;
+    private int cursor;
+    private int length;
+    private int paddingLength;
+    private boolean exclusive;
+    private int parentStreamId;
+    private int weight;
+
+    public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments)
+    {
+        super(headerParser, listener);
+        this.headerBlockParser = headerBlockParser;
+        this.headerBlockFragments = headerBlockFragments;
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        length = 0;
+        paddingLength = 0;
+        exclusive = false;
+        parentStreamId = 0;
+        weight = 0;
+    }
+
+    @Override
+    protected void emptyBody(ByteBuffer buffer)
+    {
+        if (hasFlag(Flags.END_HEADERS))
+        {
+            MetaData metaData = headerBlockParser.parse(BufferUtil.EMPTY_BUFFER, 0);
+            onHeaders(0, 0, false, metaData);
+        }
+        else
+        {
+            headerBlockFragments.setStreamId(getStreamId());
+            headerBlockFragments.setEndStream(isEndStream());
+            if (hasFlag(Flags.PRIORITY))
+                connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame");
+        }
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        boolean loop = false;
+        while (buffer.hasRemaining() || loop)
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
+
+                    length = getBodyLength();
+
+                    if (isPadding())
+                    {
+                        state = State.PADDING_LENGTH;
+                    }
+                    else if (hasFlag(Flags.PRIORITY))
+                    {
+                        state = State.EXCLUSIVE;
+                    }
+                    else
+                    {
+                        state = State.HEADERS;
+                    }
+                    break;
+                }
+                case PADDING_LENGTH:
+                {
+                    paddingLength = buffer.get() & 0xFF;
+                    --length;
+                    length -= paddingLength;
+                    state = hasFlag(Flags.PRIORITY) ? State.EXCLUSIVE : State.HEADERS;
+                    loop = length == 0;
+                    if (length < 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame_padding");
+                    break;
+                }
+                case EXCLUSIVE:
+                {
+                    // We must only peek the first byte and not advance the buffer
+                    // because the 31 least significant bits represent the stream id.
+                    int currByte = buffer.get(buffer.position());
+                    exclusive = (currByte & 0x80) == 0x80;
+                    state = State.PARENT_STREAM_ID;
+                    break;
+                }
+                case PARENT_STREAM_ID:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        parentStreamId = buffer.getInt();
+                        parentStreamId &= 0x7F_FF_FF_FF;
+                        length -= 4;
+                        state = State.WEIGHT;
+                        if (length < 1)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
+                    }
+                    else
+                    {
+                        state = State.PARENT_STREAM_ID_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case PARENT_STREAM_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    parentStreamId += currByte << (8 * cursor);
+                    --length;
+                    if (cursor > 0 && length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
+                    if (cursor == 0)
+                    {
+                        parentStreamId &= 0x7F_FF_FF_FF;
+                        state = State.WEIGHT;
+                        if (length < 1)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
+                    }
+                    break;
+                }
+                case WEIGHT:
+                {
+                    weight = (buffer.get() & 0xFF) + 1;
+                    --length;
+                    state = State.HEADERS;
+                    loop = length == 0;
+                    break;
+                }
+                case HEADERS:
+                {
+                    if (hasFlag(Flags.END_HEADERS))
+                    {
+                        MetaData metaData = headerBlockParser.parse(buffer, length);
+                        if (metaData != null)
+                        {
+                            if (LOG.isDebugEnabled())
+                                LOG.debug("Parsed {} frame hpack from {}", FrameType.HEADERS, buffer);
+                            state = State.PADDING;
+                            loop = paddingLength == 0;
+                            onHeaders(parentStreamId, weight, exclusive, metaData);
+                        }
+                    }
+                    else
+                    {
+                        int remaining = buffer.remaining();
+                        if (remaining < length)
+                        {
+                            headerBlockFragments.storeFragment(buffer, remaining, false);
+                            length -= remaining;
+                        }
+                        else
+                        {
+                            headerBlockFragments.setStreamId(getStreamId());
+                            headerBlockFragments.setEndStream(isEndStream());
+                            if (hasFlag(Flags.PRIORITY))
+                                headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive));
+                            headerBlockFragments.storeFragment(buffer, length, false);
+                            state = State.PADDING;
+                            loop = paddingLength == 0;
+                        }
+                    }
+                    break;
+                }
+                case PADDING:
+                {
+                    int size = Math.min(buffer.remaining(), paddingLength);
+                    buffer.position(buffer.position() + size);
+                    paddingLength -= size;
+                    if (paddingLength == 0)
+                    {
+                        reset();
+                        return true;
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private void onHeaders(int parentStreamId, int weight, boolean exclusive, MetaData metaData)
+    {
+        PriorityFrame priorityFrame = null;
+        if (hasFlag(Flags.PRIORITY))
+            priorityFrame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive);
+        HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream());
+        notifyHeaders(frame);
+    }
+
+    private enum State
+    {
+        PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java
new file mode 100644
index 0000000..c83f73e
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java
@@ -0,0 +1,294 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+import org.eclipse.jetty.http2.hpack.HpackDecoder;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>The HTTP/2 protocol parser.</p>
+ * <p>This parser makes use of the {@link HeaderParser} and of
+ * {@link BodyParser}s to parse HTTP/2 frames.</p>
+ */
+public class Parser
+{
+    private static final Logger LOG = Log.getLogger(Parser.class);
+
+    private final Listener listener;
+    private final HeaderParser headerParser;
+    private final BodyParser[] bodyParsers;
+    private boolean continuation;
+    private State state = State.HEADER;
+
+    public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
+    {
+        this.listener = listener;
+        this.headerParser = new HeaderParser();
+        this.bodyParsers = new BodyParser[FrameType.values().length];
+
+        HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxDynamicTableSize, maxHeaderSize));
+        HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
+
+        bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener);
+        bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
+        bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener);
+        bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener);
+        bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener);
+        bodyParsers[FrameType.PUSH_PROMISE.getType()] = new PushPromiseBodyParser(headerParser, listener, headerBlockParser);
+        bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener);
+        bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener);
+        bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener);
+        bodyParsers[FrameType.CONTINUATION.getType()] = new ContinuationBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
+    }
+
+    private void reset()
+    {
+        headerParser.reset();
+        state = State.HEADER;
+    }
+
+    /**
+     * <p>Parses the given {@code buffer} bytes and emit events to a {@link Listener}.</p>
+     * <p>When this method returns, the buffer may not be fully consumed, so invocations
+     * to this method should be wrapped in a loop:</p>
+     * <pre>
+     * while (buffer.hasRemaining())
+     *     parser.parse(buffer);
+     * </pre>
+     *
+     * @param buffer the buffer to parse
+     */
+    public void parse(ByteBuffer buffer)
+    {
+        try
+        {
+            while (true)
+            {
+                switch (state)
+                {
+                    case HEADER:
+                    {
+                        if (!parseHeader(buffer))
+                            return;
+                        break;
+                    }
+                    case BODY:
+                    {
+                        if (!parseBody(buffer))
+                            return;
+                        break;
+                    }
+                    default:
+                    {
+                        throw new IllegalStateException();
+                    }
+                }
+            }
+        }
+        catch (Throwable x)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(x);
+            BufferUtil.clear(buffer);
+            notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "parser_error");
+        }
+    }
+
+    protected boolean parseHeader(ByteBuffer buffer)
+    {
+        if (!headerParser.parse(buffer))
+            return false;
+
+        FrameType frameType = FrameType.from(getFrameType());
+        if (LOG.isDebugEnabled())
+            LOG.debug("Parsed {} frame header from {}", frameType, buffer);
+
+        if (continuation)
+        {
+            if (frameType != FrameType.CONTINUATION)
+            {
+                // SPEC: CONTINUATION frames must be consecutive.
+                BufferUtil.clear(buffer);
+                notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "continuation_frame_expected");
+                return false;
+            }
+            if (headerParser.hasFlag(Flags.END_HEADERS))
+            {
+                continuation = false;
+            }
+        }
+        else
+        {
+            if (frameType == FrameType.HEADERS &&
+                    !headerParser.hasFlag(Flags.END_HEADERS))
+            {
+                continuation = true;
+            }
+        }
+        state = State.BODY;
+        return true;
+    }
+
+    protected boolean parseBody(ByteBuffer buffer)
+    {
+        int type = getFrameType();
+        if (type < 0 || type >= bodyParsers.length)
+        {
+            BufferUtil.clear(buffer);
+            notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unknown_frame_type_" + type);
+            return false;
+        }
+
+        BodyParser bodyParser = bodyParsers[type];
+        if (headerParser.getLength() == 0)
+        {
+            bodyParser.emptyBody(buffer);
+        }
+        else
+        {
+            if (!bodyParser.parse(buffer))
+                return false;
+        }
+        if (LOG.isDebugEnabled())
+            LOG.debug("Parsed {} frame body from {}", FrameType.from(type), buffer);
+        reset();
+        return true;
+    }
+
+    protected int getFrameType()
+    {
+        return headerParser.getFrameType();
+    }
+
+    protected boolean hasFlag(int bit)
+    {
+        return headerParser.hasFlag(bit);
+    }
+
+    protected void notifyConnectionFailure(int error, String reason)
+    {
+        try
+        {
+            listener.onConnectionFailure(error, reason);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    public interface Listener
+    {
+        public void onData(DataFrame frame);
+
+        public void onHeaders(HeadersFrame frame);
+
+        public void onPriority(PriorityFrame frame);
+
+        public void onReset(ResetFrame frame);
+
+        public void onSettings(SettingsFrame frame);
+
+        public void onPushPromise(PushPromiseFrame frame);
+
+        public void onPing(PingFrame frame);
+
+        public void onGoAway(GoAwayFrame frame);
+
+        public void onWindowUpdate(WindowUpdateFrame frame);
+
+        public void onConnectionFailure(int error, String reason);
+
+        public static class Adapter implements Listener
+        {
+            @Override
+            public void onData(DataFrame frame)
+            {
+            }
+
+            @Override
+            public void onHeaders(HeadersFrame frame)
+            {
+            }
+
+            @Override
+            public void onPriority(PriorityFrame frame)
+            {
+            }
+
+            @Override
+            public void onReset(ResetFrame frame)
+            {
+            }
+
+            @Override
+            public void onSettings(SettingsFrame frame)
+            {
+            }
+
+            @Override
+            public void onPushPromise(PushPromiseFrame frame)
+            {
+            }
+
+            @Override
+            public void onPing(PingFrame frame)
+            {
+            }
+
+            @Override
+            public void onGoAway(GoAwayFrame frame)
+            {
+            }
+
+            @Override
+            public void onWindowUpdate(WindowUpdateFrame frame)
+            {
+            }
+
+            @Override
+            public void onConnectionFailure(int error, String reason)
+            {
+                LOG.warn("Connection failure: {}/{}", error, reason);
+            }
+        }
+    }
+
+    private enum State
+    {
+        HEADER, BODY
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java
new file mode 100644
index 0000000..c8968e7
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java
@@ -0,0 +1,107 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.PingFrame;
+
+public class PingBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int cursor;
+    private byte[] payload;
+
+    public PingBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        payload = null;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() != 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_ping_frame");
+                    // SPEC: wrong body length is treated as connection error.
+                    if (getBodyLength() != 8)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_ping_frame");
+                    state = State.PAYLOAD;
+                    break;
+                }
+                case PAYLOAD:
+                {
+                    payload = new byte[8];
+                    if (buffer.remaining() >= 8)
+                    {
+                        buffer.get(payload);
+                        return onPing(payload);
+                    }
+                    else
+                    {
+                        state = State.PAYLOAD_BYTES;
+                        cursor = 8;
+                    }
+                    break;
+                }
+                case PAYLOAD_BYTES:
+                {
+                    payload[8 - cursor] = buffer.get();
+                    --cursor;
+                    if (cursor == 0)
+                        return onPing(payload);
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean onPing(byte[] payload)
+    {
+        PingFrame frame = new PingFrame(payload, hasFlag(Flags.ACK));
+        reset();
+        notifyPing(frame);
+        return true;
+    }
+
+    private enum State
+    {
+        PREPARE, PAYLOAD, PAYLOAD_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java
new file mode 100644
index 0000000..94c678b
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java
@@ -0,0 +1,88 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class PrefaceParser
+{
+    private static final Logger LOG = Log.getLogger(PrefaceParser.class);
+
+    private final Parser.Listener listener;
+    private int cursor;
+
+    public PrefaceParser(Parser.Listener listener)
+    {
+        this.listener = listener;
+    }
+
+    /**
+     * <p>Advances this parser after the {@link PrefaceFrame#PREFACE_PREAMBLE_BYTES}.</p>
+     * <p>This allows the HTTP/1.1 parser to parse the preamble of the preface,
+     * which is a legal HTTP/1.1 request, and this parser will parse the remaining
+     * bytes, that are not parseable by a HTTP/1.1 parser.</p>
+     */
+    protected void directUpgrade()
+    {
+        if (cursor != 0)
+            throw new IllegalStateException();
+        cursor = PrefaceFrame.PREFACE_PREAMBLE_BYTES.length;
+    }
+
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            int currByte = buffer.get();
+            if (currByte != PrefaceFrame.PREFACE_BYTES[cursor])
+            {
+                BufferUtil.clear(buffer);
+                notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_preface");
+                return false;
+            }
+            ++cursor;
+            if (cursor == PrefaceFrame.PREFACE_BYTES.length)
+            {
+                cursor = 0;
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Parsed preface bytes from {}", buffer);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected void notifyConnectionFailure(int error, String reason)
+    {
+        try
+        {
+            listener.onConnectionFailure(error, reason);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java
new file mode 100644
index 0000000..fdffd5a
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java
@@ -0,0 +1,130 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+
+public class PriorityBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int cursor;
+    private boolean exclusive;
+    private int parentStreamId;
+
+    public PriorityBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        exclusive = false;
+        parentStreamId = 0;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_priority_frame");
+                    int length = getBodyLength();
+                    if (length != 5)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_priority_frame");
+                    state = State.EXCLUSIVE;
+                    break;
+                }
+                case EXCLUSIVE:
+                {
+                    // We must only peek the first byte and not advance the buffer
+                    // because the 31 least significant bits represent the stream id.
+                    int currByte = buffer.get(buffer.position());
+                    exclusive = (currByte & 0x80) == 0x80;
+                    state = State.PARENT_STREAM_ID;
+                    break;
+                }
+                case PARENT_STREAM_ID:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        parentStreamId = buffer.getInt();
+                        parentStreamId &= 0x7F_FF_FF_FF;
+                        state = State.WEIGHT;
+                    }
+                    else
+                    {
+                        state = State.PARENT_STREAM_ID_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case PARENT_STREAM_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    parentStreamId += currByte << (8 * cursor);
+                    if (cursor == 0)
+                    {
+                        parentStreamId &= 0x7F_FF_FF_FF;
+                        state = State.WEIGHT;
+                    }
+                    break;
+                }
+                case WEIGHT:
+                {
+                    // SPEC: stream cannot depend on itself.
+                    if (getStreamId() == parentStreamId)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_priority_frame");
+
+                    int weight = (buffer.get() & 0xFF) + 1;
+                    return onPriority(parentStreamId, weight, exclusive);
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean onPriority(int parentStreamId, int weight, boolean exclusive)
+    {
+        PriorityFrame frame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive);
+        reset();
+        notifyPriority(frame);
+        return true;
+    }
+
+    private enum State
+    {
+        PREPARE, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java
new file mode 100644
index 0000000..53afe7b
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java
@@ -0,0 +1,167 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+
+public class PushPromiseBodyParser extends BodyParser
+{
+    private final HeaderBlockParser headerBlockParser;
+    private State state = State.PREPARE;
+    private int cursor;
+    private int length;
+    private int paddingLength;
+    private int streamId;
+
+    public PushPromiseBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser)
+    {
+        super(headerParser, listener);
+        this.headerBlockParser = headerBlockParser;
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        length = 0;
+        paddingLength = 0;
+        streamId = 0;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        boolean loop = false;
+        while (buffer.hasRemaining() || loop)
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_push_promise_frame");
+
+                    // For now we don't support PUSH_PROMISE frames that don't have END_HEADERS.
+                    if (!hasFlag(Flags.END_HEADERS))
+                        return connectionFailure(buffer, ErrorCode.INTERNAL_ERROR.code, "unsupported_push_promise_frame");
+
+                    length = getBodyLength();
+
+                    if (isPadding())
+                    {
+                        state = State.PADDING_LENGTH;
+                    }
+                    else
+                    {
+                        state = State.STREAM_ID;
+                    }
+                    break;
+                }
+                case PADDING_LENGTH:
+                {
+                    paddingLength = buffer.get() & 0xFF;
+                    --length;
+                    length -= paddingLength;
+                    state = State.STREAM_ID;
+                    if (length < 4)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_push_promise_frame");
+                    break;
+                }
+                case STREAM_ID:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        streamId = buffer.getInt();
+                        streamId &= 0x7F_FF_FF_FF;
+                        length -= 4;
+                        state = State.HEADERS;
+                        loop = length == 0;
+                    }
+                    else
+                    {
+                        state = State.STREAM_ID_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case STREAM_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    streamId += currByte << (8 * cursor);
+                    --length;
+                    if (cursor > 0 && length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_push_promise_frame");
+                    if (cursor == 0)
+                    {
+                        streamId &= 0x7F_FF_FF_FF;
+                        state = State.HEADERS;
+                        loop = length == 0;
+                    }
+                    break;
+                }
+                case HEADERS:
+                {
+                    MetaData metaData = headerBlockParser.parse(buffer, length);
+                    if (metaData != null)
+                    {
+                        state = State.PADDING;
+                        loop = paddingLength == 0;
+                        onPushPromise(streamId, metaData);
+                    }
+                    break;
+                }
+                case PADDING:
+                {
+                    int size = Math.min(buffer.remaining(), paddingLength);
+                    buffer.position(buffer.position() + size);
+                    paddingLength -= size;
+                    if (paddingLength == 0)
+                    {
+                        reset();
+                        return true;
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private void onPushPromise(int streamId, MetaData metaData)
+    {
+        PushPromiseFrame frame = new PushPromiseFrame(getStreamId(), streamId, metaData);
+        notifyPushPromise(frame);
+    }
+
+    private enum State
+    {
+        PREPARE, PADDING_LENGTH, STREAM_ID, STREAM_ID_BYTES, HEADERS, PADDING
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java
new file mode 100644
index 0000000..5d80cfe
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java
@@ -0,0 +1,105 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+
+public class ResetBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int cursor;
+    private int error;
+
+    public ResetBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        error = 0;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() == 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_rst_stream_frame");
+                    int length = getBodyLength();
+                    if (length != 4)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_rst_stream_frame");
+                    state = State.ERROR;
+                    break;
+                }
+                case ERROR:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        return onReset(buffer.getInt());
+                    }
+                    else
+                    {
+                        state = State.ERROR_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case ERROR_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    error += currByte << (8 * cursor);
+                    if (cursor == 0)
+                        return onReset(error);
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean onReset(int error)
+    {
+        ResetFrame frame = new ResetFrame(getStreamId(), error);
+        reset();
+        notifyReset(frame);
+        return true;
+    }
+
+    private enum State
+    {
+        PREPARE, ERROR, ERROR_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java
new file mode 100644
index 0000000..81c5dcb
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java
@@ -0,0 +1,167 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class ServerParser extends Parser
+{
+    private static final Logger LOG = Log.getLogger(ServerParser.class);
+
+    private final Listener listener;
+    private final PrefaceParser prefaceParser;
+    private State state = State.PREFACE;
+    private boolean notifyPreface = true;
+
+    public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
+    {
+        super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize);
+        this.listener = listener;
+        this.prefaceParser = new PrefaceParser(listener);
+    }
+
+    /**
+     * <p>A direct upgrade is an unofficial upgrade from HTTP/1.1 to HTTP/2.0.</p>
+     * <p>A direct upgrade is initiated when {@code org.eclipse.jetty.server.HttpConnection}
+     * sees a request with these bytes:</p>
+     * <pre>
+     * PRI * HTTP/2.0\r\n
+     * \r\n
+     * </pre>
+     * <p>This request is part of the HTTP/2.0 preface, indicating that a
+     * HTTP/2.0 client is attempting a h2c direct connection.</p>
+     * <p>This is not a standard HTTP/1.1 Upgrade path.</p>
+     */
+    public void directUpgrade()
+    {
+        if (state != State.PREFACE)
+            throw new IllegalStateException();
+        prefaceParser.directUpgrade();
+    }
+
+    /**
+     * <p>The standard HTTP/1.1 upgrade path.</p>
+     */
+    public void standardUpgrade()
+    {
+        if (state != State.PREFACE)
+            throw new IllegalStateException();
+        notifyPreface = false;
+    }
+
+    @Override
+    public void parse(ByteBuffer buffer)
+    {
+        try
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Parsing {}", buffer);
+
+            while (true)
+            {
+                switch (state)
+                {
+                    case PREFACE:
+                    {
+                        if (!prefaceParser.parse(buffer))
+                            return;
+                        if (notifyPreface)
+                            onPreface();
+                        state = State.SETTINGS;
+                        break;
+                    }
+                    case SETTINGS:
+                    {
+                        if (!parseHeader(buffer))
+                            return;
+                        if (getFrameType() != FrameType.SETTINGS.getType() || hasFlag(Flags.ACK))
+                        {
+                            BufferUtil.clear(buffer);
+                            notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_preface");
+                            return;
+                        }
+                        if (!parseBody(buffer))
+                            return;
+                        state = State.FRAMES;
+                        break;
+                    }
+                    case FRAMES:
+                    {
+                        // Stay forever in the FRAMES state.
+                        super.parse(buffer);
+                        return;
+                    }
+                    default:
+                    {
+                        throw new IllegalStateException();
+                    }
+                }
+            }
+        }
+        catch (Throwable x)
+        {
+            LOG.debug(x);
+            BufferUtil.clear(buffer);
+            notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "parser_error");
+        }
+    }
+
+    protected void onPreface()
+    {
+        notifyPreface();
+    }
+
+    private void notifyPreface()
+    {
+        try
+        {
+            listener.onPreface();
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    public interface Listener extends Parser.Listener
+    {
+        public void onPreface();
+
+        public static class Adapter extends Parser.Listener.Adapter implements Listener
+        {
+            @Override
+            public void onPreface()
+            {
+            }
+        }
+    }
+
+    private enum State
+    {
+        PREFACE, SETTINGS, FRAMES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java
new file mode 100644
index 0000000..b1de3a0
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java
@@ -0,0 +1,212 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class SettingsBodyParser extends BodyParser
+{
+    private static final Logger LOG = Log.getLogger(SettingsBodyParser.class);
+    private State state = State.PREPARE;
+    private int cursor;
+    private int length;
+    private int settingId;
+    private int settingValue;
+    private Map<Integer, Integer> settings;
+
+    public SettingsBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    protected void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        length = 0;
+        settingId = 0;
+        settingValue = 0;
+        settings = null;
+    }
+
+    @Override
+    protected void emptyBody(ByteBuffer buffer)
+    {
+        onSettings(new HashMap<>());
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    // SPEC: wrong streamId is treated as connection error.
+                    if (getStreamId() != 0)
+                        return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
+                    length = getBodyLength();
+                    settings = new HashMap<>();
+                    state = State.SETTING_ID;
+                    break;
+                }
+                case SETTING_ID:
+                {
+                    if (buffer.remaining() >= 2)
+                    {
+                        settingId = buffer.getShort() & 0xFF_FF;
+                        state = State.SETTING_VALUE;
+                        length -= 2;
+                        if (length <= 0)
+                            return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
+                    }
+                    else
+                    {
+                        cursor = 2;
+                        settingId = 0;
+                        state = State.SETTING_ID_BYTES;
+                    }
+                    break;
+                }
+                case SETTING_ID_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    settingId += currByte << (8 * cursor);
+                    --length;
+                    if (length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
+                    if (cursor == 0)
+                    {
+                        state = State.SETTING_VALUE;
+                    }
+                    break;
+                }
+                case SETTING_VALUE:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        settingValue = buffer.getInt();
+                        if (LOG.isDebugEnabled())
+                            LOG.debug(String.format("setting %d=%d",settingId, settingValue));
+                        settings.put(settingId, settingValue);
+                        state = State.SETTING_ID;
+                        length -= 4;
+                        if (length == 0)
+                            return onSettings(settings);
+                    }
+                    else
+                    {
+                        cursor = 4;
+                        settingValue = 0;
+                        state = State.SETTING_VALUE_BYTES;
+                    }
+                    break;
+                }
+                case SETTING_VALUE_BYTES:
+                {
+                    int currByte = buffer.get() & 0xFF;
+                    --cursor;
+                    settingValue += currByte << (8 * cursor);
+                    --length;
+                    if (cursor > 0 && length <= 0)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
+                    if (cursor == 0)
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug(String.format("setting %d=%d",settingId, settingValue));
+                        settings.put(settingId, settingValue);
+                        state = State.SETTING_ID;
+                        if (length == 0)
+                            return onSettings(settings);
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    protected boolean onSettings(Map<Integer, Integer> settings)
+    {
+        SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK));
+        reset();
+        notifySettings(frame);
+        return true;
+    }
+
+    public static SettingsFrame parseBody(final ByteBuffer buffer)
+    {
+        final int bodyLength = buffer.remaining();
+        final AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
+        SettingsBodyParser parser = new SettingsBodyParser(null, null)
+        {
+            @Override
+            protected int getStreamId()
+            {
+                return 0;
+            }
+
+            @Override
+            protected int getBodyLength()
+            {
+                return bodyLength;
+            }
+
+            @Override
+            protected boolean onSettings(Map<Integer, Integer> settings)
+            {
+                frameRef.set(new SettingsFrame(settings, false));
+                return true;
+            }
+
+            @Override
+            protected boolean connectionFailure(ByteBuffer buffer, int error, String reason)
+            {
+                frameRef.set(null);
+                return false;
+            }
+        };
+        if (bodyLength == 0)
+            parser.emptyBody(buffer);
+        else
+            parser.parse(buffer);
+        return frameRef.get();
+    }
+
+    private enum State
+    {
+        PREPARE, SETTING_ID, SETTING_ID_BYTES, SETTING_VALUE, SETTING_VALUE_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java
new file mode 100644
index 0000000..c847062
--- /dev/null
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/WindowUpdateBodyParser.java
@@ -0,0 +1,106 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.parser;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
+
+public class WindowUpdateBodyParser extends BodyParser
+{
+    private State state = State.PREPARE;
+    private int cursor;
+    private int windowDelta;
+
+    public WindowUpdateBodyParser(HeaderParser headerParser, Parser.Listener listener)
+    {
+        super(headerParser, listener);
+    }
+
+    private void reset()
+    {
+        state = State.PREPARE;
+        cursor = 0;
+        windowDelta = 0;
+    }
+
+    @Override
+    public boolean parse(ByteBuffer buffer)
+    {
+        while (buffer.hasRemaining())
+        {
+            switch (state)
+            {
+                case PREPARE:
+                {
+                    int length = getBodyLength();
+                    if (length != 4)
+                        return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_window_update_frame");
+                    state = State.WINDOW_DELTA;
+                    break;
+                }
+                case WINDOW_DELTA:
+                {
+                    if (buffer.remaining() >= 4)
+                    {
+                        windowDelta = buffer.getInt() & 0x7F_FF_FF_FF;
+                        return onWindowUpdate(windowDelta);
+                    }
+                    else
+                    {
+                        state = State.WINDOW_DELTA_BYTES;
+                        cursor = 4;
+                    }
+                    break;
+                }
+                case WINDOW_DELTA_BYTES:
+                {
+                    byte currByte = buffer.get();
+                    --cursor;
+                    windowDelta += (currByte & 0xFF) << 8 * cursor;
+                    if (cursor == 0)
+                    {
+                        windowDelta &= 0x7F_FF_FF_FF;
+                        return onWindowUpdate(windowDelta);
+                    }
+                    break;
+                }
+                default:
+                {
+                    throw new IllegalStateException();
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean onWindowUpdate(int windowDelta)
+    {
+        WindowUpdateFrame frame = new WindowUpdateFrame(getStreamId(), windowDelta);
+        reset();
+        notifyWindowUpdate(frame);
+        return true;
+    }
+
+    private enum State
+    {
+        PREPARE, WINDOW_DELTA, WINDOW_DELTA_BYTES
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java
new file mode 100644
index 0000000..39e7f76
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/api/UsageTest.java
@@ -0,0 +1,60 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.api;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class UsageTest
+{
+    @Ignore
+    @Test
+    public void test() throws Exception
+    {
+//        HTTP2Client client = new HTTP2Client();
+//        client.connect("localhost", 8080, new Promise.Adapter<Session>()
+//        {
+//            @Override
+//            public void succeeded(Session session)
+//            {
+//                session.newStream(new HeadersFrame(info, null, true), new Stream.Listener.Adapter()
+//                {
+//                    @Override
+//                    public void onData(Stream stream, DataFrame frame)
+//                    {
+//                        System.out.println("received frame = " + frame);
+//                    }
+//                }, new Adapter<Stream>()
+//                {
+//                    @Override
+//                    public void succeeded(Stream stream)
+//                    {
+//                        DataFrame frame = new DataFrame(stream.getId(), ByteBuffer.wrap("HELLO".getBytes(StandardCharsets.UTF_8)), true);
+//                        stream.data(frame, new Callback.Adapter());
+//                    }
+//                });
+//            }
+//        });
+
+        // KINDA CALLBACK HELL ABOVE.
+        // BELOW USING COMPLETABLES:
+
+//        client.connect("localhost", 8080).then(session -> session.newStream(...)).then(stream -> stream.data(...));
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java
new file mode 100644
index 0000000..c8a12ef
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java
@@ -0,0 +1,152 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jetty.http2.generator.DataGenerator;
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DataGenerateParseTest
+{
+    private final byte[] smallContent = new byte[128];
+    private final byte[] largeContent = new byte[128 * 1024];
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    public DataGenerateParseTest()
+    {
+        Random random = new Random();
+        random.nextBytes(smallContent);
+        random.nextBytes(largeContent);
+    }
+
+    @Test
+    public void testGenerateParseNoContentNoPadding()
+    {
+        testGenerateParseContent(BufferUtil.EMPTY_BUFFER);
+    }
+
+    @Test
+    public void testGenerateParseSmallContentNoPadding()
+    {
+        testGenerateParseContent(ByteBuffer.wrap(smallContent));
+    }
+
+    private void testGenerateParseContent(ByteBuffer content)
+    {
+        List<DataFrame> frames = testGenerateParse(content);
+        Assert.assertEquals(1, frames.size());
+        DataFrame frame = frames.get(0);
+        Assert.assertTrue(frame.getStreamId() != 0);
+        Assert.assertTrue(frame.isEndStream());
+        Assert.assertEquals(content, frame.getData());
+    }
+
+    @Test
+    public  void testGenerateParseLargeContent()
+    {
+        ByteBuffer content = ByteBuffer.wrap(largeContent);
+        List<DataFrame> frames = testGenerateParse(content);
+        Assert.assertEquals(8, frames.size());
+        ByteBuffer aggregate = ByteBuffer.allocate(content.remaining());
+        for (int i = 1; i <= frames.size(); ++i)
+        {
+            DataFrame frame = frames.get(i - 1);
+            Assert.assertTrue(frame.getStreamId() != 0);
+            Assert.assertEquals(i == frames.size(), frame.isEndStream());
+            aggregate.put(frame.getData());
+        }
+        aggregate.flip();
+        Assert.assertEquals(content, aggregate);
+    }
+
+    private List<DataFrame> testGenerateParse(ByteBuffer data)
+    {
+        DataGenerator generator = new DataGenerator(new HeaderGenerator());
+
+        final List<DataFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onData(DataFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateData(lease, 13, data.slice(), true, data.remaining());
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                parser.parse(buffer);
+            }
+        }
+
+        return frames;
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime()
+    {
+        DataGenerator generator = new DataGenerator(new HeaderGenerator());
+
+        final List<DataFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onData(DataFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            ByteBuffer data = ByteBuffer.wrap(largeContent);
+            generator.generateData(lease, 13, data.slice(), true, data.remaining());
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(largeContent.length, frames.size());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java
new file mode 100644
index 0000000..9a1d94f
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java
@@ -0,0 +1,121 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jetty.http2.generator.GoAwayGenerator;
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GoAwayGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator());
+
+        final List<GoAwayFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onGoAway(GoAwayFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int lastStreamId = 13;
+        int error = 17;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateGoAway(lease, lastStreamId, error, null);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        GoAwayFrame frame = frames.get(0);
+        Assert.assertEquals(lastStreamId, frame.getLastStreamId());
+        Assert.assertEquals(error, frame.getError());
+        Assert.assertNull(frame.getPayload());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator());
+
+        final List<GoAwayFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onGoAway(GoAwayFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int lastStreamId = 13;
+        int error = 17;
+        byte[] payload = new byte[16];
+        new Random().nextBytes(payload);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateGoAway(lease, lastStreamId, error, payload);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            GoAwayFrame frame = frames.get(0);
+            Assert.assertEquals(lastStreamId, frame.getLastStreamId());
+            Assert.assertEquals(error, frame.getError());
+            Assert.assertArrayEquals(payload, frame.getPayload());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java
new file mode 100644
index 0000000..10e69fd
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java
@@ -0,0 +1,160 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.HeadersGenerator;
+import org.eclipse.jetty.http2.hpack.HpackEncoder;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HeadersGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
+
+        int streamId = 13;
+        HttpFields fields = new HttpFields();
+        fields.put("Accept", "text/html");
+        fields.put("User-Agent", "Jetty");
+        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
+
+        final List<HeadersFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(HeadersFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
+            generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            HeadersFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertTrue(frame.isEndStream());
+            MetaData.Request request = (MetaData.Request)frame.getMetaData();
+            Assert.assertEquals(metaData.getMethod(), request.getMethod());
+            Assert.assertEquals(metaData.getURI(), request.getURI());
+            for (int j = 0; j < fields.size(); ++j)
+            {
+                HttpField field = fields.getField(j);
+                Assert.assertTrue(request.getFields().contains(field));
+            }
+            PriorityFrame priority = frame.getPriority();
+            Assert.assertNotNull(priority);
+            Assert.assertEquals(priorityFrame.getStreamId(), priority.getStreamId());
+            Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId());
+            Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight());
+            Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive());
+        }
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder());
+
+        final List<HeadersFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onHeaders(HeadersFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            int streamId = 13;
+            HttpFields fields = new HttpFields();
+            fields.put("Accept", "text/html");
+            fields.put("User-Agent", "Jetty");
+            MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
+
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            PriorityFrame priorityFrame = new PriorityFrame(streamId, 3 * streamId, 200, true);
+            generator.generateHeaders(lease, streamId, metaData, priorityFrame, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                buffer = buffer.slice();
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            HeadersFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertTrue(frame.isEndStream());
+            MetaData.Request request = (MetaData.Request)frame.getMetaData();
+            Assert.assertEquals(metaData.getMethod(), request.getMethod());
+            Assert.assertEquals(metaData.getURI(), request.getURI());
+            for (int j = 0; j < fields.size(); ++j)
+            {
+                HttpField field = fields.getField(j);
+                Assert.assertTrue(request.getFields().contains(field));
+            }
+            PriorityFrame priority = frame.getPriority();
+            Assert.assertNotNull(priority);
+            Assert.assertEquals(priorityFrame.getStreamId(), priority.getStreamId());
+            Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId());
+            Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight());
+            Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java
new file mode 100644
index 0000000..ec5c067
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java
@@ -0,0 +1,150 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.PingGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PingGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        PingGenerator generator = new PingGenerator(new HeaderGenerator());
+
+        final List<PingFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPing(PingFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        byte[] payload = new byte[8];
+        new Random().nextBytes(payload);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePing(lease, payload, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        PingFrame frame = frames.get(0);
+        Assert.assertArrayEquals(payload, frame.getPayload());
+        Assert.assertTrue(frame.isReply());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        PingGenerator generator = new PingGenerator(new HeaderGenerator());
+
+        final List<PingFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPing(PingFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        byte[] payload = new byte[8];
+        new Random().nextBytes(payload);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePing(lease, payload, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            PingFrame frame = frames.get(0);
+            Assert.assertArrayEquals(payload, frame.getPayload());
+            Assert.assertTrue(frame.isReply());
+        }
+    }
+
+    @Test
+    public void testPayloadAsLong() throws Exception
+    {
+        PingGenerator generator = new PingGenerator(new HeaderGenerator());
+
+        final List<PingFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPing(PingFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        PingFrame ping = new PingFrame(System.nanoTime(), true);
+        generator.generate(lease, ping);
+
+        for (ByteBuffer buffer : lease.getByteBuffers())
+        {
+            while (buffer.hasRemaining())
+            {
+                parser.parse(buffer);
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        PingFrame pong = frames.get(0);
+        Assert.assertEquals(ping.getPayloadAsLong(), pong.getPayloadAsLong());
+        Assert.assertTrue(pong.isReply());
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java
new file mode 100644
index 0000000..4d8a955
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java
@@ -0,0 +1,124 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.PriorityGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PriorityGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator());
+
+        final List<PriorityFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPriority(PriorityFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int parentStreamId = 17;
+        int weight = 256;
+        boolean exclusive = true;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePriority(lease, streamId, parentStreamId, weight, exclusive);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        PriorityFrame frame = frames.get(0);
+        Assert.assertEquals(streamId, frame.getStreamId());
+        Assert.assertEquals(parentStreamId, frame.getParentStreamId());
+        Assert.assertEquals(weight, frame.getWeight());
+        Assert.assertEquals(exclusive, frame.isExclusive());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator());
+
+        final List<PriorityFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPriority(PriorityFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int parentStreamId = 17;
+        int weight = 3;
+        boolean exclusive = true;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePriority(lease, streamId, parentStreamId, weight, exclusive);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            PriorityFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertEquals(parentStreamId, frame.getParentStreamId());
+            Assert.assertEquals(weight, frame.getWeight());
+            Assert.assertEquals(exclusive, frame.isExclusive());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java
new file mode 100644
index 0000000..eb7382d
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java
@@ -0,0 +1,147 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.PushPromiseGenerator;
+import org.eclipse.jetty.http2.hpack.HpackEncoder;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PushPromiseGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder());
+
+        final List<PushPromiseFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPushPromise(PushPromiseFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int promisedStreamId = 17;
+        HttpFields fields = new HttpFields();
+        fields.put("Accept", "text/html");
+        fields.put("User-Agent", "Jetty");
+        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePushPromise(lease, streamId, promisedStreamId, metaData);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            PushPromiseFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId());
+            MetaData.Request request = (MetaData.Request)frame.getMetaData();
+            Assert.assertEquals(metaData.getMethod(), request.getMethod());
+            Assert.assertEquals(metaData.getURI(), request.getURI());
+            for (int j = 0; j < fields.size(); ++j)
+            {
+                HttpField field = fields.getField(j);
+                Assert.assertTrue(request.getFields().contains(field));
+            }
+        }
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder());
+
+        final List<PushPromiseFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onPushPromise(PushPromiseFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int promisedStreamId = 17;
+        HttpFields fields = new HttpFields();
+        fields.put("Accept", "text/html");
+        fields.put("User-Agent", "Jetty");
+        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generatePushPromise(lease, streamId, promisedStreamId, metaData);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            PushPromiseFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertEquals(promisedStreamId, frame.getPromisedStreamId());
+            MetaData.Request request = (MetaData.Request)frame.getMetaData();
+            Assert.assertEquals(metaData.getMethod(), request.getMethod());
+            Assert.assertEquals(metaData.getURI(), request.getURI());
+            for (int j = 0; j < fields.size(); ++j)
+            {
+                HttpField field = fields.getField(j);
+                Assert.assertTrue(request.getFields().contains(field));
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java
new file mode 100644
index 0000000..93e7d22
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java
@@ -0,0 +1,116 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.ResetGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ResetGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        ResetGenerator generator = new ResetGenerator(new HeaderGenerator());
+
+        final List<ResetFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onReset(ResetFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int error = 17;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateReset(lease, streamId, error);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        ResetFrame frame = frames.get(0);
+        Assert.assertEquals(streamId, frame.getStreamId());
+        Assert.assertEquals(error, frame.getError());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        ResetGenerator generator = new ResetGenerator(new HeaderGenerator());
+
+        final List<ResetFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onReset(ResetFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int error = 17;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateReset(lease, streamId, error);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            ResetFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertEquals(error, frame.getError());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java
new file mode 100644
index 0000000..856ae04
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java
@@ -0,0 +1,181 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.SettingsGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SettingsGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParseNoSettings() throws Exception
+    {
+        List<SettingsFrame> frames = testGenerateParse(Collections.<Integer, Integer>emptyMap());
+        Assert.assertEquals(1, frames.size());
+        SettingsFrame frame = frames.get(0);
+        Assert.assertEquals(0, frame.getSettings().size());
+        Assert.assertTrue(frame.isReply());
+    }
+
+    @Test
+    public void testGenerateParseSettings() throws Exception
+    {
+        Map<Integer, Integer> settings1 = new HashMap<>();
+        int key1 = 13;
+        Integer value1 = 17;
+        settings1.put(key1, value1);
+        int key2 = 19;
+        Integer value2 = 23;
+        settings1.put(key2, value2);
+        List<SettingsFrame> frames = testGenerateParse(settings1);
+        Assert.assertEquals(1, frames.size());
+        SettingsFrame frame = frames.get(0);
+        Map<Integer, Integer> settings2 = frame.getSettings();
+        Assert.assertEquals(2, settings2.size());
+        Assert.assertEquals(value1, settings2.get(key1));
+        Assert.assertEquals(value2, settings2.get(key2));
+    }
+
+    private List<SettingsFrame> testGenerateParse(Map<Integer, Integer> settings)
+    {
+        SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
+
+        final List<SettingsFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(SettingsFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateSettings(lease, settings, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        return frames;
+    }
+
+    @Test
+    public void testGenerateParseInvalidSettings() throws Exception
+    {
+        SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
+
+        final AtomicInteger errorRef = new AtomicInteger();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onConnectionFailure(int error, String reason)
+            {
+                errorRef.set(error);
+            }
+        }, 4096, 8192);
+
+        Map<Integer, Integer> settings1 = new HashMap<>();
+        settings1.put(13, 17);
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.generateSettings(lease, settings1, true);
+        // Modify the length of the frame to make it invalid
+        ByteBuffer bytes = lease.getByteBuffers().get(0);
+        bytes.putShort(1, (short)(bytes.getShort(1) - 1));
+
+        for (ByteBuffer buffer : lease.getByteBuffers())
+        {
+            while (buffer.hasRemaining())
+            {
+                parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+            }
+        }
+
+        Assert.assertEquals(ErrorCode.FRAME_SIZE_ERROR.code, errorRef.get());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator());
+
+        final List<SettingsFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onSettings(SettingsFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        Map<Integer, Integer> settings1 = new HashMap<>();
+        int key = 13;
+        Integer value = 17;
+        settings1.put(key, value);
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateSettings(lease, settings1, true);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            SettingsFrame frame = frames.get(0);
+            Map<Integer, Integer> settings2 = frame.getSettings();
+            Assert.assertEquals(1, settings2.size());
+            Assert.assertEquals(value, settings2.get(key));
+            Assert.assertTrue(frame.isReply());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java
new file mode 100644
index 0000000..158524b
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java
@@ -0,0 +1,116 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.frames;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http2.generator.HeaderGenerator;
+import org.eclipse.jetty.http2.generator.WindowUpdateGenerator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class WindowUpdateGenerateParseTest
+{
+    private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
+
+    @Test
+    public void testGenerateParse() throws Exception
+    {
+        WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
+
+        final List<WindowUpdateFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onWindowUpdate(WindowUpdateFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int windowUpdate = 17;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateWindowUpdate(lease, streamId, windowUpdate);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(buffer);
+                }
+            }
+        }
+
+        Assert.assertEquals(1, frames.size());
+        WindowUpdateFrame frame = frames.get(0);
+        Assert.assertEquals(streamId, frame.getStreamId());
+        Assert.assertEquals(windowUpdate, frame.getWindowDelta());
+    }
+
+    @Test
+    public void testGenerateParseOneByteAtATime() throws Exception
+    {
+        WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
+
+        final List<WindowUpdateFrame> frames = new ArrayList<>();
+        Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+        {
+            @Override
+            public void onWindowUpdate(WindowUpdateFrame frame)
+            {
+                frames.add(frame);
+            }
+        }, 4096, 8192);
+
+        int streamId = 13;
+        int windowUpdate = 17;
+
+        // Iterate a few times to be sure generator and parser are properly reset.
+        for (int i = 0; i < 2; ++i)
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.generateWindowUpdate(lease, streamId, windowUpdate);
+
+            frames.clear();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                while (buffer.hasRemaining())
+                {
+                    parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
+                }
+            }
+
+            Assert.assertEquals(1, frames.size());
+            WindowUpdateFrame frame = frames.get(0);
+            Assert.assertEquals(streamId, frame.getStreamId());
+            Assert.assertEquals(windowUpdate, frame.getWindowDelta());
+        }
+    }
+}
diff --git a/jetty-http2/http2-common/src/test/resources/jetty-logging.properties b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..b4e4380
--- /dev/null
+++ b/jetty-http2/http2-common/src/test/resources/jetty-logging.properties
@@ -0,0 +1,2 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.http2.LEVEL=INFO
diff --git a/jetty-http2/http2-hpack/pom.xml b/jetty-http2/http2-hpack/pom.xml
new file mode 100644
index 0000000..d205412
--- /dev/null
+++ b/jetty-http2/http2-hpack/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.http2</groupId>
+    <artifactId>http2-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>http2-hpack</artifactId>
+  <name>Jetty :: HTTP2 :: HPACK</name>
+
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.hpack</bundle-symbolic-name>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-http</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-io</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util-ajax</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+  </build>
+
+</project>
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java
new file mode 100644
index 0000000..155b3f7
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/AuthorityHttpField.java
@@ -0,0 +1,43 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpHeader;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class AuthorityHttpField extends HostPortHttpField
+{
+    public final static String AUTHORITY = HpackContext.STATIC_TABLE[1][0];
+    
+    public AuthorityHttpField(String authority)
+    {
+        super(HttpHeader.C_AUTHORITY,AUTHORITY,authority);
+    }
+    
+    @Override
+    public String toString()
+    {
+        return String.format("%s(preparsed h=%s p=%d)",super.toString(),getHost(),getPort());
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java
new file mode 100644
index 0000000..89fbf00
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java
@@ -0,0 +1,515 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.util.ArrayQueue;
+import org.eclipse.jetty.util.ArrayTernaryTrie;
+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;
+
+
+/* ------------------------------------------------------------ */
+/** HPACK - Header Compression for HTTP/2
+ * <p>This class maintains the compression context for a single HTTP/2
+ * connection. Specifically it holds the static and dynamic Header Field Tables
+ * and the associated sizes and limits.
+ * </p>
+ * <p>It is compliant with draft 11 of the specification</p>
+ */
+public class HpackContext
+{
+    public static final Logger LOG = Log.getLogger(HpackContext.class);
+    
+    public static final String[][] STATIC_TABLE = 
+    {
+        {null,null},
+        /* 1  */ {":authority",null},
+        /* 2  */ {":method","GET"},
+        /* 3  */ {":method","POST"},
+        /* 4  */ {":path","/"},
+        /* 5  */ {":path","/index.html"},
+        /* 6  */ {":scheme","http"},
+        /* 7  */ {":scheme","https"},
+        /* 8  */ {":status","200"},
+        /* 9  */ {":status","204"},
+        /* 10 */ {":status","206"},
+        /* 11 */ {":status","304"},
+        /* 12 */ {":status","400"},
+        /* 13 */ {":status","404"},
+        /* 14 */ {":status","500"},
+        /* 15 */ {"accept-charset",null},
+        /* 16 */ {"accept-encoding","gzip, deflate"},
+        /* 17 */ {"accept-language",null},
+        /* 18 */ {"accept-ranges",null},
+        /* 19 */ {"accept",null},
+        /* 20 */ {"access-control-allow-origin",null},
+        /* 21 */ {"age",null},
+        /* 22 */ {"allow",null},
+        /* 23 */ {"authorization",null},
+        /* 24 */ {"cache-control",null},
+        /* 25 */ {"content-disposition",null},
+        /* 26 */ {"content-encoding",null},
+        /* 27 */ {"content-language",null},
+        /* 28 */ {"content-length",null},
+        /* 29 */ {"content-location",null},
+        /* 30 */ {"content-range",null},
+        /* 31 */ {"content-type",null},
+        /* 32 */ {"cookie",null},
+        /* 33 */ {"date",null},
+        /* 34 */ {"etag",null},
+        /* 35 */ {"expect",null},
+        /* 36 */ {"expires",null},
+        /* 37 */ {"from",null},
+        /* 38 */ {"host",null},
+        /* 39 */ {"if-match",null},
+        /* 40 */ {"if-modified-since",null},
+        /* 41 */ {"if-none-match",null},
+        /* 42 */ {"if-range",null},
+        /* 43 */ {"if-unmodified-since",null},
+        /* 44 */ {"last-modified",null},
+        /* 45 */ {"link",null},
+        /* 46 */ {"location",null},
+        /* 47 */ {"max-forwards",null},
+        /* 48 */ {"proxy-authenticate",null},
+        /* 49 */ {"proxy-authorization",null},
+        /* 50 */ {"range",null},
+        /* 51 */ {"referer",null},
+        /* 52 */ {"refresh",null},
+        /* 53 */ {"retry-after",null},
+        /* 54 */ {"server",null},
+        /* 55 */ {"set-cookie",null},
+        /* 56 */ {"strict-transport-security",null},
+        /* 57 */ {"transfer-encoding",null},
+        /* 58 */ {"user-agent",null},
+        /* 59 */ {"vary",null},
+        /* 60 */ {"via",null},
+        /* 61 */ {"www-authenticate",null},
+    };
+    
+    private static final Map<HttpField,Entry> __staticFieldMap = new HashMap<>();
+    private static final Trie<StaticEntry> __staticNameMap = new ArrayTernaryTrie<>(true,512);
+    private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.UNKNOWN.ordinal()];
+    private static final StaticEntry[] __staticTable=new StaticEntry[STATIC_TABLE.length];
+    static
+    {
+        Set<String> added = new HashSet<>();
+        for (int i=1;i<STATIC_TABLE.length;i++)
+        {
+            StaticEntry entry=null;
+
+            String name  = STATIC_TABLE[i][0];
+            String value = STATIC_TABLE[i][1];
+            HttpHeader header = HttpHeader.CACHE.get(name);
+            if (header!=null && value!=null)
+            {
+                switch (header)
+                {
+                    case C_METHOD:
+                    {
+                        
+                        HttpMethod method = HttpMethod.CACHE.get(value);
+                        if (method!=null)
+                            entry=new StaticEntry(i,new StaticTableHttpField(header,name,value,method));
+                        break;
+                    }
+                    
+                    case C_SCHEME:
+                    {
+                        
+                        HttpScheme scheme = HttpScheme.CACHE.get(value);
+                        if (scheme!=null)
+                            entry=new StaticEntry(i,new StaticTableHttpField(header,name,value,scheme));
+                        break;
+                    }
+                    
+                    case C_STATUS:
+                    {
+                        entry=new StaticEntry(i,new StaticTableHttpField(header,name,value,Integer.valueOf(value)));
+                        break;
+                    }
+                    
+                    default:
+                        break;
+                }
+            }
+            
+            if (entry==null)
+                entry=new StaticEntry(i,header==null?new HttpField(STATIC_TABLE[i][0],value):new HttpField(header,name,value));
+            
+                        
+            __staticTable[i]=entry;
+            
+            if (entry._field.getValue()!=null)
+                __staticFieldMap.put(entry._field,entry);
+            
+            if (!added.contains(entry._field.getName()))
+            {
+                added.add(entry._field.getName());
+                __staticNameMap.put(entry._field.getName(),entry);
+                if (__staticNameMap.get(entry._field.getName())==null)
+                    throw new IllegalStateException("name trie too small");
+            }
+        }
+        
+        for (HttpHeader h : HttpHeader.values())
+        {
+            StaticEntry entry = __staticNameMap.get(h.asString());
+            if (entry!=null)
+                __staticTableByHeader[h.ordinal()]=entry;
+        }
+    }
+    
+    private int _maxDynamicTableSizeInBytes;
+    private int _dynamicTableSizeInBytes;
+    private final DynamicTable _dynamicTable;
+    private final Map<HttpField,Entry> _fieldMap = new HashMap<>();
+    private final Map<String,Entry> _nameMap = new HashMap<>();
+    
+    HpackContext(int maxDynamicTableSize)
+    {
+        _maxDynamicTableSizeInBytes=maxDynamicTableSize;
+        int guesstimateEntries = 10+maxDynamicTableSize/(32+10+10);
+        _dynamicTable=new DynamicTable(guesstimateEntries,guesstimateEntries+10);
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("HdrTbl[%x] created max=%d",hashCode(),maxDynamicTableSize));
+    }
+    
+    public void resize(int newMaxDynamicTableSize)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d",hashCode(),_maxDynamicTableSizeInBytes,newMaxDynamicTableSize));
+        _maxDynamicTableSizeInBytes=newMaxDynamicTableSize;
+        int guesstimateEntries = 10+newMaxDynamicTableSize/(32+10+10);
+        evict();
+        _dynamicTable.resizeUnsafe(guesstimateEntries);
+    }
+    
+    public Entry get(HttpField field)
+    {
+        Entry entry = _fieldMap.get(field);
+        if (entry==null)
+            entry=__staticFieldMap.get(field);
+        return entry;
+    }
+    
+    public Entry get(String name)
+    {
+        Entry entry = __staticNameMap.get(name);
+        if (entry!=null)
+            return entry;
+        return _nameMap.get(StringUtil.asciiToLowerCase(name));
+    }
+    
+    public Entry get(int index)
+    {
+        if (index<__staticTable.length)
+            return __staticTable[index];
+            
+        int d=_dynamicTable.size()-index+__staticTable.length-1;
+
+        if (d>=0) 
+            return _dynamicTable.getUnsafe(d);      
+        return null;
+    }
+    
+    public Entry get(HttpHeader header)
+    {
+        Entry e = __staticTableByHeader[header.ordinal()];
+        if (e==null)
+            return get(header.asString());
+        return e;
+    }
+
+    public static Entry getStatic(HttpHeader header)
+    {
+        return __staticTableByHeader[header.ordinal()];
+    }
+    
+    public Entry add(HttpField field)
+    {
+        int slot=_dynamicTable.getNextSlotUnsafe();
+        Entry entry=new Entry(slot,field);
+        int size = entry.getSize();
+        if (size>_maxDynamicTableSizeInBytes)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(String.format("HdrTbl[%x] !added size %d>%d",hashCode(),size,_maxDynamicTableSizeInBytes));
+            return null;
+        }
+        _dynamicTableSizeInBytes+=size;
+        _dynamicTable.addUnsafe(entry);
+        _fieldMap.put(field,entry);
+        _nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("HdrTbl[%x] added %s",hashCode(),entry));
+        evict();
+        return entry;
+    }
+
+    /**
+     * @return Current dynamic table size in entries
+     */
+    public int size()
+    {
+        return _dynamicTable.size();
+    }
+    
+    /**
+     * @return Current Dynamic table size in Octets
+     */
+    public int getDynamicTableSize()
+    {
+        return _dynamicTableSizeInBytes;
+    }
+
+    /**
+     * @return Max Dynamic table size in Octets
+     */
+    public int getMaxDynamicTableSize()
+    {
+        return _maxDynamicTableSizeInBytes;
+    }
+
+    public int index(Entry entry)
+    {
+        if (entry._slot<0)
+            return 0;
+        if (entry.isStatic())
+            return entry._slot;
+
+        return _dynamicTable.index(entry)+__staticTable.length-1;
+    }
+    
+    public static int staticIndex(HttpHeader header)
+    {
+        if (header==null)
+            return 0;
+        Entry entry=__staticNameMap.get(header.asString());
+        if (entry==null)
+            return 0;
+        return entry.getSlot();
+    }
+    
+    private void evict()
+    {
+        while (_dynamicTableSizeInBytes>_maxDynamicTableSizeInBytes)
+        {
+            Entry entry = _dynamicTable.pollUnsafe();
+            if (LOG.isDebugEnabled())
+                LOG.debug(String.format("HdrTbl[%x] evict %s",hashCode(),entry));
+            _dynamicTableSizeInBytes-=entry.getSize();
+            entry._slot=-1;
+            _fieldMap.remove(entry.getHttpField());
+            String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName());
+            if (entry==_nameMap.get(lc))
+                _nameMap.remove(lc);
+        }
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d",hashCode(),_dynamicTable.size(),_dynamicTableSizeInBytes,_maxDynamicTableSizeInBytes));
+    }
+    
+    @Override
+    public String toString()
+    {
+        return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}",hashCode(),_dynamicTable.size(),_dynamicTableSizeInBytes,_maxDynamicTableSizeInBytes);
+    }
+    
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     */
+    private class DynamicTable extends ArrayQueue<HpackContext.Entry>
+    {
+        /* ------------------------------------------------------------ */
+        /**
+         * @param initCapacity
+         * @param growBy
+         */
+        private DynamicTable(int initCapacity, int growBy)
+        {
+            super(initCapacity,growBy);
+        }
+
+        /* ------------------------------------------------------------ */
+        /**
+         * @see org.eclipse.jetty.util.ArrayQueue#growUnsafe()
+         */
+        @Override
+        protected void resizeUnsafe(int newCapacity)
+        {
+            // Relay on super.growUnsafe to pack all entries 0 to _nextSlot
+            super.resizeUnsafe(newCapacity);
+            for (int s=0;s<_nextSlot;s++)
+                ((Entry)_elements[s])._slot=s;
+        }
+
+        /* ------------------------------------------------------------ */
+        /**
+         * @see org.eclipse.jetty.util.ArrayQueue#enqueue(java.lang.Object)
+         */
+        @Override
+        public boolean enqueue(Entry e)
+        {
+            return super.enqueue(e);
+        }
+
+        /* ------------------------------------------------------------ */
+        /**
+         * @see org.eclipse.jetty.util.ArrayQueue#dequeue()
+         */
+        @Override
+        public Entry dequeue()
+        {
+            return super.dequeue();
+        }
+        
+        /* ------------------------------------------------------------ */
+        /**
+         * @param entry
+         * @return
+         */
+        private int index(Entry entry)
+        {
+            return entry._slot>=_nextE?_size-entry._slot+_nextE:_nextSlot-entry._slot;
+        }
+
+    }
+
+
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    public static class Entry
+    {
+        final HttpField _field;
+        int _slot;
+        
+        Entry()
+        {    
+            _slot=0;
+            _field=null;
+        }
+        
+        Entry(int index,String name, String value)
+        {    
+            _slot=index;
+            _field=new HttpField(name,value);
+        }
+        
+        Entry(int slot, HttpField field)
+        {    
+            _slot=slot;
+            _field=field;
+        }
+
+        public int getSize()
+        {
+            return 32+_field.getName().length()+_field.getValue().length();
+        }
+        
+        public HttpField getHttpField()
+        {
+            return _field;
+        }
+        
+        public boolean isStatic()
+        {
+            return false;
+        }
+        
+        public byte[] getStaticHuffmanValue()
+        {
+            return null;
+        }
+        
+        public int getSlot()
+        {
+            return _slot;
+        }
+        
+        public String toString()
+        {
+            return String.format("{%s,%d,%s,%x}",isStatic()?"S":"D",_slot,_field,hashCode());
+        }
+    } 
+    
+    public static class StaticEntry extends Entry
+    {
+        private final byte[] _huffmanValue;
+        private final byte _encodedField;
+        
+        StaticEntry(int index,HttpField field)
+        {    
+            super(index,field);
+            String value = field.getValue();
+            if (value!=null && value.length()>0)
+            {
+                int huffmanLen = Huffman.octetsNeeded(value);
+                int lenLen = NBitInteger.octectsNeeded(7,huffmanLen);
+                _huffmanValue = new byte[1+lenLen+huffmanLen];
+                ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); 
+                        
+                // Indicate Huffman
+                buffer.put((byte)0x80);
+                // Add huffman length
+                NBitInteger.encode(buffer,7,huffmanLen);
+                // Encode value
+                Huffman.encode(buffer,value);       
+            }
+            else
+                _huffmanValue=null;
+            
+            _encodedField=(byte)(0x80|index);
+        }
+
+        @Override
+        public boolean isStatic()
+        {
+            return true;
+        }
+        
+        @Override
+        public byte[] getStaticHuffmanValue()
+        {
+            return _huffmanValue;
+        }
+        
+        public byte getEncodedField()
+        {
+            return _encodedField;
+        }
+    }
+
+
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java
new file mode 100644
index 0000000..38dc856
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java
@@ -0,0 +1,280 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Hpack Decoder
+ * <p>This is not thread safe and may only be called by 1 thread at a time.</p>
+ */
+public class HpackDecoder
+{
+    public static final Logger LOG = Log.getLogger(HpackDecoder.class);
+    public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 =
+            new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L);
+
+    private final HpackContext _context;
+    private final MetaDataBuilder _builder;
+    private int _localMaxDynamicTableSize;
+
+    /**
+     * @param localMaxDynamicTableSize  The maximum allowed size of the local dynamic header field table.
+     * @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters.
+     */
+    public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize)
+    {
+        _context=new HpackContext(localMaxDynamicTableSize);
+        _localMaxDynamicTableSize=localMaxDynamicTableSize;
+        _builder = new MetaDataBuilder(maxHeaderSize);
+    }
+
+    public HpackContext getHpackContext()
+    {
+        return _context;
+    }
+
+    public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize)
+    {
+        _localMaxDynamicTableSize=localMaxdynamciTableSize;
+    }
+
+    public MetaData decode(ByteBuffer buffer)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining()));
+
+        // If the buffer is big, don't even think about decoding it
+        if (buffer.remaining()>_builder.getMaxSize())
+            throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize());
+
+
+        while(buffer.hasRemaining())
+        {
+            if (LOG.isDebugEnabled())
+            {
+                int l=Math.min(buffer.remaining(),16);
+                // TODO: not guaranteed the buffer has a backing array !
+                LOG.debug("decode {}{}",
+                        TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l),
+                        l<buffer.remaining()?"...":"");
+            }
+
+            byte b = buffer.get();
+            if (b<0)
+            {
+                // 7.1 indexed if the high bit is set
+                int index = NBitInteger.decode(buffer,7);
+                Entry entry=_context.get(index);
+                if (entry==null)
+                {
+                    throw new BadMessageException("Unknown index "+index);
+                }
+                else if (entry.isStatic())
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("decode IdxStatic {}",entry);
+                    // emit field
+                    _builder.emit(entry.getHttpField());
+
+                    // TODO copy and add to reference set if there is room
+                    // _context.add(entry.getHttpField());
+                }
+                else
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("decode Idx {}",entry);
+                    // emit
+                    _builder.emit(entry.getHttpField());
+                }
+            }
+            else
+            {
+                // look at the first nibble in detail
+                byte f= (byte)((b&0xF0)>>4);
+                String name;
+                HttpHeader header;
+                String value;
+
+                boolean indexed;
+                int name_index;
+
+                switch (f)
+                {
+                    case 2: // 7.3
+                    case 3: // 7.3
+                        // change table size
+                        int size = NBitInteger.decode(buffer,5);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("decode resize="+size);
+                        if (size>_localMaxDynamicTableSize)
+                            throw new IllegalArgumentException();
+                        _context.resize(size);
+                        continue;
+
+                    case 0: // 7.2.2
+                    case 1: // 7.2.3
+                        indexed=false;
+                        name_index=NBitInteger.decode(buffer,4);
+                        break;
+
+
+                    case 4: // 7.2.1
+                    case 5: // 7.2.1
+                    case 6: // 7.2.1
+                    case 7: // 7.2.1
+                        indexed=true;
+                        name_index=NBitInteger.decode(buffer,6);
+                        break;
+
+                    default:
+                        throw new IllegalStateException();
+                }
+
+
+                boolean huffmanName=false;
+
+                // decode the name
+                if (name_index>0)
+                {
+                    Entry name_entry=_context.get(name_index);
+                    name=name_entry.getHttpField().getName();
+                    header=name_entry.getHttpField().getHeader();
+                }
+                else
+                {
+                    huffmanName = (buffer.get()&0x80)==0x80;
+                    int length = NBitInteger.decode(buffer,7);
+                    _builder.checkSize(length,huffmanName);
+                    if (huffmanName)
+                        name=Huffman.decode(buffer,length);
+                    else
+                        name=toASCIIString(buffer,length);
+                    for (int i=0;i<name.length();i++)
+                    {
+                        char c=name.charAt(i);
+                        if (c>='A'&&c<='Z')
+                        {
+                            throw new BadMessageException(400,"Uppercase header name");
+                        }
+                    }
+                    header=HttpHeader.CACHE.get(name);
+                }
+
+                // decode the value
+                boolean huffmanValue = (buffer.get()&0x80)==0x80;
+                int length = NBitInteger.decode(buffer,7);
+                _builder.checkSize(length,huffmanValue);
+                if (huffmanValue)
+                    value=Huffman.decode(buffer,length);
+                else
+                    value=toASCIIString(buffer,length);
+
+                // Make the new field
+                HttpField field;
+                if (header==null)
+                {
+                    // just make a normal field and bypass header name lookup
+                    field = new HttpField(null,name,value);
+                }
+                else
+                {
+                    // might be worthwhile to create a value HttpField if it is indexed
+                    // and/or of a type that may be looked up multiple times.
+                    switch(header)
+                    {
+                        case C_STATUS:
+                            if (indexed)
+                                field = new HttpField.IntValueHttpField(header,name,value);
+                            else
+                                field = new HttpField(header,name,value);
+                            break;
+
+                        case C_AUTHORITY:
+                            field = new AuthorityHttpField(value);
+                            break;
+
+                        case CONTENT_LENGTH:
+                            if ("0".equals(value))
+                                field = CONTENT_LENGTH_0;
+                            else
+                                field = new HttpField.LongValueHttpField(header,name,value);
+                            break;
+
+                        default:
+                            field = new HttpField(header,name,value);
+                            break;
+                    }
+                }
+
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("decoded '{}' by {}/{}/{}",
+                            field,
+                            name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"),
+                            huffmanValue ? "HuffVal" : "LitVal",
+                            indexed ? "Idx" : "");
+                }
+
+                // emit the field
+                _builder.emit(field);
+
+                // if indexed
+                if (indexed)
+                {
+                    // add to dynamic table
+                    _context.add(field);
+                }
+
+            }
+        }
+
+        return _builder.build();
+    }
+
+    public static String toASCIIString(ByteBuffer buffer,int length)
+    {
+        StringBuilder builder = new StringBuilder(length);
+        int position=buffer.position();
+        int start=buffer.arrayOffset()+ position;
+        int end=start+length;
+        buffer.position(position+length);
+        byte[] array=buffer.array();
+        for (int i=start;i<end;i++)
+            builder.append((char)(0x7f&array[i]));
+        return builder.toString();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("HpackDecoder@%x{%s}",hashCode(),_context);
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java
new file mode 100644
index 0000000..e42ffb8
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java
@@ -0,0 +1,354 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+import java.util.EnumSet;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
+import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class HpackEncoder
+{
+    public static final Logger LOG = Log.getLogger(HpackEncoder.class);
+
+    private final static HttpField[] __status= new HttpField[599];
+
+
+    final static EnumSet<HttpHeader> __DO_NOT_HUFFMAN =
+            EnumSet.of(
+                    HttpHeader.AUTHORIZATION,
+                    HttpHeader.CONTENT_MD5,
+                    HttpHeader.PROXY_AUTHENTICATE,
+                    HttpHeader.PROXY_AUTHORIZATION);
+
+    final static EnumSet<HttpHeader> __DO_NOT_INDEX =
+            EnumSet.of(
+                    // HttpHeader.C_PATH,  // TODO more data needed
+                    // HttpHeader.DATE,    // TODO more data needed
+                    HttpHeader.AUTHORIZATION,
+                    HttpHeader.CONTENT_MD5,
+                    HttpHeader.CONTENT_RANGE,
+                    HttpHeader.ETAG,
+                    HttpHeader.IF_MODIFIED_SINCE,
+                    HttpHeader.IF_UNMODIFIED_SINCE,
+                    HttpHeader.IF_NONE_MATCH,
+                    HttpHeader.IF_RANGE,
+                    HttpHeader.IF_MATCH,
+                    HttpHeader.LOCATION,
+                    HttpHeader.RANGE,
+                    HttpHeader.RETRY_AFTER,
+                    // HttpHeader.EXPIRES,
+                    HttpHeader.LAST_MODIFIED,
+                    HttpHeader.SET_COOKIE,
+                    HttpHeader.SET_COOKIE2);
+
+
+    final static EnumSet<HttpHeader> __NEVER_INDEX =
+            EnumSet.of(
+                    HttpHeader.AUTHORIZATION,
+                    HttpHeader.SET_COOKIE,
+                    HttpHeader.SET_COOKIE2);
+
+    static
+    {
+        for (HttpStatus.Code code : HttpStatus.Code.values())
+            __status[code.getCode()]=new PreEncodedHttpField(HttpHeader.C_STATUS,Integer.toString(code.getCode()));
+    }
+
+    private final HpackContext _context;
+    private final boolean _debug;
+    private int _remoteMaxDynamicTableSize;
+    private int _localMaxDynamicTableSize;
+
+    public HpackEncoder()
+    {
+        this(4096,4096);
+    }
+
+    public HpackEncoder(int localMaxDynamicTableSize)
+    {
+        this(localMaxDynamicTableSize,4096);
+    }
+
+    public HpackEncoder(int localMaxDynamicTableSize,int remoteMaxDynamicTableSize)
+    {
+        _context=new HpackContext(remoteMaxDynamicTableSize);
+        _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize;
+        _localMaxDynamicTableSize=localMaxDynamicTableSize;
+        _debug=LOG.isDebugEnabled();
+    }
+
+    public HpackContext getHpackContext()
+    {
+        return _context;
+    }
+
+    public void setRemoteMaxDynamicTableSize(int remoteMaxDynamicTableSize)
+    {
+        _remoteMaxDynamicTableSize=remoteMaxDynamicTableSize;
+    }
+
+    public void setLocalMaxDynamicTableSize(int localMaxDynamicTableSize)
+    {
+        _localMaxDynamicTableSize=localMaxDynamicTableSize;
+    }
+
+    public void encode(ByteBuffer buffer, MetaData metadata)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("CtxTbl[%x] encoding",_context.hashCode()));
+
+        int pos = buffer.position();
+
+        // Check the dynamic table sizes!
+        int maxDynamicTableSize=Math.min(_remoteMaxDynamicTableSize,_localMaxDynamicTableSize);
+        if (maxDynamicTableSize!=_context.getMaxDynamicTableSize())
+            encodeMaxDynamicTableSize(buffer,maxDynamicTableSize);
+
+        // Add Request/response meta fields
+        if (metadata.isRequest())
+        {
+            MetaData.Request request = (MetaData.Request)metadata;
+
+            // TODO optimise these to avoid HttpField creation
+            String scheme=request.getURI().getScheme();
+            encode(buffer,new HttpField(HttpHeader.C_SCHEME,scheme==null?HttpScheme.HTTP.asString():scheme));
+            encode(buffer,new HttpField(HttpHeader.C_METHOD,request.getMethod()));
+            encode(buffer,new HttpField(HttpHeader.C_AUTHORITY,request.getURI().getAuthority()));
+            encode(buffer,new HttpField(HttpHeader.C_PATH,request.getURI().getPathQuery()));
+
+        }
+        else if (metadata.isResponse())
+        {
+            MetaData.Response response = (MetaData.Response)metadata;
+            int code=response.getStatus();
+            HttpField status = code<__status.length?__status[code]:null;
+            if (status==null)
+                status=new HttpField.IntValueHttpField(HttpHeader.C_STATUS,code);
+            encode(buffer,status);
+        }
+
+        // Add all the other fields
+        for (HttpField field : metadata)
+            encode(buffer,field);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("CtxTbl[%x] encoded %d octets",_context.hashCode(), buffer.position() - pos));
+    }
+
+    public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxDynamicTableSize)
+    {
+        if (maxDynamicTableSize>_remoteMaxDynamicTableSize)
+            throw new IllegalArgumentException();
+        buffer.put((byte)0x20);
+        NBitInteger.encode(buffer,5,maxDynamicTableSize);
+        _context.resize(maxDynamicTableSize);
+    }
+
+    public void encode(ByteBuffer buffer, HttpField field)
+    {
+        final int p=_debug?buffer.position():-1;
+
+        String encoding=null;
+
+        // Is there an entry for the field?
+        Entry entry = _context.get(field);
+        if (entry!=null)
+        {
+            // Known field entry, so encode it as indexed
+            if (entry.isStatic())
+            {
+                buffer.put(((StaticEntry)entry).getEncodedField());
+                if (_debug)
+                    encoding="IdxFieldS1";
+            }
+            else
+            {
+                int index=_context.index(entry);
+                buffer.put((byte)0x80);
+                NBitInteger.encode(buffer,7,index);
+                if (_debug)
+                    encoding="IdxField"+(entry.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(7,index));
+            }
+        }
+        else
+        {
+            // Unknown field entry, so we will have to send literally.
+            final boolean indexed;
+
+            // But do we know it's name?
+            HttpHeader header = field.getHeader();
+
+            // Select encoding strategy
+            if (header==null)
+            {
+                // Select encoding strategy for unknown header names
+                Entry name = _context.get(field.getName());
+
+                if (field instanceof PreEncodedHttpField)
+                {
+                    int i=buffer.position();
+                    ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2);
+                    byte b=buffer.get(i);
+                    indexed=b<0||b>=0x40;
+                    if (_debug)
+                        encoding=indexed?"PreEncodedIdx":"PreEncoded";
+                }
+                // has the custom header name been seen before?
+                else if (name==null)
+                {
+                    // unknown name and value, so let's index this just in case it is
+                    // the first time we have seen a custom name or a custom field.
+                    // unless the name is changing, this is worthwhile
+                    indexed=true;
+                    encodeName(buffer,(byte)0x40,6,field.getName(),null);
+                    encodeValue(buffer,true,field.getValue());
+                    if (_debug)
+                        encoding="LitHuffNHuffVIdx";
+                }
+                else
+                {
+                    // known custom name, but unknown value.
+                    // This is probably a custom field with changing value, so don't index.
+                    indexed=false;
+                    encodeName(buffer,(byte)0x00,4,field.getName(),null);
+                    encodeValue(buffer,true,field.getValue());
+                    if (_debug)
+                        encoding="LitHuffNHuffV!Idx";
+                }
+            }
+            else
+            {
+                // Select encoding strategy for known header names
+                Entry name = _context.get(header);
+
+                if (field instanceof PreEncodedHttpField)
+                {
+                    // Preencoded field
+                    int i=buffer.position();
+                    ((PreEncodedHttpField)field).putTo(buffer,HttpVersion.HTTP_2);
+                    byte b=buffer.get(i);
+                    indexed=b<0||b>=0x40;
+                    if (_debug)
+                        encoding=indexed?"PreEncodedIdx":"PreEncoded";
+                }
+                else if (__DO_NOT_INDEX.contains(header))
+                {
+                    // Non indexed field
+                    indexed=false;
+                    boolean never_index=__NEVER_INDEX.contains(header);
+                    boolean huffman=!__DO_NOT_HUFFMAN.contains(header);
+                    encodeName(buffer,never_index?(byte)0x10:(byte)0x00,4,header.asString(),name);
+                    encodeValue(buffer,huffman,field.getValue());
+
+                    if (_debug)
+                        encoding="Lit"+
+                                ((name==null)?"HuffN":("IdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(4,_context.index(name)))))+
+                                (huffman?"HuffV":"LitV")+
+                                (indexed?"Idx":(never_index?"!!Idx":"!Idx"));
+                }
+                else if (header==HttpHeader.CONTENT_LENGTH && field.getValue().length()>1)
+                {
+                    // Non indexed content length for 2 digits or more
+                    indexed=false;
+                    encodeName(buffer,(byte)0x00,4,header.asString(),name);
+                    encodeValue(buffer,true,field.getValue());
+                    if (_debug)
+                        encoding="LitIdxNS"+(1+NBitInteger.octectsNeeded(4,_context.index(name)))+"HuffV!Idx";
+                }
+                else
+                {
+                    // indexed
+                    indexed=true;
+                    boolean huffman=!__DO_NOT_HUFFMAN.contains(header);
+                    encodeName(buffer,(byte)0x40,6,header.asString(),name);
+                    encodeValue(buffer,huffman,field.getValue());
+                    if (_debug)
+                        encoding=((name==null)?"LitHuffN":("LitIdxN"+(name.isStatic()?"S":"")+(1+NBitInteger.octectsNeeded(6,_context.index(name)))))+
+                                (huffman?"HuffVIdx":"LitVIdx");
+                }
+            }
+
+            // If we want the field referenced, then we add it to our
+            // table and reference set.
+            if (indexed)
+                _context.add(field);
+        }
+
+        if (_debug)
+        {
+            int e=buffer.position();
+            if (LOG.isDebugEnabled())
+                LOG.debug("encode {}:'{}' to '{}'",encoding,field,TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+p,e-p));
+        }
+    }
+
+    private void encodeName(ByteBuffer buffer, byte mask, int bits, String name, Entry entry)
+    {
+        buffer.put(mask);
+        if (entry==null)
+        {
+            // leave name index bits as 0
+            // Encode the name always with lowercase huffman
+            buffer.put((byte)0x80);
+            NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name));
+            Huffman.encodeLC(buffer,name);
+        }
+        else
+        {
+            NBitInteger.encode(buffer,bits,_context.index(entry));
+        }
+    }
+
+    static void encodeValue(ByteBuffer buffer, boolean huffman, String value)
+    {
+        if (huffman)
+        {
+            // huffman literal value
+            buffer.put((byte)0x80);
+            NBitInteger.encode(buffer,7,Huffman.octetsNeeded(value));
+            Huffman.encode(buffer,value);
+        }
+        else
+        {
+            // add literal assuming iso_8859_1
+            buffer.put((byte)0x00);
+            NBitInteger.encode(buffer,7,value.length());
+            for (int i=0;i<value.length();i++)
+            {
+                char c=value.charAt(i);
+                if (c<' '|| c>127)
+                    throw new IllegalArgumentException();
+                buffer.put((byte)c);
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java
new file mode 100644
index 0000000..f73b347
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java
@@ -0,0 +1,97 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.HttpFieldPreEncoder;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.util.BufferUtil;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class HpackFieldPreEncoder implements HttpFieldPreEncoder
+{
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion()
+     */
+    @Override
+    public HttpVersion getHttpVersion()
+    {
+        return HttpVersion.HTTP_2;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String)
+     */
+    @Override
+    public byte[] getEncodedField(HttpHeader header, String name, String value)
+    {
+        boolean not_indexed=HpackEncoder.__DO_NOT_INDEX.contains(header);
+        
+        ByteBuffer buffer = BufferUtil.allocate(name.length()+value.length()+10);
+        BufferUtil.clearToFill(buffer);
+        boolean huffman;
+        int bits;
+        
+        if (not_indexed)
+        {
+            // Non indexed field
+            boolean never_index=HpackEncoder.__NEVER_INDEX.contains(header);
+            huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header);
+            buffer.put(never_index?(byte)0x10:(byte)0x00);
+            bits=4;
+        }
+        else if (header==HttpHeader.CONTENT_LENGTH && value.length()>1)
+        {
+            // Non indexed content length for 2 digits or more
+            buffer.put((byte)0x00);
+            huffman=true;
+            bits=4;
+        }
+        else
+        {
+            // indexed
+            buffer.put((byte)0x40);
+            huffman=!HpackEncoder.__DO_NOT_HUFFMAN.contains(header);
+            bits=6;
+        }
+        
+        int name_idx=HpackContext.staticIndex(header);
+        if (name_idx>0)
+            NBitInteger.encode(buffer,bits,name_idx);
+        else
+        {
+            buffer.put((byte)0x80);
+            NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(name));
+            Huffman.encodeLC(buffer,name);
+        }
+
+        HpackEncoder.encodeValue(buffer,huffman,value);
+        
+        BufferUtil.flipToFlush(buffer,0);
+        return BufferUtil.toArray(buffer);
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java
new file mode 100644
index 0000000..da28684
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java
@@ -0,0 +1,480 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+
+public class Huffman
+{
+
+    // Appendix C: Huffman Codes
+    // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C
+    static final int[][] CODES =
+    { 
+        /*    (  0)  |11111111|11000                      */       {0x1ff8,13},
+        /*    (  1)  |11111111|11111111|1011000           */     {0x7fffd8,23},
+        /*    (  2)  |11111111|11111111|11111110|0010     */    {0xfffffe2,28},
+        /*    (  3)  |11111111|11111111|11111110|0011     */    {0xfffffe3,28},
+        /*    (  4)  |11111111|11111111|11111110|0100     */    {0xfffffe4,28},
+        /*    (  5)  |11111111|11111111|11111110|0101     */    {0xfffffe5,28},
+        /*    (  6)  |11111111|11111111|11111110|0110     */    {0xfffffe6,28},
+        /*    (  7)  |11111111|11111111|11111110|0111     */    {0xfffffe7,28},
+        /*    (  8)  |11111111|11111111|11111110|1000     */    {0xfffffe8,28},
+        /*    (  9)  |11111111|11111111|11101010          */     {0xffffea,24},
+        /*    ( 10)  |11111111|11111111|11111111|111100   */   {0x3ffffffc,30},
+        /*    ( 11)  |11111111|11111111|11111110|1001     */    {0xfffffe9,28},
+        /*    ( 12)  |11111111|11111111|11111110|1010     */    {0xfffffea,28},
+        /*    ( 13)  |11111111|11111111|11111111|111101   */   {0x3ffffffd,30},
+        /*    ( 14)  |11111111|11111111|11111110|1011     */    {0xfffffeb,28},
+        /*    ( 15)  |11111111|11111111|11111110|1100     */    {0xfffffec,28},
+        /*    ( 16)  |11111111|11111111|11111110|1101     */    {0xfffffed,28},
+        /*    ( 17)  |11111111|11111111|11111110|1110     */    {0xfffffee,28},
+        /*    ( 18)  |11111111|11111111|11111110|1111     */    {0xfffffef,28},
+        /*    ( 19)  |11111111|11111111|11111111|0000     */    {0xffffff0,28},
+        /*    ( 20)  |11111111|11111111|11111111|0001     */    {0xffffff1,28},
+        /*    ( 21)  |11111111|11111111|11111111|0010     */    {0xffffff2,28},
+        /*    ( 22)  |11111111|11111111|11111111|111110   */   {0x3ffffffe,30},
+        /*    ( 23)  |11111111|11111111|11111111|0011     */    {0xffffff3,28},
+        /*    ( 24)  |11111111|11111111|11111111|0100     */    {0xffffff4,28},
+        /*    ( 25)  |11111111|11111111|11111111|0101     */    {0xffffff5,28},
+        /*    ( 26)  |11111111|11111111|11111111|0110     */    {0xffffff6,28},
+        /*    ( 27)  |11111111|11111111|11111111|0111     */    {0xffffff7,28},
+        /*    ( 28)  |11111111|11111111|11111111|1000     */    {0xffffff8,28},
+        /*    ( 29)  |11111111|11111111|11111111|1001     */    {0xffffff9,28},
+        /*    ( 30)  |11111111|11111111|11111111|1010     */    {0xffffffa,28},
+        /*    ( 31)  |11111111|11111111|11111111|1011     */    {0xffffffb,28},
+        /*' ' ( 32)  |010100                              */         {0x14, 6},
+        /*'!' ( 33)  |11111110|00                         */        {0x3f8,10},
+        /*'"' ( 34)  |11111110|01                         */        {0x3f9,10},
+        /*'#' ( 35)  |11111111|1010                       */        {0xffa,12},
+        /*'$' ( 36)  |11111111|11001                      */       {0x1ff9,13},
+        /*'%' ( 37)  |010101                              */         {0x15, 6},
+        /*'&' ( 38)  |11111000                            */         {0xf8, 8},
+        /*''' ( 39)  |11111111|010                        */        {0x7fa,11},
+        /*'(' ( 40)  |11111110|10                         */        {0x3fa,10},
+        /*')' ( 41)  |11111110|11                         */        {0x3fb,10},
+        /*'*' ( 42)  |11111001                            */         {0xf9, 8},
+        /*'+' ( 43)  |11111111|011                        */        {0x7fb,11},
+        /*',' ( 44)  |11111010                            */         {0xfa, 8},
+        /*'-' ( 45)  |010110                              */         {0x16, 6},
+        /*'.' ( 46)  |010111                              */         {0x17, 6},
+        /*'/' ( 47)  |011000                              */         {0x18, 6},
+        /*'0' ( 48)  |00000                               */          {0x0, 5},
+        /*'1' ( 49)  |00001                               */          {0x1, 5},
+        /*'2' ( 50)  |00010                               */          {0x2, 5},
+        /*'3' ( 51)  |011001                              */         {0x19, 6},
+        /*'4' ( 52)  |011010                              */         {0x1a, 6},
+        /*'5' ( 53)  |011011                              */         {0x1b, 6},
+        /*'6' ( 54)  |011100                              */         {0x1c, 6},
+        /*'7' ( 55)  |011101                              */         {0x1d, 6},
+        /*'8' ( 56)  |011110                              */         {0x1e, 6},
+        /*'9' ( 57)  |011111                              */         {0x1f, 6},
+        /*':' ( 58)  |1011100                             */         {0x5c, 7},
+        /*';' ( 59)  |11111011                            */         {0xfb, 8},
+        /*'<' ( 60)  |11111111|1111100                    */       {0x7ffc,15},
+        /*'=' ( 61)  |100000                              */         {0x20, 6},
+        /*'>' ( 62)  |11111111|1011                       */        {0xffb,12},
+        /*'?' ( 63)  |11111111|00                         */        {0x3fc,10},
+        /*'@' ( 64)  |11111111|11010                      */       {0x1ffa,13},
+        /*'A' ( 65)  |100001                              */         {0x21, 6},
+        /*'B' ( 66)  |1011101                             */         {0x5d, 7},
+        /*'C' ( 67)  |1011110                             */         {0x5e, 7},
+        /*'D' ( 68)  |1011111                             */         {0x5f, 7},
+        /*'E' ( 69)  |1100000                             */         {0x60, 7},
+        /*'F' ( 70)  |1100001                             */         {0x61, 7},
+        /*'G' ( 71)  |1100010                             */         {0x62, 7},
+        /*'H' ( 72)  |1100011                             */         {0x63, 7},
+        /*'I' ( 73)  |1100100                             */         {0x64, 7},
+        /*'J' ( 74)  |1100101                             */         {0x65, 7},
+        /*'K' ( 75)  |1100110                             */         {0x66, 7},
+        /*'L' ( 76)  |1100111                             */         {0x67, 7},
+        /*'M' ( 77)  |1101000                             */         {0x68, 7},
+        /*'N' ( 78)  |1101001                             */         {0x69, 7},
+        /*'O' ( 79)  |1101010                             */         {0x6a, 7},
+        /*'P' ( 80)  |1101011                             */         {0x6b, 7},
+        /*'Q' ( 81)  |1101100                             */         {0x6c, 7},
+        /*'R' ( 82)  |1101101                             */         {0x6d, 7},
+        /*'S' ( 83)  |1101110                             */         {0x6e, 7},
+        /*'T' ( 84)  |1101111                             */         {0x6f, 7},
+        /*'U' ( 85)  |1110000                             */         {0x70, 7},
+        /*'V' ( 86)  |1110001                             */         {0x71, 7},
+        /*'W' ( 87)  |1110010                             */         {0x72, 7},
+        /*'X' ( 88)  |11111100                            */         {0xfc, 8},
+        /*'Y' ( 89)  |1110011                             */         {0x73, 7},
+        /*'Z' ( 90)  |11111101                            */         {0xfd, 8},
+        /*'[' ( 91)  |11111111|11011                      */       {0x1ffb,13},
+        /*'\' ( 92)  |11111111|11111110|000               */      {0x7fff0,19},
+        /*']' ( 93)  |11111111|11100                      */       {0x1ffc,13},
+        /*'^' ( 94)  |11111111|111100                     */       {0x3ffc,14},
+        /*'_' ( 95)  |100010                              */         {0x22, 6},
+        /*'`' ( 96)  |11111111|1111101                    */       {0x7ffd,15},
+        /*'a' ( 97)  |00011                               */          {0x3, 5},
+        /*'b' ( 98)  |100011                              */         {0x23, 6},
+        /*'c' ( 99)  |00100                               */          {0x4, 5},
+        /*'d' (100)  |100100                              */         {0x24, 6},
+        /*'e' (101)  |00101                               */          {0x5, 5},
+        /*'f' (102)  |100101                              */         {0x25, 6},
+        /*'g' (103)  |100110                              */         {0x26, 6},
+        /*'h' (104)  |100111                              */         {0x27, 6},
+        /*'i' (105)  |00110                               */          {0x6, 5},
+        /*'j' (106)  |1110100                             */         {0x74, 7},
+        /*'k' (107)  |1110101                             */         {0x75, 7},
+        /*'l' (108)  |101000                              */         {0x28, 6},
+        /*'m' (109)  |101001                              */         {0x29, 6},
+        /*'n' (110)  |101010                              */         {0x2a, 6},
+        /*'o' (111)  |00111                               */          {0x7, 5},
+        /*'p' (112)  |101011                              */         {0x2b, 6},
+        /*'q' (113)  |1110110                             */         {0x76, 7},
+        /*'r' (114)  |101100                              */         {0x2c, 6},
+        /*'s' (115)  |01000                               */          {0x8, 5},
+        /*'t' (116)  |01001                               */          {0x9, 5},
+        /*'u' (117)  |101101                              */         {0x2d, 6},
+        /*'v' (118)  |1110111                             */         {0x77, 7},
+        /*'w' (119)  |1111000                             */         {0x78, 7},
+        /*'x' (120)  |1111001                             */         {0x79, 7},
+        /*'y' (121)  |1111010                             */         {0x7a, 7},
+        /*'z' (122)  |1111011                             */         {0x7b, 7},
+        /*'{' (123)  |11111111|1111110                    */       {0x7ffe,15},
+        /*'|' (124)  |11111111|100                        */        {0x7fc,11},
+        /*'}' (125)  |11111111|111101                     */       {0x3ffd,14},
+        /*'~' (126)  |11111111|11101                      */       {0x1ffd,13},
+        /*    (127)  |11111111|11111111|11111111|1100     */    {0xffffffc,28},
+        /*    (128)  |11111111|11111110|0110              */      {0xfffe6,20},
+        /*    (129)  |11111111|11111111|010010            */     {0x3fffd2,22},
+        /*    (130)  |11111111|11111110|0111              */      {0xfffe7,20},
+        /*    (131)  |11111111|11111110|1000              */      {0xfffe8,20},
+        /*    (132)  |11111111|11111111|010011            */     {0x3fffd3,22},
+        /*    (133)  |11111111|11111111|010100            */     {0x3fffd4,22},
+        /*    (134)  |11111111|11111111|010101            */     {0x3fffd5,22},
+        /*    (135)  |11111111|11111111|1011001           */     {0x7fffd9,23},
+        /*    (136)  |11111111|11111111|010110            */     {0x3fffd6,22},
+        /*    (137)  |11111111|11111111|1011010           */     {0x7fffda,23},
+        /*    (138)  |11111111|11111111|1011011           */     {0x7fffdb,23},
+        /*    (139)  |11111111|11111111|1011100           */     {0x7fffdc,23},
+        /*    (140)  |11111111|11111111|1011101           */     {0x7fffdd,23},
+        /*    (141)  |11111111|11111111|1011110           */     {0x7fffde,23},
+        /*    (142)  |11111111|11111111|11101011          */     {0xffffeb,24},
+        /*    (143)  |11111111|11111111|1011111           */     {0x7fffdf,23},
+        /*    (144)  |11111111|11111111|11101100          */     {0xffffec,24},
+        /*    (145)  |11111111|11111111|11101101          */     {0xffffed,24},
+        /*    (146)  |11111111|11111111|010111            */     {0x3fffd7,22},
+        /*    (147)  |11111111|11111111|1100000           */     {0x7fffe0,23},
+        /*    (148)  |11111111|11111111|11101110          */     {0xffffee,24},
+        /*    (149)  |11111111|11111111|1100001           */     {0x7fffe1,23},
+        /*    (150)  |11111111|11111111|1100010           */     {0x7fffe2,23},
+        /*    (151)  |11111111|11111111|1100011           */     {0x7fffe3,23},
+        /*    (152)  |11111111|11111111|1100100           */     {0x7fffe4,23},
+        /*    (153)  |11111111|11111110|11100             */     {0x1fffdc,21},
+        /*    (154)  |11111111|11111111|011000            */     {0x3fffd8,22},
+        /*    (155)  |11111111|11111111|1100101           */     {0x7fffe5,23},
+        /*    (156)  |11111111|11111111|011001            */     {0x3fffd9,22},
+        /*    (157)  |11111111|11111111|1100110           */     {0x7fffe6,23},
+        /*    (158)  |11111111|11111111|1100111           */     {0x7fffe7,23},
+        /*    (159)  |11111111|11111111|11101111          */     {0xffffef,24},
+        /*    (160)  |11111111|11111111|011010            */     {0x3fffda,22},
+        /*    (161)  |11111111|11111110|11101             */     {0x1fffdd,21},
+        /*    (162)  |11111111|11111110|1001              */      {0xfffe9,20},
+        /*    (163)  |11111111|11111111|011011            */     {0x3fffdb,22},
+        /*    (164)  |11111111|11111111|011100            */     {0x3fffdc,22},
+        /*    (165)  |11111111|11111111|1101000           */     {0x7fffe8,23},
+        /*    (166)  |11111111|11111111|1101001           */     {0x7fffe9,23},
+        /*    (167)  |11111111|11111110|11110             */     {0x1fffde,21},
+        /*    (168)  |11111111|11111111|1101010           */     {0x7fffea,23},
+        /*    (169)  |11111111|11111111|011101            */     {0x3fffdd,22},
+        /*    (170)  |11111111|11111111|011110            */     {0x3fffde,22},
+        /*    (171)  |11111111|11111111|11110000          */     {0xfffff0,24},
+        /*    (172)  |11111111|11111110|11111             */     {0x1fffdf,21},
+        /*    (173)  |11111111|11111111|011111            */     {0x3fffdf,22},
+        /*    (174)  |11111111|11111111|1101011           */     {0x7fffeb,23},
+        /*    (175)  |11111111|11111111|1101100           */     {0x7fffec,23},
+        /*    (176)  |11111111|11111111|00000             */     {0x1fffe0,21},
+        /*    (177)  |11111111|11111111|00001             */     {0x1fffe1,21},
+        /*    (178)  |11111111|11111111|100000            */     {0x3fffe0,22},
+        /*    (179)  |11111111|11111111|00010             */     {0x1fffe2,21},
+        /*    (180)  |11111111|11111111|1101101           */     {0x7fffed,23},
+        /*    (181)  |11111111|11111111|100001            */     {0x3fffe1,22},
+        /*    (182)  |11111111|11111111|1101110           */     {0x7fffee,23},
+        /*    (183)  |11111111|11111111|1101111           */     {0x7fffef,23},
+        /*    (184)  |11111111|11111110|1010              */      {0xfffea,20},
+        /*    (185)  |11111111|11111111|100010            */     {0x3fffe2,22},
+        /*    (186)  |11111111|11111111|100011            */     {0x3fffe3,22},
+        /*    (187)  |11111111|11111111|100100            */     {0x3fffe4,22},
+        /*    (188)  |11111111|11111111|1110000           */     {0x7ffff0,23},
+        /*    (189)  |11111111|11111111|100101            */     {0x3fffe5,22},
+        /*    (190)  |11111111|11111111|100110            */     {0x3fffe6,22},
+        /*    (191)  |11111111|11111111|1110001           */     {0x7ffff1,23},
+        /*    (192)  |11111111|11111111|11111000|00       */    {0x3ffffe0,26},
+        /*    (193)  |11111111|11111111|11111000|01       */    {0x3ffffe1,26},
+        /*    (194)  |11111111|11111110|1011              */      {0xfffeb,20},
+        /*    (195)  |11111111|11111110|001               */      {0x7fff1,19},
+        /*    (196)  |11111111|11111111|100111            */     {0x3fffe7,22},
+        /*    (197)  |11111111|11111111|1110010           */     {0x7ffff2,23},
+        /*    (198)  |11111111|11111111|101000            */     {0x3fffe8,22},
+        /*    (199)  |11111111|11111111|11110110|0        */    {0x1ffffec,25},
+        /*    (200)  |11111111|11111111|11111000|10       */    {0x3ffffe2,26},
+        /*    (201)  |11111111|11111111|11111000|11       */    {0x3ffffe3,26},
+        /*    (202)  |11111111|11111111|11111001|00       */    {0x3ffffe4,26},
+        /*    (203)  |11111111|11111111|11111011|110      */    {0x7ffffde,27},
+        /*    (204)  |11111111|11111111|11111011|111      */    {0x7ffffdf,27},
+        /*    (205)  |11111111|11111111|11111001|01       */    {0x3ffffe5,26},
+        /*    (206)  |11111111|11111111|11110001          */     {0xfffff1,24},
+        /*    (207)  |11111111|11111111|11110110|1        */    {0x1ffffed,25},
+        /*    (208)  |11111111|11111110|010               */      {0x7fff2,19},
+        /*    (209)  |11111111|11111111|00011             */     {0x1fffe3,21},
+        /*    (210)  |11111111|11111111|11111001|10       */    {0x3ffffe6,26},
+        /*    (211)  |11111111|11111111|11111100|000      */    {0x7ffffe0,27},
+        /*    (212)  |11111111|11111111|11111100|001      */    {0x7ffffe1,27},
+        /*    (213)  |11111111|11111111|11111001|11       */    {0x3ffffe7,26},
+        /*    (214)  |11111111|11111111|11111100|010      */    {0x7ffffe2,27},
+        /*    (215)  |11111111|11111111|11110010          */     {0xfffff2,24},
+        /*    (216)  |11111111|11111111|00100             */     {0x1fffe4,21},
+        /*    (217)  |11111111|11111111|00101             */     {0x1fffe5,21},
+        /*    (218)  |11111111|11111111|11111010|00       */    {0x3ffffe8,26},
+        /*    (219)  |11111111|11111111|11111010|01       */    {0x3ffffe9,26},
+        /*    (220)  |11111111|11111111|11111111|1101     */    {0xffffffd,28},
+        /*    (221)  |11111111|11111111|11111100|011      */    {0x7ffffe3,27},
+        /*    (222)  |11111111|11111111|11111100|100      */    {0x7ffffe4,27},
+        /*    (223)  |11111111|11111111|11111100|101      */    {0x7ffffe5,27},
+        /*    (224)  |11111111|11111110|1100              */      {0xfffec,20},
+        /*    (225)  |11111111|11111111|11110011          */     {0xfffff3,24},
+        /*    (226)  |11111111|11111110|1101              */      {0xfffed,20},
+        /*    (227)  |11111111|11111111|00110             */     {0x1fffe6,21},
+        /*    (228)  |11111111|11111111|101001            */     {0x3fffe9,22},
+        /*    (229)  |11111111|11111111|00111             */     {0x1fffe7,21},
+        /*    (230)  |11111111|11111111|01000             */     {0x1fffe8,21},
+        /*    (231)  |11111111|11111111|1110011           */     {0x7ffff3,23},
+        /*    (232)  |11111111|11111111|101010            */     {0x3fffea,22},
+        /*    (233)  |11111111|11111111|101011            */     {0x3fffeb,22},
+        /*    (234)  |11111111|11111111|11110111|0        */    {0x1ffffee,25},
+        /*    (235)  |11111111|11111111|11110111|1        */    {0x1ffffef,25},
+        /*    (236)  |11111111|11111111|11110100          */     {0xfffff4,24},
+        /*    (237)  |11111111|11111111|11110101          */     {0xfffff5,24},
+        /*    (238)  |11111111|11111111|11111010|10       */    {0x3ffffea,26},
+        /*    (239)  |11111111|11111111|1110100           */     {0x7ffff4,23},
+        /*    (240)  |11111111|11111111|11111010|11       */    {0x3ffffeb,26},
+        /*    (241)  |11111111|11111111|11111100|110      */    {0x7ffffe6,27},
+        /*    (242)  |11111111|11111111|11111011|00       */    {0x3ffffec,26},
+        /*    (243)  |11111111|11111111|11111011|01       */    {0x3ffffed,26},
+        /*    (244)  |11111111|11111111|11111100|111      */    {0x7ffffe7,27},
+        /*    (245)  |11111111|11111111|11111101|000      */    {0x7ffffe8,27},
+        /*    (246)  |11111111|11111111|11111101|001      */    {0x7ffffe9,27},
+        /*    (247)  |11111111|11111111|11111101|010      */    {0x7ffffea,27},
+        /*    (248)  |11111111|11111111|11111101|011      */    {0x7ffffeb,27},
+        /*    (249)  |11111111|11111111|11111111|1110     */    {0xffffffe,28},
+        /*    (250)  |11111111|11111111|11111101|100      */    {0x7ffffec,27},
+        /*    (251)  |11111111|11111111|11111101|101      */    {0x7ffffed,27},
+        /*    (252)  |11111111|11111111|11111101|110      */    {0x7ffffee,27},
+        /*    (253)  |11111111|11111111|11111101|111      */    {0x7ffffef,27},
+        /*    (254)  |11111111|11111111|11111110|000      */    {0x7fffff0,27},
+        /*    (255)  |11111111|11111111|11111011|10       */    {0x3ffffee,26},
+        /*EOS (256)  |11111111|11111111|11111111|111111   */   {0x3fffffff,30},
+    };
+
+    static final int[][] LCCODES = new int[CODES.length][];
+    
+    // Huffman decode tree stored in a flattened char array for good 
+    // locality of reference.
+    static final char[] tree;
+    static final char[] rowsym;
+    static final byte[] rowbits;
+
+    // Build the Huffman lookup tree and LC TABLE
+    static 
+    {
+        System.arraycopy(CODES,0,LCCODES,0,CODES.length);
+        for (int i='A';i<='Z';i++)
+            LCCODES[i]=LCCODES['a'+i-'A'];
+        
+        int r=0;
+        for (int i=0;i<CODES.length;i++)
+            r+=(CODES[i][1]+7)/8;
+        tree=new char[r*256];
+        rowsym=new char[r];
+        rowbits=new byte[r];
+
+        r=0;
+        for (int sym = 0; sym < CODES.length; sym++) 
+        {
+            int code = CODES[sym][0];
+            int len = CODES[sym][1];
+
+            int current = 0;
+
+            while (len > 8) 
+            {
+                len -= 8;
+                int i = ((code >>> len) & 0xFF);
+
+                int t=current*256+i;
+                current = tree[t];
+                if (current == 0)
+                {
+                    tree[t] = (char)++r;
+                    current=r;
+                }
+            }
+
+            int terminal = ++r;
+            rowsym[r]=(char)sym;
+            int b = len & 0x07;
+            int terminalBits = b == 0?8:b;
+
+            rowbits[r]=(byte)terminalBits;
+            int shift = 8 - len;
+            int start = current*256 + ((code << shift) & 0xFF);
+            int end = start + (1<<shift);
+            for (int i = start; i < end; i++)
+                tree[i]=(char)terminal;
+        }
+    }
+
+    public static String decode(ByteBuffer buffer)
+    {  
+        return decode(buffer,buffer.remaining());
+    }
+
+    public static String decode(ByteBuffer buffer,int length)
+    {        
+        StringBuilder out = new StringBuilder(length*2);
+        int node = 0;
+        int current = 0;
+        int bits = 0;
+        
+        byte[] array = buffer.array();
+        int position=buffer.position();
+        int start=buffer.arrayOffset()+position;
+        int end=start+length;
+        buffer.position(position+length);
+        
+        for (int i=start; i<end; i++)
+        {
+            int b = array[i]&0xFF;
+            current = (current << 8) | b;
+            bits += 8;
+            while (bits >= 8) 
+            {
+                int c = (current >>> (bits - 8)) & 0xFF;
+                node = tree[node*256+c];
+                if (rowbits[node]!=0) 
+                {
+                    // terminal node
+                    out.append(rowsym[node]);
+                    bits -= rowbits[node];
+                    node = 0;
+                } 
+                else 
+                {
+                    // non-terminal node
+                    bits -= 8;
+                }
+            }
+        }
+
+        while (bits > 0) 
+        {
+            int c = (current << (8 - bits)) & 0xFF;
+            node = tree[node*256+c];
+            if (rowbits[node]==0 || rowbits[node] > bits) 
+                break;
+            
+            if (rowbits[node]==0)
+                throw new IllegalStateException();
+            
+            out.append(rowsym[node]);
+            bits -= rowbits[node];
+            node = 0;
+        }
+
+        return out.toString();
+    }
+
+    public static int octetsNeeded(String s)
+    {   
+        return octetsNeeded(CODES,s);
+    }
+    
+    public static void encode(ByteBuffer buffer,String s)
+    {
+        encode(CODES,buffer,s);
+    }
+    
+    public static int octetsNeededLC(String s)
+    {
+        return octetsNeeded(LCCODES,s);
+    }
+
+    public static void encodeLC(ByteBuffer buffer, String s)
+    {
+        encode(LCCODES,buffer,s);
+    }
+    
+    private static int octetsNeeded(final int[][] table,String s)
+    {   
+        int needed=0;
+        int len = s.length();
+        for (int i=0;i<len;i++)
+        {
+            char c=s.charAt(i);
+            if (c>=128 || c<' ')
+                throw new IllegalArgumentException();
+            needed += table[c][1];
+        }
+
+        return (needed+7) / 8;
+    }
+
+    private static void encode(final int[][] table,ByteBuffer buffer,String s)
+    {
+        long current = 0;
+        int n = 0;
+
+        byte[] array = buffer.array();
+        int p=buffer.arrayOffset()+buffer.position();
+
+        int len = s.length();
+        for (int i=0;i<len;i++)
+        {
+            char c=s.charAt(i);
+            if (c>=128 || c<' ')
+                throw new IllegalArgumentException();
+            int code = table[c][0];
+            int bits = table[c][1];
+
+            current <<= bits;
+            current |= code;
+            n += bits;
+
+            while (n >= 8) 
+            {
+                n -= 8;
+                array[p++]=(byte)(current >> n);
+            }
+        }
+
+        if (n > 0) 
+        {
+          current <<= (8 - n);
+          current |= (0xFF >>> n); 
+          array[p++]=(byte)current;
+        }
+        
+        buffer.position(p-buffer.arrayOffset());
+    }
+
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java
new file mode 100644
index 0000000..1db32e3
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java
@@ -0,0 +1,184 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+
+public class MetaDataBuilder
+{ 
+    private final int _maxSize;
+    private int _size;
+    private int _status;
+    private String _method;
+    private HttpScheme _scheme;
+    private HostPortHttpField _authority;
+    private String _path;  
+    private long _contentLength=Long.MIN_VALUE;
+
+    private HttpFields _fields = new HttpFields(10);
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
+     */
+    MetaDataBuilder(int maxHeadersSize)
+    {
+        _maxSize=maxHeadersSize;
+    }
+    
+    /** Get the maxSize.
+     * @return the maxSize
+     */
+    public int getMaxSize()
+    {
+        return _maxSize;
+    }
+
+    /** Get the size.
+     * @return the current size in bytes
+     */
+    public int getSize()
+    {
+        return _size;
+    }
+
+    public void emit(HttpField field)
+    {        
+        int field_size = field.getName().length()+field.getValue().length();
+        _size+=field_size;
+        if (_size>_maxSize)
+            throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize);
+        
+        if (field instanceof StaticTableHttpField)
+        {
+            StaticTableHttpField value = (StaticTableHttpField)field;
+            switch(field.getHeader())
+            {
+                case C_STATUS:
+                    _status=(Integer)value.getStaticValue();
+                    break;
+                    
+                case C_METHOD:
+                    _method=field.getValue();
+                    break;
+
+                case C_SCHEME:
+                    _scheme = (HttpScheme)value.getStaticValue();
+                    break;
+                    
+                default:
+                    throw new IllegalArgumentException(field.getName());
+            }
+        }
+        else if (field.getHeader()!=null)
+        {
+            switch(field.getHeader())
+            {
+                case C_STATUS:
+                    _status=field.getIntValue();
+                    break;
+
+                case C_METHOD:
+                    _method=field.getValue();
+                    break;
+
+                case C_SCHEME:
+                    _scheme = HttpScheme.CACHE.get(field.getValue());
+                    break;
+
+                case C_AUTHORITY:
+                    _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
+                    break;
+
+                case HOST:
+                    // :authority fields must come first.  If we have one, ignore the host header as far as authority goes.
+                    if (_authority==null)
+                        _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
+                    _fields.add(field);
+                    break;
+
+                case C_PATH:
+                    _path = field.getValue();
+                    break;
+
+                case CONTENT_LENGTH:
+                    _contentLength = field.getLongValue();
+                    _fields.add(field);
+                    break;
+                    
+                default:
+                    if (field.getName().charAt(0)!=':')
+                        _fields.add(field);
+            }
+        }
+        else
+        {
+            if (field.getName().charAt(0)!=':')
+                _fields.add(field);
+        }
+    }
+    
+    public MetaData build()
+    {
+        try
+        {
+            HttpFields fields = _fields;
+            _fields = new HttpFields(Math.max(10,fields.size()+5));
+            
+            if (_method!=null)
+                return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength);
+            if (_status!=0)
+                return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength);
+            return new MetaData(HttpVersion.HTTP_2,fields,_contentLength);
+        }
+        finally
+        {
+            _status=0;
+            _method=null;
+            _scheme=null;
+            _authority=null;
+            _path=null;
+            _size=0;
+            _contentLength=Long.MIN_VALUE;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Check that the max size will not be exceeded.
+     * @param length the length
+     * @param huffman the huffman name
+     */
+    public void checkSize(int length, boolean huffman)
+    {
+        // Apply a huffman fudge factor
+        if (huffman)
+            length=(length*4)/3;
+        if ((_size+length)>_maxSize)
+            throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize);
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java
new file mode 100644
index 0000000..5e99117
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java
@@ -0,0 +1,151 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+
+public class NBitInteger
+{
+    public static int octectsNeeded(int n,int i)
+    {
+        if (n==8)
+        {
+            int nbits = 0xFF;
+            i=i-nbits;
+            if (i<0)
+                return 1;
+            if (i==0)
+                return 2;
+            int lz=Integer.numberOfLeadingZeros(i);
+            int log=32-lz;
+            return 1+(log+6)/7;
+        }
+        
+        int nbits = 0xFF >>> (8 - n);
+        i=i-nbits;
+        if (i<0)
+            return 0;
+        if (i==0)
+            return 1;
+        int lz=Integer.numberOfLeadingZeros(i);
+        int log=32-lz;
+        return (log+6)/7;
+    }
+    
+    public static void encode(ByteBuffer buf, int n, int i)
+    {
+        if (n==8)
+        {
+            if (i < 0xFF)
+            {
+                buf.put((byte)i);
+            }
+            else
+            {
+                buf.put((byte)0xFF);
+
+                int length = i - 0xFF;
+                while (true)
+                {
+                    if ((length & ~0x7F) == 0)
+                    {
+                        buf.put((byte)length);
+                        return;
+                    }
+                    else
+                    {
+                        buf.put((byte)((length & 0x7F) | 0x80));
+                        length >>>= 7;
+                    }
+                }
+            }
+        }
+        else
+        {
+            int p=buf.position()-1;
+            int bits = 0xFF >>> (8 - n);
+
+            if (i < bits)
+            {
+                buf.put(p,(byte)((buf.get(p)&~bits)|i));
+            }
+            else
+            {
+                buf.put(p,(byte)(buf.get(p)|bits));
+
+                int length = i - bits;
+                while (true)
+                {
+                    if ((length & ~0x7F) == 0)
+                    {
+                        buf.put((byte)length);
+                        return;
+                    }
+                    else
+                    {
+                        buf.put((byte)((length & 0x7F) | 0x80));
+                        length >>>= 7;
+                    }
+                }
+            }
+        }
+    }
+
+    public static int decode(ByteBuffer buffer, int n)
+    {
+        if (n==8)
+        {
+            int nbits = 0xFF;
+
+            int i=buffer.get()&0xff;
+            
+            if (i == nbits)
+            {       
+                int m=1;
+                int b;
+                do
+                {
+                    b = 0xff&buffer.get();
+                    i = i + (b&127) * m;
+                    m = m*128;
+                }
+                while ((b&128) == 128);
+            }
+            return i;
+        }
+        
+        int nbits = 0xFF >>> (8 - n);
+
+        int i=buffer.get(buffer.position()-1)&nbits;
+        
+        if (i == nbits)
+        {       
+            int m=1;
+            int b;
+            do
+            {
+                b = 0xff&buffer.get();
+                i = i + (b&127) * m;
+                m = m*128;
+            }
+            while ((b&128) == 128);
+        }
+        return i;
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java
new file mode 100644
index 0000000..275ab53
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/StaticTableHttpField.java
@@ -0,0 +1,61 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+
+/* ------------------------------------------------------------ */
+public class StaticTableHttpField extends HttpField
+{
+    private final Object _value;
+
+    public StaticTableHttpField(HttpHeader header, String name, String valueString, Object value)
+    {
+        super(header,name,valueString);
+        if (value==null)
+            throw new IllegalArgumentException();
+        _value=value;
+    }
+    
+    public StaticTableHttpField(HttpHeader header,String valueString, Object value)
+    {
+        this (header,header.asString(),valueString, value);
+    }
+    
+    public StaticTableHttpField(String name, String valueString, Object value)
+    {
+        super(name,valueString);
+        if (value==null)
+            throw new IllegalArgumentException();
+        _value=value;
+    }
+
+    public Object getStaticValue()
+    {
+        return _value;
+    }
+    
+    @Override
+    public String toString()
+    {
+        return super.toString()+"(evaluated)";
+    }
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder b/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder
new file mode 100644
index 0000000..4dca767
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/main/resources/META-INF/services/org.eclipse.jetty.http.HttpFieldPreEncoder
@@ -0,0 +1 @@
+org.eclipse.jetty.http2.hpack.HpackFieldPreEncoder
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java
new file mode 100644
index 0000000..1d4b38c
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java
@@ -0,0 +1,455 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class HpackContextTest
+{
+
+    @Test
+    public void testStaticName()
+    {
+        HpackContext ctx = new HpackContext(4096);
+        Entry entry=ctx.get(":method");
+        assertEquals(":method",entry.getHttpField().getName());
+        Assert.assertTrue(entry.isStatic());
+        Assert.assertThat(entry.toString(),Matchers.startsWith("{S,2,:method: "));
+    }
+    
+    @Test
+    public void testEmptyAdd()
+    {
+        HpackContext ctx = new HpackContext(0);
+        HttpField field = new HttpField("foo","bar");
+        Assert.assertNull(ctx.add(field));
+    }
+    
+    @Test
+    public void testTooBigAdd()
+    {
+        HpackContext ctx = new HpackContext(37);
+        HttpField field = new HttpField("foo","bar");
+        Assert.assertNull(ctx.add(field));
+    }
+    
+    @Test
+    public void testJustRight()
+    {
+        HpackContext ctx = new HpackContext(38);
+        HttpField field = new HttpField("foo","bar");
+        Entry entry=ctx.add(field);
+        Assert.assertNotNull(entry);
+        Assert.assertThat(entry.toString(),Matchers.startsWith("{D,0,foo: bar,"));
+    }
+    
+    @Test
+    public void testEvictOne()
+    {
+        HpackContext ctx = new HpackContext(38);
+        HttpField field0 = new HttpField("foo","bar");
+        
+        assertEquals(field0,ctx.add(field0).getHttpField());
+        assertEquals(field0,ctx.get("foo").getHttpField());
+        
+        HttpField field1 = new HttpField("xxx","yyy");
+        assertEquals(field1,ctx.add(field1).getHttpField());
+
+        assertNull(ctx.get(field0));
+        assertNull(ctx.get("foo"));
+        assertEquals(field1,ctx.get(field1).getHttpField());
+        assertEquals(field1,ctx.get("xxx").getHttpField());
+        
+    }
+
+    @Test
+    public void testEvictNames()
+    {
+        HpackContext ctx = new HpackContext(38*2);
+        HttpField[] field = 
+        {
+           new HttpField("name","v0"),
+           new HttpField("name","v1"),
+           new HttpField("name","v2"),
+           new HttpField("name","v3"),
+           new HttpField("name","v4"),
+           new HttpField("name","v5"),
+        };
+        
+        Entry[] entry = new Entry[field.length];
+        
+        // Add 2 name entries to fill table
+        for (int i=0;i<=1;i++)
+            entry[i]=ctx.add(field[i]);
+        
+        // check there is a name reference and it is the most recent added
+        assertEquals(entry[1],ctx.get("name"));
+
+        // Add 1 other entry to table and evict 1
+        ctx.add(new HttpField("xxx","yyy"));
+        
+        // check the name reference has been not been evicted
+        assertEquals(entry[1],ctx.get("name"));
+        
+        // Add 1 other entry to table and evict 1
+        ctx.add(new HttpField("foo","bar"));
+        
+        // name is evicted
+        assertNull(ctx.get("name"));
+    }
+    @Test
+    public void testGetAddStatic()
+    {
+        HpackContext ctx = new HpackContext(4096);
+
+        // Look for the field.  Should find static version.
+        HttpField methodGet = new HttpField(":method","GET");
+        assertEquals(methodGet,ctx.get(methodGet).getHttpField());
+        assertTrue(ctx.get(methodGet).isStatic());
+        
+        // Add static version to dynamic table
+        Entry e0=ctx.add(ctx.get(methodGet).getHttpField());
+        
+        // Look again and should see dynamic version
+        assertEquals(methodGet,ctx.get(methodGet).getHttpField());
+        assertFalse(methodGet==ctx.get(methodGet).getHttpField());
+        assertFalse(ctx.get(methodGet).isStatic());
+        
+        // Duplicates allows
+        Entry e1=ctx.add(ctx.get(methodGet).getHttpField());
+        
+        // Look again and should see dynamic version
+        assertEquals(methodGet,ctx.get(methodGet).getHttpField());
+        assertFalse(methodGet==ctx.get(methodGet).getHttpField());
+        assertFalse(ctx.get(methodGet).isStatic());
+        assertFalse(e0==e1);
+    }
+    
+    @Test
+    public void testGetAddStaticName()
+    {
+        HpackContext ctx = new HpackContext(4096);
+        HttpField methodOther = new HttpField(":method","OTHER");
+
+        // Look for the field by name.  Should find static version.
+        assertEquals(":method",ctx.get(":method").getHttpField().getName());
+        assertTrue(ctx.get(":method").isStatic());
+        
+        // Add dynamic entry with method
+        ctx.add(methodOther);
+        
+        // Look for the field by name.  Should find static version.
+        assertEquals(":method",ctx.get(":method").getHttpField().getName());
+        assertTrue(ctx.get(":method").isStatic()); 
+    }
+
+    @Test
+    public void testIndexes()
+    {
+        // Only enough space for 5 entries
+        HpackContext ctx = new HpackContext(38*5);
+        
+        HttpField methodPost = new HttpField(":method","POST");
+        HttpField[] field = 
+        {
+           new HttpField("fo0","b0r"),
+           new HttpField("fo1","b1r"),
+           new HttpField("fo2","b2r"),
+           new HttpField("fo3","b3r"),
+           new HttpField("fo4","b4r"),
+           new HttpField("fo5","b5r"),
+           new HttpField("fo6","b6r"),
+           new HttpField("fo7","b7r"),
+           new HttpField("fo8","b8r"),
+           new HttpField("fo9","b9r"),
+           new HttpField("foA","bAr"),
+        };
+        
+        Entry[] entry = new Entry[100];
+        
+        // Lookup the index of a static field
+        assertEquals(0,ctx.size());
+        assertEquals(":authority",ctx.get(1).getHttpField().getName());
+        assertEquals(3,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61).getHttpField().getName());
+        assertEquals(null,ctx.get(62));
+        
+        // Add a single entry  
+        entry[0]=ctx.add(field[0]);
+        
+        // Check new entry is 62 
+        assertEquals(1,ctx.size());
+        assertEquals(62,ctx.index(entry[0]));
+        assertEquals(entry[0],ctx.get(62));
+        
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+0+ctx.size()));
+        
+
+        // Add 4 more entries
+        for (int i=1;i<=4;i++)  
+            entry[i]=ctx.add(field[i]);
+
+        // Check newest entry is at 62 oldest at 66
+        assertEquals(5,ctx.size());
+        int index=66;
+        for (int i=0;i<=4;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+0+ctx.size()));
+        
+        // add 1 more entry and this should cause an eviction!
+        entry[5]=ctx.add(field[5]);
+
+        // Check newest entry is at 1 oldest at 5
+        index=66;
+        for (int i=1;i<=5;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+        // check entry 0 evicted
+        assertNull(ctx.get(field[0]));
+        assertEquals(0,ctx.index(entry[0]));
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+0+ctx.size()));
+        
+        // Add 4 more entries
+        for (int i=6;i<=9;i++)  
+            entry[i]=ctx.add(field[i]);
+        
+        // Check newest entry is at 1 oldest at 5
+        index=66;
+        for (int i=5;i<=9;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+        // check entry 0-4 evicted
+        for (int i=0;i<=4;i++) 
+        {
+            assertNull(ctx.get(field[i]));
+            assertEquals(0,ctx.index(entry[i]));
+        }
+        
+
+        // Add new entries enough so that array queue will wrap
+        for (int i=10;i<=52;i++)
+            entry[i]=ctx.add(new HttpField("n"+i,"v"+i));
+
+        index=66;
+        for (int i=48;i<=52;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+    }
+    
+
+    @Test
+    public void testResize()
+    {
+        // Only enough space for 5 entries
+        HpackContext ctx = new HpackContext(38*5);
+        HttpField methodPost = new HttpField(":method","POST");
+        
+        HttpField[] field = 
+        {
+           new HttpField("fo0","b0r"),
+           new HttpField("fo1","b1r"),
+           new HttpField("fo2","b2r"),
+           new HttpField("fo3","b3r"),
+           new HttpField("fo4","b4r"),
+           new HttpField("fo5","b5r"),
+           new HttpField("fo6","b6r"),
+           new HttpField("fo7","b7r"),
+           new HttpField("fo8","b8r"),
+           new HttpField("fo9","b9r"),
+           new HttpField("foA","bAr"),
+        };
+        Entry[] entry = new Entry[field.length];
+        
+        // Add 5 entries
+        for (int i=0;i<=4;i++)  
+            entry[i]=ctx.add(field[i]);
+        
+        assertEquals(5,ctx.size());
+        
+        // check indexes
+        int index=66;
+        for (int i=0;i<=4;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+ctx.size()));
+        
+        
+        
+        // resize so that only 2 entries may be held
+        ctx.resize(38*2);
+        assertEquals(2,ctx.size());
+        
+        // check indexes
+        index=63;
+        for (int i=3;i<=4;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+ctx.size()));
+        
+        // resize so that 6.5 entries may be held
+        ctx.resize(38*6+19);
+        assertEquals(2,ctx.size());
+
+        // check indexes
+        index=63;
+        for (int i=3;i<=4;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+ctx.size()));
+        
+
+        // Add 5 entries
+        for (int i=5;i<=9;i++)  
+            entry[i]=ctx.add(field[i]);
+        
+        assertEquals(6,ctx.size());
+
+        // check indexes
+        index=67;
+        for (int i=4;i<=9;i++)  
+        {
+            assertEquals(index,ctx.index(entry[i]));
+            assertEquals(entry[i],ctx.get(index));
+            index--;
+        }
+
+        // and statics have moved up 0
+        assertEquals(":authority",ctx.get(1+0).getHttpField().getName());
+        assertEquals(3+0,ctx.index(ctx.get(methodPost)));
+        assertEquals(methodPost,ctx.get(3+0).getHttpField());
+        assertEquals("www-authenticate",ctx.get(61+0).getHttpField().getName());
+        assertEquals(null,ctx.get(62+ctx.size()));
+        
+    }
+    
+    @Test
+    public void testStaticHuffmanValues()
+    {
+        HpackContext ctx = new HpackContext(4096);
+        for (int i=2;i<=14;i++)
+        {
+            Entry entry=ctx.get(i);
+            assertTrue(entry.isStatic());
+            
+            ByteBuffer buffer = ByteBuffer.wrap(entry.getStaticHuffmanValue());
+            int huff = 0xff&buffer.get();
+            assertTrue((0x80&huff)==0x80);
+            
+            int len = NBitInteger.decode(buffer,7);
+            
+            assertEquals(len,buffer.remaining());
+            String value = Huffman.decode(buffer);
+            
+            assertEquals(entry.getHttpField().getValue(),value);
+            
+        }
+    }
+    
+
+    
+    @Test
+    public void testNameInsensitivity()
+    {
+        HpackContext ctx = new HpackContext(4096);
+        assertEquals("content-length",ctx.get("content-length").getHttpField().getName());
+        assertEquals("content-length",ctx.get("Content-Length").getHttpField().getName());
+        assertTrue(ctx.get("Content-Length").isStatic());
+        assertTrue(ctx.get("Content-Type").isStatic());
+        
+        ctx.add(new HttpField("Wibble","Wobble"));
+        assertEquals("Wibble",ctx.get("wibble").getHttpField().getName());
+        assertEquals("Wibble",ctx.get("Wibble").getHttpField().getName());
+        
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java
new file mode 100644
index 0000000..8b40fd7
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java
@@ -0,0 +1,162 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.util.TypeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class HpackDecoderTest
+{
+    @Test
+    public void testDecodeD_3()
+    {
+        HpackDecoder decoder = new HpackDecoder(4096,8192);
+
+        // First request
+        String encoded="828684410f7777772e6578616d706c652e636f6d";
+        ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+
+        MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        assertFalse(request.iterator().hasNext());
+
+        // Second request
+        encoded="828684be58086e6f2d6361636865";
+        buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+
+        request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        Iterator<HttpField> iterator=request.iterator();
+        assertTrue(iterator.hasNext());
+        assertEquals(new HttpField("cache-control","no-cache"),iterator.next());
+        assertFalse(iterator.hasNext());
+
+        // Third request
+        encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565";
+        buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+
+        request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET",request.getMethod());
+        assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme());
+        assertEquals("/index.html",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        iterator=request.iterator();
+        assertTrue(iterator.hasNext());
+        assertEquals(new HttpField("custom-key","custom-value"),iterator.next());
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testDecodeD_4()
+    {
+        HpackDecoder decoder = new HpackDecoder(4096,8192);
+
+        // First request
+        String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff";
+        ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+
+        MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        assertFalse(request.iterator().hasNext());
+
+        // Second request
+        encoded="828684be5886a8eb10649cbf";
+        buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+
+        request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        Iterator<HttpField> iterator=request.iterator();
+        assertTrue(iterator.hasNext());
+        assertEquals(new HttpField("cache-control","no-cache"),iterator.next());
+        assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testDecodeWithArrayOffset()
+    {
+        String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
+
+        HpackDecoder decoder = new HpackDecoder(4096,8192);
+        String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d";
+        byte[] bytes = TypeUtil.fromHexString(encoded);
+        byte[] array = new byte[bytes.length + 1];
+        System.arraycopy(bytes, 0, array, 1, bytes.length);
+        ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice();
+
+        MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        assertEquals(1,request.getFields().size());
+        HttpField field = request.iterator().next();
+        assertEquals(HttpHeader.AUTHORIZATION, field.getHeader());
+        assertEquals(value, field.getValue());
+    }
+
+    @Test
+    public void testDecodeHuffmanWithArrayOffset()
+    {
+        HpackDecoder decoder = new HpackDecoder(4096,8192);
+
+        String encoded="8286418cf1e3c2e5f23a6ba0ab90f4ff84";
+        byte[] bytes = TypeUtil.fromHexString(encoded);
+        byte[] array = new byte[bytes.length + 1];
+        System.arraycopy(bytes, 0, array, 1, bytes.length);
+        ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice();
+
+        MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
+
+        assertEquals("GET", request.getMethod());
+        assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
+        assertEquals("/",request.getURI().getPath());
+        assertEquals("www.example.com",request.getURI().getHost());
+        assertFalse(request.iterator().hasNext());
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java
new file mode 100644
index 0000000..bfb8b92
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java
@@ -0,0 +1,190 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+
+import static org.junit.Assert.assertThat;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.util.BufferUtil;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class HpackEncoderTest
+{
+    @Test
+    public void testUnknownFieldsContextManagement()
+    {
+        HpackEncoder encoder = new HpackEncoder(38*5);
+        HttpFields fields = new HttpFields();
+        
+
+        HttpField[] field = 
+        {
+           new HttpField("fo0","b0r"),
+           new HttpField("fo1","b1r"),
+           new HttpField("fo2","b2r"),
+           new HttpField("fo3","b3r"),
+           new HttpField("fo4","b4r"),
+           new HttpField("fo5","b5r"),
+           new HttpField("fo6","b6r"),
+           new HttpField("fo7","b7r"),
+           new HttpField("fo8","b8r"),
+           new HttpField("fo9","b9r"),
+           new HttpField("foA","bAr"),
+        };
+        
+        // Add 4 entries
+        for (int i=0;i<=3;i++)  
+            fields.add(field[i]);
+        
+        // encode them
+        ByteBuffer buffer = BufferUtil.allocate(4096);
+        int pos = BufferUtil.flipToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,pos);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+        
+        // All are in the dynamic table
+        Assert.assertEquals(4,encoder.getHpackContext().size());
+                
+        // encode exact same fields again!
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+
+        // All are in the dynamic table
+        Assert.assertEquals(4,encoder.getHpackContext().size());
+        
+        // Add 4 more fields
+        for (int i=4;i<=7;i++)  
+            fields.add(field[i]);
+        
+        // encode
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+
+        // max dynamic table size reached
+        Assert.assertEquals(5,encoder.getHpackContext().size());
+        
+        
+        // remove some fields
+        for (int i=0;i<=7;i+=2)  
+            fields.remove(field[i].getName());
+
+        // encode
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+
+        // max dynamic table size reached
+        Assert.assertEquals(5,encoder.getHpackContext().size());
+
+
+        // remove another fields
+        fields.remove(field[1].getName());
+
+        // encode
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+
+        // max dynamic table size reached
+        Assert.assertEquals(5,encoder.getHpackContext().size());
+
+        
+        // re add the field
+
+        fields.add(field[1]);
+
+        // encode
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+
+        // max dynamic table size reached
+        Assert.assertEquals(5,encoder.getHpackContext().size());
+
+    }
+
+
+    @Test
+    public void testNeverIndexSetCookie()
+    {
+        HpackEncoder encoder = new HpackEncoder(38*5);
+        ByteBuffer buffer = BufferUtil.allocate(4096);
+        
+        HttpFields fields = new HttpFields();
+        fields.put("set-cookie","some cookie value");
+
+        // encode
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+        
+        // empty dynamic table
+        Assert.assertEquals(0,encoder.getHpackContext().size());
+        
+
+        // encode again
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // something was encoded!
+        assertThat(buffer.remaining(),Matchers.greaterThan(0));
+        
+        // empty dynamic table
+        Assert.assertEquals(0,encoder.getHpackContext().size());
+        
+    }
+    
+
+    
+
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java
new file mode 100644
index 0000000..aec0c5e
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java
@@ -0,0 +1,135 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.ajax.JSON;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class HpackPerfTest
+{
+    int _maxDynamicTableSize=4*1024;
+    int _unencodedSize;
+    int _encodedSize;
+    
+    @Before
+    public void before()
+    {
+        _unencodedSize=0;
+        _encodedSize=0;
+    }
+
+    @After
+    public void after()
+    {        
+        System.err.printf("dynamictable=%d unencoded=%d encoded=%d p=%3.1f%%%n",_maxDynamicTableSize,_unencodedSize,_encodedSize,100.0*_encodedSize/_unencodedSize);
+
+    }
+    
+    @Test
+    public void simpleTest() throws Exception
+    {
+        runStories(_maxDynamicTableSize);
+    }
+    
+    private void runStories(int maxDynamicTableSize) throws Exception
+    {
+        // Find files
+        File data = MavenTestingUtils.getTestResourceDir("data");
+        String[] files = data.list(new FilenameFilter()
+        {
+            @Override
+            public boolean accept(File dir, String name)
+            {
+                return name.startsWith("story_");
+            }
+        });
+        
+        // Parse JSON
+        Map<String,Object>[] stories = new Map[files.length];
+        int i=0;
+        for (String story : files)
+            stories[i++]=(Map<String,Object>)JSON.parse(new FileReader(new File(data,story)));
+        
+        ByteBuffer buffer = BufferUtil.allocate(256*1024);
+        
+        // Encode all the requests
+        encodeStories(buffer,stories,"request");
+
+        // clear table
+        BufferUtil.clearToFill(buffer);
+        BufferUtil.flipToFlush(buffer,0);
+        
+        // Encode all the responses
+        encodeStories(buffer,stories,"response");
+        
+    }
+    
+    private void encodeStories(ByteBuffer buffer,Map<String,Object>[] stories, String type) throws Exception
+    {
+        for (Map<String,Object> story : stories)
+        {
+            if (type.equals(story.get("context")))
+            {
+                HpackEncoder encoder = new HpackEncoder(_maxDynamicTableSize,_maxDynamicTableSize);
+                
+                // System.err.println(story);
+                Object[] cases = (Object[])story.get("cases");
+                for (Object c : cases)
+                {
+                    // System.err.println("  "+c);
+                    Object[] headers = (Object[])((Map<String,Object>)c).get("headers");
+                    // System.err.println("    "+headers);
+                    HttpFields fields = new HttpFields();
+                    for (Object header:headers)
+                    {
+                        Map<String,String> h = (Map<String,String>)header;
+                        Map.Entry<String, String> e = h.entrySet().iterator().next();
+                        fields.add(e.getKey(),e.getValue());
+                        _unencodedSize+=e.getKey().length()+e.getValue().length();
+                        
+                    }
+
+                    BufferUtil.clearToFill(buffer);
+                    encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields));
+                    BufferUtil.flipToFlush(buffer,0);
+                    _encodedSize+=buffer.remaining();
+                    
+                }
+            }
+        }
+
+    }
+    
+    
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java
new file mode 100644
index 0000000..c1b1d0d
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java
@@ -0,0 +1,207 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.DateGenerator;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http.MetaData.Response;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.util.BufferUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HpackTest
+{
+    final static HttpField ServerJetty = new PreEncodedHttpField(HttpHeader.SERVER,"jetty");
+    final static HttpField XPowerJetty = new PreEncodedHttpField(HttpHeader.X_POWERED_BY,"jetty");
+    final static HttpField Date = new PreEncodedHttpField(HttpHeader.DATE,DateGenerator.formatDate(System.currentTimeMillis()));
+    
+    @Test
+    public void encodeDecodeResponseTest()
+    {
+        HpackEncoder encoder = new HpackEncoder();
+        HpackDecoder decoder = new HpackDecoder(4096,8192);
+        ByteBuffer buffer = BufferUtil.allocate(16*1024);
+        
+        HttpFields fields0 = new HttpFields();
+        fields0.add(HttpHeader.CONTENT_TYPE,"text/html");
+        fields0.add(HttpHeader.CONTENT_LENGTH,"1024");
+        fields0.add(ServerJetty);
+        fields0.add(XPowerJetty);
+        fields0.add(Date);
+        fields0.add(HttpHeader.SET_COOKIE,"abcdefghijklmnopqrstuvwxyz");
+        fields0.add("custom-key","custom-value");
+        Response original0 = new MetaData.Response(HttpVersion.HTTP_2,200,fields0);
+        
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original0);
+        BufferUtil.flipToFlush(buffer,0);
+        Response decoded0 = (Response)decoder.decode(buffer);
+
+        assertMetadataSame(original0,decoded0);
+        
+        // Same again?
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original0);
+        BufferUtil.flipToFlush(buffer,0);
+        Response decoded0b = (Response)decoder.decode(buffer);
+
+        assertMetadataSame(original0,decoded0b);        
+
+        HttpFields fields1 = new HttpFields();
+        fields1.add(HttpHeader.CONTENT_TYPE,"text/plain");
+        fields1.add(HttpHeader.CONTENT_LENGTH,"1234");
+        fields1.add(ServerJetty);
+        fields0.add(XPowerJetty);
+        fields0.add(Date);
+        fields1.add("Custom-Key","Other-Value");
+        Response original1 = new MetaData.Response(HttpVersion.HTTP_2,200,fields1);
+
+        // Same again?
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original1);
+        BufferUtil.flipToFlush(buffer,0);
+        Response decoded1 = (Response)decoder.decode(buffer);
+
+        assertMetadataSame(original1,decoded1);
+        Assert.assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName());
+    }
+    
+    @Test
+    public void encodeDecodeTooLargeTest()
+    {
+        HpackEncoder encoder = new HpackEncoder();
+        HpackDecoder decoder = new HpackDecoder(4096,101);
+        ByteBuffer buffer = BufferUtil.allocate(16*1024);
+        
+        HttpFields fields0 = new HttpFields();
+        fields0.add("1234567890","1234567890123456789012345678901234567890");
+        fields0.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
+        MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0);
+        
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original0);
+        BufferUtil.flipToFlush(buffer,0);
+        MetaData decoded0 = (MetaData)decoder.decode(buffer);
+
+        assertMetadataSame(original0,decoded0);
+               
+        HttpFields fields1 = new HttpFields();
+        fields1.add("1234567890","1234567890123456789012345678901234567890");
+        fields1.add("Cookie","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
+        fields1.add("x","y");
+        MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1);
+
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original1);
+        BufferUtil.flipToFlush(buffer,0);
+        try
+        {
+            decoder.decode(buffer);
+            Assert.fail();
+        }
+        catch(BadMessageException e)
+        {
+            assertEquals(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,e.getCode());
+        }
+    }
+
+    @Test
+    public void evictReferencedFieldTest()
+    {
+        HpackEncoder encoder = new HpackEncoder(200,200);
+        HpackDecoder decoder = new HpackDecoder(200,1024);
+        ByteBuffer buffer = BufferUtil.allocate(16*1024);
+        
+        HttpFields fields0 = new HttpFields();
+        fields0.add("123456789012345678901234567890123456788901234567890","value");
+        fields0.add("foo","abcdeffhijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
+        MetaData original0= new MetaData(HttpVersion.HTTP_2,fields0);
+
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original0);
+        BufferUtil.flipToFlush(buffer,0);
+        MetaData decoded0 = (MetaData)decoder.decode(buffer);
+
+        assertEquals(2,encoder.getHpackContext().size());
+        assertEquals(2,decoder.getHpackContext().size());
+        assertEquals("123456789012345678901234567890123456788901234567890",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+1).getHttpField().getName());
+        assertEquals("foo",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+0).getHttpField().getName());
+        
+        assertMetadataSame(original0,decoded0);
+               
+        HttpFields fields1 = new HttpFields();
+        fields1.add("123456789012345678901234567890123456788901234567890","other_value");
+        fields1.add("x","y");
+        MetaData original1 = new MetaData(HttpVersion.HTTP_2,fields1);
+
+        BufferUtil.clearToFill(buffer);
+        encoder.encode(buffer,original1);
+        BufferUtil.flipToFlush(buffer,0);
+        MetaData decoded1 = (MetaData)decoder.decode(buffer);
+        assertMetadataSame(original1,decoded1);
+        
+        assertEquals(2,encoder.getHpackContext().size());
+        assertEquals(2,decoder.getHpackContext().size());
+        assertEquals("x",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+0).getHttpField().getName());
+        assertEquals("foo",encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length+1).getHttpField().getName());        
+    }
+    
+    private void assertMetadataSame(MetaData.Response expected, MetaData.Response actual)
+    {
+        assertThat("Response.status", actual.getStatus(), is(expected.getStatus()));
+        assertThat("Response.reason", actual.getReason(), is(expected.getReason()));
+        assertMetadataSame((MetaData)expected,(MetaData)actual);
+    }
+
+    private void assertMetadataSame(MetaData expected, MetaData actual)
+    {
+        assertThat("Metadata.contentLength",actual.getContentLength(),is(expected.getContentLength()));
+        assertThat("Metadata.version" + ".version", actual.getVersion(), is(expected.getVersion()));
+        assertHttpFieldsSame("Metadata.fields",expected.getFields(),actual.getFields());
+    }
+
+    private void assertHttpFieldsSame(String msg, HttpFields expected, HttpFields actual)
+    {
+        assertThat(msg + ".size", actual.size(), is(expected.size()));
+        
+        for (HttpField actualField : actual)
+        {
+            if ("DATE".equalsIgnoreCase(actualField.getName()))
+            {
+                // skip comparison on Date, as these values can often differ by 1 second
+                // during testing.
+                continue;
+            }
+            assertThat(msg + ".contains(" + actualField + ")",expected.contains(actualField),is(true));
+        }
+    }
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java
new file mode 100644
index 0000000..207a5e4
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java
@@ -0,0 +1,107 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.TypeUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HuffmanTest
+{
+    String[][] tests =
+        {
+            {"D.4.1","f1e3c2e5f23a6ba0ab90f4ff","www.example.com"},
+            {"D.4.2","a8eb10649cbf","no-cache"},
+            {"D.6.1k","6402","302"},
+            {"D.6.1v","aec3771a4b","private"},
+            {"D.6.1d","d07abe941054d444a8200595040b8166e082a62d1bff","Mon, 21 Oct 2013 20:13:21 GMT"},
+            {"D.6.1l","9d29ad171863c78f0b97c8e9ae82ae43d3","https://www.example.com"},
+            {"D.6.2te","640cff","303"},
+        };
+    
+    @Test
+    public void testDecode() throws Exception
+    {
+        for (String[] test:tests)
+        {
+            byte[] encoded=TypeUtil.fromHexString(test[1]);
+            String decoded=Huffman.decode(ByteBuffer.wrap(encoded));
+            Assert.assertEquals(test[0],test[2],decoded);
+        }
+    }
+    
+    @Test
+    public void testDecodeTrailingFF() throws Exception
+    {
+        for (String[] test:tests)
+        {
+            byte[] encoded=TypeUtil.fromHexString(test[1]+"FF");
+            String decoded=Huffman.decode(ByteBuffer.wrap(encoded));
+            Assert.assertEquals(test[0],test[2],decoded);
+        }
+    }
+    
+    @Test
+    public void testEncode() throws Exception
+    {
+        for (String[] test:tests)
+        {
+            ByteBuffer buf = BufferUtil.allocate(1024);
+            int pos=BufferUtil.flipToFill(buf);
+            Huffman.encode(buf,test[2]);
+            BufferUtil.flipToFlush(buf,pos);
+            String encoded=TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase();
+            Assert.assertEquals(test[0],test[1],encoded);
+            Assert.assertEquals(test[1].length()/2,Huffman.octetsNeeded(test[2]));
+        }
+    }
+
+    @Test
+    public void testEncode8859Only() throws Exception
+    {
+        char bad[] = {(char)128,(char)0,(char)-1,' '-1};
+        for (int i=0;i<bad.length;i++)
+        {
+            String s="bad '"+bad[i]+"'";
+            
+            try
+            {
+                Huffman.octetsNeeded(s);
+                Assert.fail("i="+i);
+            }
+            catch(IllegalArgumentException e)
+            {
+            }
+            
+            try
+            {
+                Huffman.encode(BufferUtil.allocate(32),s);
+                Assert.fail("i="+i);
+            }
+            catch(IllegalArgumentException e)
+            {
+            }
+        }
+    }
+    
+    
+}
diff --git a/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java
new file mode 100644
index 0000000..d204bc0
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java
@@ -0,0 +1,214 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.hpack;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.TypeUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class NBitIntegerTest
+{
+
+    @Test 
+    public void testOctetsNeeded()
+    {
+        assertEquals(0,NBitInteger.octectsNeeded(5,10));
+        assertEquals(2,NBitInteger.octectsNeeded(5,1337));
+        assertEquals(1,NBitInteger.octectsNeeded(8,42));
+        assertEquals(3,NBitInteger.octectsNeeded(8,1337));
+
+        assertEquals(0,NBitInteger.octectsNeeded(6,62));
+        assertEquals(1,NBitInteger.octectsNeeded(6,63));
+        assertEquals(1,NBitInteger.octectsNeeded(6,64));
+        assertEquals(2,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x01));
+        assertEquals(3,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x80));
+        assertEquals(4,NBitInteger.octectsNeeded(6,63+0x00+0x80*0x80*0x80));
+    }
+
+    @Test
+    public void testEncode()
+    {
+        testEncode(6,0,"00");
+        testEncode(6,1,"01");
+        testEncode(6,62,"3e");
+        testEncode(6,63,"3f00");
+        testEncode(6,63+1,"3f01");
+        testEncode(6,63+0x7e,"3f7e");
+        testEncode(6,63+0x7f,"3f7f");
+        testEncode(6,63+0x00+0x80*0x01,"3f8001");
+        testEncode(6,63+0x01+0x80*0x01,"3f8101");
+        testEncode(6,63+0x7f+0x80*0x01,"3fFf01");
+        testEncode(6,63+0x00+0x80*0x02,"3f8002");
+        testEncode(6,63+0x01+0x80*0x02,"3f8102");
+        testEncode(6,63+0x7f+0x80*0x7f,"3fFf7f");
+        testEncode(6,63+0x00+0x80*0x80,     "3f808001");
+        testEncode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
+        testEncode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
+
+        testEncode(8,0,"00");
+        testEncode(8,1,"01");
+        testEncode(8,128,"80");
+        testEncode(8,254,"Fe");
+        testEncode(8,255,"Ff00");
+        testEncode(8,255+1,"Ff01");
+        testEncode(8,255+0x7e,"Ff7e");
+        testEncode(8,255+0x7f,"Ff7f");
+        testEncode(8,255+0x80,"Ff8001");
+        testEncode(8,255+0x00+0x80*0x80,"Ff808001");
+    }
+
+    public void testEncode(int n,int i,String expected)
+    {
+        ByteBuffer buf = BufferUtil.allocate(16);
+        int p=BufferUtil.flipToFill(buf);
+        if (n<8)
+            buf.put((byte)0x00);
+        NBitInteger.encode(buf,n,i);
+        BufferUtil.flipToFlush(buf,p);
+        String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
+        assertEquals(expected,r);
+        
+        assertEquals(expected.length()/2,(n<8?1:0)+NBitInteger.octectsNeeded(n,i));
+    }
+    
+    @Test
+    public void testDecode()
+    {
+        testDecode(6,0,"00");
+        testDecode(6,1,"01");
+        testDecode(6,62,"3e");
+        testDecode(6,63,"3f00");
+        testDecode(6,63+1,"3f01");
+        testDecode(6,63+0x7e,"3f7e");
+        testDecode(6,63+0x7f,"3f7f");
+        testDecode(6,63+0x80,"3f8001");
+        testDecode(6,63+0x81,"3f8101");
+        testDecode(6,63+0x7f+0x80*0x01,"3fFf01");
+        testDecode(6,63+0x00+0x80*0x02,"3f8002");
+        testDecode(6,63+0x01+0x80*0x02,"3f8102");
+        testDecode(6,63+0x7f+0x80*0x7f,"3fFf7f");
+        testDecode(6,63+0x00+0x80*0x80,     "3f808001");
+        testDecode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
+        testDecode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
+        
+        testDecode(8,0,"00");
+        testDecode(8,1,"01");
+        testDecode(8,128,"80");
+        testDecode(8,254,"Fe");
+        testDecode(8,255,"Ff00");
+        testDecode(8,255+1,"Ff01");
+        testDecode(8,255+0x7e,"Ff7e");
+        testDecode(8,255+0x7f,"Ff7f");
+        testDecode(8,255+0x80,"Ff8001");
+        testDecode(8,255+0x00+0x80*0x80,"Ff808001");
+    }
+    
+    
+    public void testDecode(int n,int expected,String encoded)
+    {
+        ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
+        buf.position(n==8?0:1);
+        Assert.assertEquals(expected,NBitInteger.decode(buf,n));
+    }
+    
+    @Test
+    public void testEncodeExampleD_1_1()
+    {
+        ByteBuffer buf = BufferUtil.allocate(16);
+        int p=BufferUtil.flipToFill(buf);
+        buf.put((byte)0x77);
+        buf.put((byte)0xFF);
+        NBitInteger.encode(buf,5,10);
+        BufferUtil.flipToFlush(buf,p);
+        
+        String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
+        
+        assertEquals("77Ea",r);
+        
+    }
+    
+    @Test
+    public void testDecodeExampleD_1_1()
+    {
+        ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF"));
+        buf.position(2);
+        
+        Assert.assertEquals(10,NBitInteger.decode(buf,5));
+    }
+    
+
+    @Test
+    public void testEncodeExampleD_1_2()
+    {
+        ByteBuffer buf = BufferUtil.allocate(16);
+        int p=BufferUtil.flipToFill(buf);
+        buf.put((byte)0x88);
+        buf.put((byte)0x00);
+        NBitInteger.encode(buf,5,1337);
+        BufferUtil.flipToFlush(buf,p);
+        
+        String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
+        
+        Assert.assertEquals("881f9a0a",r);
+        
+    }
+    
+    @Test
+    public void testDecodeExampleD_1_2()
+    {
+        ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff"));
+        buf.position(2);
+        
+        Assert.assertEquals(1337,NBitInteger.decode(buf,5));
+    }
+    
+    
+    @Test
+    public void testEncodeExampleD_1_3()
+    {
+        ByteBuffer buf = BufferUtil.allocate(16);
+        int p=BufferUtil.flipToFill(buf);
+        buf.put((byte)0x88);
+        buf.put((byte)0xFF);
+        NBitInteger.encode(buf,8,42);
+        BufferUtil.flipToFlush(buf,p);
+        
+        String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
+        
+        Assert.assertEquals("88Ff2a",r);
+        
+    }
+
+    
+    @Test
+    public void testDecodeExampleD_1_3()
+    {
+        ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf"));
+        buf.position(1);
+        
+        Assert.assertEquals(42,NBitInteger.decode(buf,8));
+    }
+    
+
+}
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_00.json b/jetty-http2/http2-hpack/src/test/resources/data/story_00.json
new file mode 100644
index 0000000..44d521f
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_00.json
@@ -0,0 +1,53 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/cmn/logo-ns-130528.png"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_01.json b/jetty-http2/http2-hpack/src/test/resources/data/story_01.json
new file mode 100644
index 0000000..54aab3b
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_01.json
@@ -0,0 +1,52 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":scheme": "https"
+        },
+        {
+          ":authority": "example.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          ":method": "GET"
+        },
+        {
+          "user-agent": "hpack-test"
+        },
+        {
+          "cookie": "xxxxxxx1"
+        },
+        {
+          "x-hello": "world"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":scheme": "https"
+        },
+        {
+          ":authority": "example.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          ":method": "GET"
+        },
+        {
+          "user-agent": "hpack-test"
+        },
+        {
+          "cookie": "xxxxxxx2"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_02.json b/jetty-http2/http2-hpack/src/test/resources/data/story_02.json
new file mode 100644
index 0000000..4348579
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_02.json
@@ -0,0 +1,339 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "amazon.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/gno/beacon/BeaconSprite-US-01._V401903535_.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/x-locale/common/transparent-pixel._V386942464_.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/img12/other/disaster-relief/300-column/sandy-relief_300x75._V400689491_.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.amazon.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/x-locale/common/transparent-pixel._V192234675_.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/img12/shoes/sales_events/11_nov/1030_AccessoriesPROMO_GWright._V400626950_.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/Automotive/rotos/Duracell600_120._V192204764_.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "g-ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/G/01/ui/loadIndicators/loadIndicator-large._V192195480_.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ecx.images-amazon.com"
+        },
+        {
+          ":path": "/images/I/41HZ-ND-SUL._SL135_.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.amazon.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_03.json b/jetty-http2/http2-hpack/src/test/resources/data/story_03.json
new file mode 100644
index 0000000..3d7e5be
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_03.json
@@ -0,0 +1,342 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "baidu.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "baidu.com"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/img/baidu_sylogo1.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/cache/global/img/gs.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/global/js/home-1.8.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/user/js/u-1.3.4.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/img/i-1.0.0.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_04.json b/jetty-http2/http2-hpack/src/test/resources/data/story_04.json
new file mode 100644
index 0000000..3d7e5be
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_04.json
@@ -0,0 +1,342 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "baidu.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "baidu.com"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/img/baidu_sylogo1.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/cache/global/img/gs.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/global/js/home-1.8.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/cache/user/js/u-1.3.4.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s1.bdstatic.com"
+        },
+        {
+          ":path": "/r/www/img/i-1.0.0.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.baidu.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.baidu.com"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_05.json b/jetty-http2/http2-hpack/src/test/resources/data/story_05.json
new file mode 100644
index 0000000..dfcd8e1
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_05.json
@@ -0,0 +1,366 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "geo.craigslist.org"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/about/sites/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/styles/countries.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.craigslist.org/about/sites/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/js/formats.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.craigslist.org/about/sites/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/js/jquery-1.4.2.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.craigslist.org/about/sites/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "shoals.craigslist.org"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.craigslist.org/about/sites/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/styles/craigslist.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://shoals.craigslist.org/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/js/formats.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://shoals.craigslist.org/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.craigslist.org"
+        },
+        {
+          ":path": "/js/homepage.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://shoals.craigslist.org/"
+        },
+        {
+          "cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_06.json b/jetty-http2/http2-hpack/src/test/resources/data/story_06.json
new file mode 100644
index 0000000..74dac51
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_06.json
@@ -0,0 +1,342 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ebay.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.ebay.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ebay-stories.com"
+        },
+        {
+          ":path": "/wp-content/uploads/2012/11/Iso-65.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "rover.ebay.com"
+        },
+        {
+          ":path": "/roversync/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        },
+        {
+          "cookie": "ebay=%5Esbf%3D%23%5E; dp1=bpbf/%238000000000005276504d^u1p/QEBfX0BAX19AQA**5276504d^; cssg=c67883f113a0a56964e646c6ffaa1abe; s=CgAD4ACBQlm5NYzY3ODgzZjExM2EwYTU2OTY0ZTY0NmM2ZmZhYTFhYmUBSgAYUJZuTTUwOTUxY2NkLjAuMS4zLjE1MS4zLjAuMeN+7JE*; nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.ebaystatic.com"
+        },
+        {
+          ":path": "/aw/pics/s.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.ebaystatic.com"
+        },
+        {
+          ":path": "/aw/pics/mops/2012_doodles/Holiday/DS3/ImgWeek_1_Penguin_Small_150x30.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.ebaystatic.com"
+        },
+        {
+          ":path": "/aw/pics/globalHeader/facebook/g12.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.ebaystatic.com"
+        },
+        {
+          ":path": "/aw/pics/globalHeader/twitter/g12.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.ebaystatic.com"
+        },
+        {
+          ":path": "/aw/pics/globalHeader/icon_mobile_gray_11x16.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "srx.main.ebayrtm.com"
+        },
+        {
+          ":path": "/rtm"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.ebay.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_07.json b/jetty-http2/http2-hpack/src/test/resources/data/story_07.json
new file mode 100644
index 0000000..cabe2c3
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_07.json
@@ -0,0 +1,345 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yb/r/GsNJNwuI-UM.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yY/r/u8iA3kXb8Y1.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yI/r/qANVTsC52fp.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yt/r/FZaMKqARgC6.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yZ/r/jlKDoX15kHG.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yO/r/_MRarphcCIq.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yP/r/CRkiDDWTd1u.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yX/x/Qq6L1haQrYr.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yI/r/qANVTsC52fp.css"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/yN/r/EarbWo_mDU-.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.facebook.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "static.ak.fbcdn.net"
+        },
+        {
+          ":path": "/rsrc.php/v2/y7/x/9jt7oVdF7z3.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yO/r/_MRarphcCIq.css"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_08.json b/jetty-http2/http2-hpack/src/test/resources/data/story_08.json
new file mode 100644
index 0000000..f0fefde
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_08.json
@@ -0,0 +1,363 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "flickr.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.flickr.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "us.adserver.yahoo.com"
+        },
+        {
+          ":path": "/a"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.flickr.com"
+        },
+        {
+          ":path": "/images/share-this-icons-sprite.png.v6"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.flickr.com"
+        },
+        {
+          ":path": "/images/flickr-sprite.png.v4"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        },
+        {
+          "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.flickr.com"
+        },
+        {
+          ":path": "/flanal_event.gne"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "y.analytics.yahoo.com"
+        },
+        {
+          ":path": "/fpc.pl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "d.yimg.com"
+        },
+        {
+          ":path": "/ce/soup/soup_generated_fragment.gne"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "geo.yahoo.com"
+        },
+        {
+          ":path": "/b"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.flickr.com"
+        },
+        {
+          ":path": "/photos/nasacommons/4940913342/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541; fl_v=souhp; fpc10001561398679=Qvv1ikW_|aUqazlyMaa|fses10001561398679=|aUqazlyMaa|Qvv1ikW_|fvis10001561398679=Zj1odHRwJTNBJTJGJTJGd3d3LmZsaWNrci5jb20lMkYmdD0xMzUxOTUwMDc1JmI9JTJGaW5kZXhfc291cC5nbmU=|8M1871YYH0|8M1871YYH0|8M1871YYH0|8|8M1871YYH0|8M1871YYH0"
+        },
+        {
+          "referer": "http://www.flickr.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_09.json b/jetty-http2/http2-hpack/src/test/resources/data/story_09.json
new file mode 100644
index 0000000..b922bc7
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_09.json
@@ -0,0 +1,345 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "linkedin.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.linkedin.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/concat/common/js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.linkedin.com"
+        },
+        {
+          ":path": "/analytics/noauthtracker"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-requested-with": "XMLHttpRequest"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        },
+        {
+          "cookie": "bcookie=\"v=2&bae845a5-83ed-4590-becf-f0f3d586432b\"; leo_auth_token=\"GST:UDbWFFpLLdcS6gHJ7NJa3XYRsc7W_gDwutbWnlWLfo7G_2Y4jfLH-H:1351948419:4b5c0f1309310a9b659b97d8960e64fdd635526b\"; JSESSIONID=\"ajax:0608630266152992729\"; visit=\"v=1&G\"; X-LI-IDC=C1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "s.c.lnkd.licdn.com"
+        },
+        {
+          ":path": "/scds/common/u/img/favicon_v3.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.linkedin.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_10.json b/jetty-http2/http2-hpack/src/test/resources/data/story_10.json
new file mode 100644
index 0000000..686aa68
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_10.json
@@ -0,0 +1,339 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "msn.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.msn.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ads1.msads.net"
+        },
+        {
+          ":path": "/library/primedns.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stj.s-msn.com"
+        },
+        {
+          ":path": "/primedns.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "blu.stc.s-msn.com"
+        },
+        {
+          ":path": "/as/wea3/i/en-us/law/39.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stj.s-msn.com"
+        },
+        {
+          ":path": "/primedns.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stc.s-msn.com"
+        },
+        {
+          ":path": "/br/sc/i/ff/adchoices_gif2.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stb00.s-msn.com"
+        },
+        {
+          ":path": "/i/80/53CAC6A10B6248682CF221B24A92.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stb01.s-msn.com"
+        },
+        {
+          ":path": "/i/E0/A6C312635EF0A355668C820EB5343.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "col.stb00.s-msn.com"
+        },
+        {
+          ":path": "/i/BB/B1F619A1AD4D4AA6B0648BDBBCDEED.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.msn.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_11.json b/jetty-http2/http2-hpack/src/test/resources/data/story_11.json
new file mode 100644
index 0000000..cc86a09
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_11.json
@@ -0,0 +1,369 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "nytimes.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "t.pointroll.com"
+        },
+        {
+          ":path": "/PointRoll/Track/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.bbc.co.uk/news/business-20178000"
+        },
+        {
+          "cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "t.pointroll.com"
+        },
+        {
+          ":path": "/PointRoll/Track/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.bbc.co.uk/news/business-20178000"
+        },
+        {
+          "cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/packages/css/multimedia/bundles/projects/2012/HPLiveDebateFlex.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/js/app/common/slideshow/embeddedSlideshowBuilder.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/css/0.1/screen/slideshow/modules/slidingGallery.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/adx/images/ADS/31/46/ad.314668/NYT_MBM_IPHON_LEFT_Oct11.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/packages/js/multimedia/bundles/projects/2012/HPLiveDebateFlex.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/packages/js/multimedia/data/FilmStripPromo/2012_election_filmstrip.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "graphics8.nytimes.com"
+        },
+        {
+          ":path": "/packages/js/elections/2012/debates/videostrip/filmstrip.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.nytimes.com/"
+        },
+        {
+          "cookie": "RMID=007f010022166047bee9002b; adxcs=-"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_12.json b/jetty-http2/http2-hpack/src/test/resources/data/story_12.json
new file mode 100644
index 0000000..3b27fd7
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_12.json
@@ -0,0 +1,369 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "pinterest.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/164311086374323731_DhZSfIfc_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/161637074097583855_SNjDRMKe_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/273593746083022624_FCoEkXsC_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/52917364342893663_qtPmJgkx_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/116952921544035902_KyTWinzm_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/283445370267774252_AttBMVfT_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/237142736599025827_ufDEHdRe_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/224194887669533381_UBmi659g_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "media-cache-lt0.pinterest.com"
+        },
+        {
+          ":path": "/upload/274156696036479907_A1ezgnsj_b.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://pinterest.com/"
+        },
+        {
+          "cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_13.json b/jetty-http2/http2-hpack/src/test/resources/data/story_13.json
new file mode 100644
index 0000000..a692cb5
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_13.json
@@ -0,0 +1,342 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "qq.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/followme.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/sosologo.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/festival/da18search.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/festival/da18bodybg05.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/loginall_1.2.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/aikanLoading1.1.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/joke/Koala/Qfast1.0.1.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mat1.gtimg.com"
+        },
+        {
+          ":path": "/www/images/qq2012/mobileNews.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "img1.gtimg.com"
+        },
+        {
+          ":path": "/v/pics/hv1/241/117/1186/77149726.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.qq.com/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_14.json b/jetty-http2/http2-hpack/src/test/resources/data/story_14.json
new file mode 100644
index 0000000..c07d85f
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_14.json
@@ -0,0 +1,339 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "sina.com.cn"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.sina.com.cn"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "news.sina.com.cn"
+        },
+        {
+          ":path": "/js/87/20121024/201218ConfTop.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "int.dpool.sina.com.cn"
+        },
+        {
+          ":path": "/iplookup/iplookup.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i3.sinaimg.cn"
+        },
+        {
+          ":path": "/video/2012/1103/U7805P167DT20121103211853.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i3.sinaimg.cn"
+        },
+        {
+          ":path": "/home/2012/1102/U6041P30DT20121102122146.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i3.sinaimg.cn"
+        },
+        {
+          ":path": "/home/deco/2009/0330/logo_home.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "d1.sina.com.cn"
+        },
+        {
+          ":path": "/shh/lechan/20121016sina/logo1.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i0.sinaimg.cn"
+        },
+        {
+          ":path": "/home/2012/1103/U8551P30DT20121103063734.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i1.sinaimg.cn"
+        },
+        {
+          ":path": "/home/2012/1101/U6648P30DT20121101141432.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.sina.com.cn/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_15.json b/jetty-http2/http2-hpack/src/test/resources/data/story_15.json
new file mode 100644
index 0000000..1bd29a3
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_15.json
@@ -0,0 +1,336 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "taobao.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.taobao.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.taobao.com"
+        },
+        {
+          ":path": "/index_global.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "a.tbcdn.cn"
+        },
+        {
+          ":path": "/p/fp/2011a/assets/space.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "a.tbcdn.cn"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "a.tbcdn.cn"
+        },
+        {
+          ":path": "/p/fp/2011hk/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "a.tbcdn.cn"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "a.tbcdn.cn"
+        },
+        {
+          ":path": "/p/fp/2010c/js/fp-direct-promo-min.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "img01.taobaocdn.com"
+        },
+        {
+          ":path": "/tps/i1/T1fqY2XilfXXahsVgc-1000-40.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "img01.taobaocdn.com"
+        },
+        {
+          ":path": "/tps/i1/T1rZiwXgtfXXXXXXXX-110-135.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.taobao.com/index_global.php"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_16.json b/jetty-http2/http2-hpack/src/test/resources/data/story_16.json
new file mode 100644
index 0000000..e638e7d
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_16.json
@@ -0,0 +1,375 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "en.wikipedia.org"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "en.wikipedia.org"
+        },
+        {
+          ":path": "/wiki/Main_Page"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "upload.wikimedia.org"
+        },
+        {
+          ":path": "/wikipedia/en/c/ca/Kanthirava_cropped.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Fri, 02 Nov 2012 23:46:59 GMT"
+        },
+        {
+          "if-none-match": "288bdb2fd5e5a4f7272f58fcb083a7e1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "upload.wikimedia.org"
+        },
+        {
+          ":path": "/wikipedia/commons/thumb/d/d2/Dancing_girl_ajanta_%28cropped%29.jpg/72px-Dancing_girl_ajanta_%28cropped%29.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Tue, 30 Oct 2012 17:37:15 GMT"
+        },
+        {
+          "if-none-match": "6e8d56df9be35494b4d9f0ea72ed1a3e"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bits.wikimedia.org"
+        },
+        {
+          ":path": "/en.wikipedia.org/load.php"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://en.wikipedia.org/wiki/Main_Page"
+        },
+        {
+          "if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_17.json b/jetty-http2/http2-hpack/src/test/resources/data/story_17.json
new file mode 100644
index 0000000..50fa4ca
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_17.json
@@ -0,0 +1,348 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/clr/1/clr-121025.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp/logo.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_1.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/weather/general/transparent_s/clouds.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/weather/general/transparent_s/sun.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_2.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/premium/contents/bnr/2012/50x50/0928_store_supernatural.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_18.json b/jetty-http2/http2-hpack/src/test/resources/data/story_18.json
new file mode 100644
index 0000000..43377fb
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_18.json
@@ -0,0 +1,351 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yahoo.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "d.yimg.com"
+        },
+        {
+          ":path": "/hd/ch7news/7_world/1103_0700_nat_elephant_sml_1898chj-1898chl.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "au.yahoo.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "d.yimg.com"
+        },
+        {
+          ":path": "/mi/ywa.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yui.yahooapis.com"
+        },
+        {
+          ":path": "/combo"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "secure-au.imrworldwide.com"
+        },
+        {
+          ":path": "/cgi-bin/m"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "chart.finance.yahoo.com"
+        },
+        {
+          ":path": "/instrument/1.0/%5Eaxjo/chart;range=5d/image;size=179x98"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "chart.finance.yahoo.com"
+        },
+        {
+          ":path": "/instrument/1.0/%5Eaord/chart;range=5d/image;size=179x98"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "chart.finance.yahoo.com"
+        },
+        {
+          ":path": "/instrument/1.0/audusd=x/chart;range=5d/image;size=179x98"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        },
+        {
+          "cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "cm.au.yahoo.overture.com"
+        },
+        {
+          ":path": "/js_flat_1_0/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://au.yahoo.com/?p=us"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_19.json b/jetty-http2/http2-hpack/src/test/resources/data/story_19.json
new file mode 100644
index 0000000..fe8dd3a
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_19.json
@@ -0,0 +1,345 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.ru"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yandex.ru"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yabs.yandex.ru"
+        },
+        {
+          ":path": "/count/Vnw_3zF2dkO40002Zhl8KGa5KPK2cmPfMeYpO2zG0vAeOuAefZIAgoA2KAe2fPOOP96yq4ba1fDKGQC1hlDVeQN8GfVD17e7"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        },
+        {
+          "cookie": "t=p; yandexuid=6410453771351949451"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yabs.yandex.ru"
+        },
+        {
+          ":path": "/count/Vnw_3mft8wq40000Zhl8KGa5KP6yq4ba1fDKhlDVeQN8GfVD17a3=qcOn49K2cmPfMcbQagXZWgYAgoA2KAMM66IcD7W3"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        },
+        {
+          "cookie": "t=p; yandexuid=6410453771351949451"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.st"
+        },
+        {
+          ":path": "/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.st"
+        },
+        {
+          ":path": "/www/1.359/www/i/yandex3.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.st"
+        },
+        {
+          ":path": "/morda-logo/i/logo.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "mc.yandex.ru"
+        },
+        {
+          ":path": "/watch/722545"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        },
+        {
+          "cookie": "t=p; yandexuid=6410453771351949451"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.st"
+        },
+        {
+          ":path": "/www/1.359/www/pages-desktop/www-css/_www-css.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yandex.st"
+        },
+        {
+          ":path": "/www/_/_r7pp-b-hKoDbgyGYy0IB3wlkno.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yandex.ru/"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_20.json b/jetty-http2/http2-hpack/src/test/resources/data/story_20.json
new file mode 100644
index 0000000..f86f11a
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_20.json
@@ -0,0 +1,5674 @@
+{
+  "context": "request",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yahoo.co.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/clr/1/clr-121025.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp/logo.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_1.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/weather/general/transparent_s/clouds.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/weather/general/transparent_s/sun.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_2.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/premium/contents/bnr/2012/50x50/0928_store_supernatural.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_3.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_5.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/500052/1080894/20121029/meulz5rknmobtjfqmyz8-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/70506/1082209/20121024/ffmwiwdybofwysftxna1-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/yahoo/javascript/yfa_visual5_tbp.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yahoo.co.jp"
+        },
+        {
+          ":path": "/javascript/fp_base_bd_ga_5.0.42.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/yahoo/javascript/csc/20060824/lib2obf_b6.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/pr/tb_bg-120110.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/uhd/homepage_bg-120123.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/sicons/bookstore16.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/sicons/movie16.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/sicons/game16.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/cmn/pic_all-121004.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/sicons/fortune16.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/emg/disaster_ttl2.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/video-topics/rec/1211/03_e01.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/clr/1/clr-121025.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://k.yimg.jp/images/top/sp2/clr/1/clr-121025.css"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/cmp/comp_all-121012.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "k.yimg.jp"
+        },
+        {
+          ":path": "/images/top/sp2/spotlight/2011/1031o.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "news.c.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/20121103-00000193-sph-000-thumb.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2237/1080330/20121103/bg6so7sbgcqenc9py6xk-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "www.yahoo.co.jp"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/images/security/pf/yjsecure.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/js/yjaxc.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "dailynews.yahoo.co.jp"
+        },
+        {
+          ":path": "/fc/sports/nippon_series/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://www.yahoo.co.jp/"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "dailynews.yahoo.co.jp"
+        },
+        {
+          ":path": "/fc/js/fb_pc.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1073618/20121029/ypxcyyekc_ruhypdisqu-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/fc.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/icon/photo.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/mh/news.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/30/1077242/20121029/ixbislu9ygczxzdkfnpt-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/facebook/news_Facebook_76x76.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/rapid/1.5.0/ult.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/new2.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/nestopics_icon_40.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/yahoo/javascript/yfa_visual5.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/193/1072227/20121029/uyzwkpexjszyi2zgct4p-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085127/20121102/dalvv9p9fw9tribawawe-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085124/20121102/bz9rzgnremydaxbp4ihb-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/editor/topics_pr_linkimg_l2.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "lpt.c.yimg.jp"
+        },
+        {
+          ":path": "/im_sigg537mI30DS9hWeZeGpWl75Q---x200-y190-q90/amd/20121103-00000542-sanspo-000-view.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "amd.c.yimg.jp"
+        },
+        {
+          ":path": "/im_siggHulEjLwgzPyrVDkZ9oNPng---x200-y133-q90/amd/20121031-00005828-yj_corptrend-000-51670401-view.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "amd.c.yimg.jp"
+        },
+        {
+          ":path": "/im_siggrMDL3ZpnqnwM4Z1FYvhX2Q---x200-y133-q90/amd/20121101-00005830-yj_corptrend-000-51751400-view.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/css/import_ver2.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/commerce/js/libs/jquery/core/1.4.2/jquery.min.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/yui/jp/uhd/olympic/1.0.2/img/uhdChnk.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/yn_gnavi_sprite_20120926.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/social/btnMx.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/ytopics_sprite_icons.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/ytopics_sprite_backgrounds.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/relTabLeft.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/relTabRight.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/bullet_list.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/yui/jp/uft/1.0.0/img/utfChnk.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/accountTitleBg.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/social/sprite_icoSns16.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/topics/wiki/trendTitleBg.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/topics/css/import_ver2.css?date=20121029"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/yahoo/javascript/csc/20060824/lib2obf_b4.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ah.yimg.jp"
+        },
+        {
+          ":path": "/bdv/164354/1084075/20121101/4feasfvz47csxcoydlvl-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "platform.twitter.com"
+        },
+        {
+          ":path": "/widgets.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "platform.twitter.com"
+        },
+        {
+          ":path": "/widgets/tweet_button.1351848862.html"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "connect.facebook.net"
+        },
+        {
+          ":path": "/ja_JP/all.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "bkskapi.dailynews.yahoo.co.jp"
+        },
+        {
+          ":path": "/detail"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "platform.twitter.com"
+        },
+        {
+          ":path": "/widgets/follow_button.1351848862.html"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.twitter.com"
+        },
+        {
+          ":path": "/t.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "cdn.api.twitter.com"
+        },
+        {
+          ":path": "/1/urls/count.json"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "r.twimg.com"
+        },
+        {
+          ":path": "/jot"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/tweet_button.1351848862.html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "cdn.api.twitter.com"
+        },
+        {
+          ":path": "/1/users/show.json"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "p.twitter.com"
+        },
+        {
+          ":path": "/f.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "r.twimg.com"
+        },
+        {
+          ":path": "/jot"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://platform.twitter.com/widgets/follow_button.1351848862.html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "POST"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ocsp.verisign.com"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "115"
+        },
+        {
+          "content-type": "application/ocsp-request"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "dailynews.yahoo.co.jp"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJTOPICSFBREAD=d=juTus3MJdA6fAPKQn3MJyoWvkTaY6I2RngPiVKE3BMv8AFX.C4TMg0utwM_uXg_sKn7y2yDVFKE-&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/css/yj2.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/clear.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/cobranding/sanspo.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/json/jsr_class_1_1.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/hl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://dailynews.yahoo.co.jp/fc/sports/nippon_series/?1351933494"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/socialModule/realtimeSearch_1_0-min.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/jquery/jquery.template.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/socialModule/facebook_1_3_1-min.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "amd.c.yimg.jp"
+        },
+        {
+          ":path": "/im_siggvNnG417_XZJF5TsJPh7FFQ---x200-y190-q90/amd/20121103-00000542-sanspo-000-4-view.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/70506/1082210/20121024/0ffcv4drh8ir07jvroju-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1082189/20121029/2n1tdzicd8j7eotfexbi-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/jquery/jquery.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/widgets/widgets_1_1.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085127/20121102/ilaj2_d_zo_9bjginqty-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085124/20121102/vval_chos32k_7okick9-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/30/1072134/20121029/qv2c_lhjbra0qr5ps55w-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/css/master-news.css"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/css,*/*;q=0.1"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/news_socialbutton.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/media/ymui/img/lineWide_4x1.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/yn_sprite_icons.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/media/ymui/img/carrrot_2.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/media/ymui/img/photoNew_45x15.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/sprite_bgRTSearchBox.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/sprite_icoTwitter.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/yn_sprite_background.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/ranking.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/v1/yn_gnavi_sprite.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/yui/jp/ult/arrow.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/listing/tool/yjaxc/yjaxc-iframe.html"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "realtime.search.yahooapis.jp"
+        },
+        {
+          ":path": "/v1/post"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/widgets/tweet_button.html"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/listing/tool/yjaxc/yjaxc-iframe.html?src0=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Foi%3Fs%3Danemos_news01295%26i%3D2078709534%26w%3D%26apg%3D1%26t%3Dj%26u%3Dhttp%253A%252F%252Fheadlines.yahoo.co.jp%252Fhl%253Fa%253D20121103-00000542-sanspo-base%26ref%3Dhttp%253A%252F%252Fdailynews.yahoo.co.jp%252Ffc%252Fsports%252Fnippon_series%252F%253F1351933494%26enc%3DEUC-JP%26spaceId%3D%26jisx0402%3D%26type%3D%26crawlUrl%3D&src1=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Fjs%2Fyjaxc-internal-banner.js%3Fimgurl%3Dhttp%253A%252F%252Fah.yimg.jp%252Fimages%252Fim%252Finnerad%252F%26imgpath%3Dbnr1_ss_1_300-250.jpg%26clickurl%3Dhttp%253A%252F%252Frd.yahoo.co.jp%252Fbzc%252Fsds%252F97648%252Fevt%253D97648%252F*http%253A%252F%252Flisting.yahoo.co.jp%252Fy_promo%252Flisting01%252F%253Fo%253DJP1350"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/sc/show"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ah.yimg.jp"
+        },
+        {
+          ":path": "/bdv/164354/1080825/20121101/hii0znrxvsbx0dt01k_g-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/widgets/images/tweet.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/widgets/images/tweet_ja.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/lib/news/widgets/tweet_button.html"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "puffer.c.yimg.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "puffer.c.yimg.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "puffer.c.yimg.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "puffer.c.yimg.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/images/im/imgim/pc2/im1001149230pcmr1.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/listing/tool/yjaxc/yjaxc-iframe.html?src0=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Foi%3Fs%3Danemos_news01295%26i%3D2078709534%26w%3D%26apg%3D1%26t%3Dj%26u%3Dhttp%253A%252F%252Fheadlines.yahoo.co.jp%252Fhl%253Fa%253D20121103-00000542-sanspo-base%26ref%3Dhttp%253A%252F%252Fdailynews.yahoo.co.jp%252Ffc%252Fsports%252Fnippon_series%252F%253F1351933494%26enc%3DEUC-JP%26spaceId%3D%26jisx0402%3D%26type%3D%26crawlUrl%3D&src1=http%3A%2F%2Fyjaxc.yahoo.co.jp%2Fjs%2Fyjaxc-internal-banner.js%3Fimgurl%3Dhttp%253A%252F%252Fah.yimg.jp%252Fimages%252Fim%252Finnerad%252F%26imgpath%3Dbnr1_ss_1_300-250.jpg%26clickurl%3Dhttp%253A%252F%252Frd.yahoo.co.jp%252Fbzc%252Fsds%252F97648%252Fevt%253D97648%252F*http%253A%252F%252Flisting.yahoo.co.jp%252Fy_promo%252Flisting01%252F%253Fo%253DJP1350"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "urls.api.twitter.com"
+        },
+        {
+          ":path": "/1/urls/count.json"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/lib/news/widgets/tweet_button.html?_=1351949189638&count=none&id=twitter_tweet_button_2&lang=ja&original_referer=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base&redirect=&text=%E5%B7%A8%E4%BA%BA%E3%81%8C%EF%BC%93%E5%B9%B4%E3%81%B6%E3%82%8A%E6%97%A5%E6%9C%AC%E4%B8%80%EF%BC%81%E5%BE%A9%E5%B8%B0%E3%81%AE%E9%98%BF%E9%83%A8%E3%81%8C%E6%B1%BA%E5%8B%9D%E6%89%93%EF%BC%88%E3%82%B5%E3%83%B3%E3%82%B1%E3%82%A4%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84%EF%BC%89%20-%20Y!%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&url=http%3A%2F%2Fheadlines.yahoo.co.jp%2Fhl%3Fa%3D20121103-00000542-sanspo-base"
+        },
+        {
+          "cookie": "pid=v3:1351947306477664316206054; k=10.35.101.123.1351947536129989; guest_id=v1%3A135194753658491573; __utma=43838368.2140315505.1351947542.1351947542.1351947542.1; __utmb=43838368.2.10.1351947542; __utmz=43838368.1351947542.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "puffer.c.yimg.jp"
+        },
+        {
+          ":path": "/"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/favicon.ico"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/hl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?a=20121103-00000542-sanspo-base"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/images/tech/bcn1.js"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/3124/1073472/20121029/mkgcwzthl_hbpnxy_tno-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1074517/20121029/kqo8rgbu_aykmxxf3cqf-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/media/ymui/img/carrrot_5.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://i.yimg.jp/images/news/v1/css/master-news.css?v11"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085127/20121102/crs1gvpzl74_ilnbd8yl-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/bylines/v201209/main/bnr/bnr_300x90.png"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/twitter/tw_spo_300_60.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/193/1074340/20121029/rhnusvihwpg9khhap9vn-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/1862/1083691/20121030/fk8wxszqyglpfwkac5kl-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/hl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=moto&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1082190/20121029/_xhxh5ukdv3s6oigo4bq-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1075880/20121029/vstketkrv3fci_zfj0fb-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/30/1072203/20121029/rzqkxhmakk4bokrlm87_-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "i.yimg.jp"
+        },
+        {
+          ":path": "/images/news/module/md20120709_gsearch.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "content.yieldmanager.edgesuite.net"
+        },
+        {
+          ":path": "/atoms/71/f8/fb/ee/71f8fbeed96e2ac38d4638d6c6e2ece4.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/hl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=socc&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1073618/20121029/tldo4m5hcuajwtl9ebr7-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/3514/1070875/20121102/di3ufilunjw9ul9nrygs-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "amd.c.yimg.jp"
+        },
+        {
+          ":path": "/im_siggSTQFSGS6B_ulqQXD.kRB.g---x150-y83-q90/amd/20121103-00000687-yom-000-1-thumb.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/30/1072095/20121029/_wzyz3fszhqvouc6tuav-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "content.yieldmanager.edgesuite.net"
+        },
+        {
+          ":path": "/atoms/23/03/f1/77/2303f17798f0116b59cd53fbb5f89873.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "headlines.yahoo.co.jp"
+        },
+        {
+          ":path": "/hl"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=base&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b; YJNEWSCOMMENT=d=06yLIwT4EjfCUHM_ZATPTTC.be6FwFeXux__KeWeqlDK.dHwKDQYqgJFHj9.HJlNGmTwWgk.h4h.sU8V_TDfRcrHwDjLWrrsKoxSuxiWaUP8PvEUAbJUe9xIk79LoWKr6tlDjWRkyBVLbqWqtJB_axSkadUO&v=1; YJNEWSFB=d=g52f45b4EjeJqzak676NkVYuFf6EMD66FMZIfmpIG32ywhp.ZRx6EAf7vGDLjqk7eQGKmGgvFcgo&v=1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1074517/20121029/qym5s_fuonkwfh4vw608-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/71629/1073614/20121029/wnskbirfjfjyqqjwjnx3-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "yjaxc.yahoo.co.jp"
+        },
+        {
+          ":path": "/oi"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "*/*"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        },
+        {
+          "cookie": "B=76j09a189a6h4&b=3&s=0b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/2959/1085124/20121102/71ewr2thlfq_2yiqyhjw-a.gif"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/30/1072106/20121029/hczia9w6zzi3jskznvxo-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":method": "GET"
+        },
+        {
+          ":scheme": "http"
+        },
+        {
+          ":authority": "ai.yimg.jp"
+        },
+        {
+          ":path": "/bdv/26008/1077726/20121029/zuabaglgdswip3wx_faw-a.jpg"
+        },
+        {
+          "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
+        },
+        {
+          "accept": "image/png,image/*;q=0.8,*/*;q=0.5"
+        },
+        {
+          "accept-language": "en-US,en;q=0.5"
+        },
+        {
+          "accept-encoding": "gzip, deflate"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "referer": "http://headlines.yahoo.co.jp/hl?c=spo&t=l"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_21.json b/jetty-http2/http2-hpack/src/test/resources/data/story_21.json
new file mode 100644
index 0000000..86b67a6
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_21.json
@@ -0,0 +1,15422 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "location": "http://www.amazon.com/"
+        },
+        {
+          "content-length": "230"
+        },
+        {
+          "keep-alive": "timeout=2, max=20"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "6577"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 17:58:47 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 19 Oct 2012 23:59:58 GMT"
+        },
+        {
+          "age": "932740"
+        },
+        {
+          "x-amz-cf-id": "whiC_hNmBgrO48K-Fv1AqlFY-Cig61exld9QXg99v4RwPo9kzfqE9Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 26 Sep 2012 22:18:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 25 Sep 2012 20:26:21 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3249950"
+        },
+        {
+          "x-amz-cf-id": "LClrkUlr2-9oeIoNwP-CxxGuMmJQguT1mVNFchiptNXT2gkurFa1cw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3774"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 23:02:44 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 23:02:44 GMT"
+        },
+        {
+          "age": "309703"
+        },
+        {
+          "x-amz-cf-id": "0SnGIpF0HloiJDtBSskp0LPclCOdy-cBHBsP3LTUdBy-0l2hmYRW2w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-amz-id-1": "0HE6SZ5H5Z4Y71SA54J9"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "x-amz-id-2": "MqdgMKxu1H6fgZ4cXY/fMQyxCVupVtmdiA3mTqc2n4+baHA/4MFE3DtVsBH6B4hp"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 11 Sep 2012 13:31:51 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Sep 2008 10:13:34 GMT"
+        },
+        {
+          "age": "4577556"
+        },
+        {
+          "x-amz-cf-id": "AvgiZt6QvGiJjVptinxMWssqdE82ATuSxl0D-EfQqkg6iVMBCgJkdQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "7813"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 07:00:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:41:23 GMT"
+        },
+        {
+          "age": "108266"
+        },
+        {
+          "x-amz-cf-id": "C0P4ip7yqOsc3niS_9Bd5ONzppJ1_dduEL7eXeMlCIsohE0Nad0iCw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2503"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 16:46:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 02 Jun 2010 17:55:54 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "29362669"
+        },
+        {
+          "x-amz-cf-id": "T5hInOb6hUOq4NSYTVt8TjsCSGRUHafPxwGkS5jiNGzpLmixDUmWug=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "7441"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 14:59:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:01:41 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3103499"
+        },
+        {
+          "x-amz-cf-id": "8puqnUMeyh0E9DCrrjWoD5tD9GjqgGyr6aMyg--qLs2ztEb3QIj9HQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4127"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 21:46:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 12 Sep 2012 23:45:20 GMT"
+        },
+        {
+          "age": "3165467"
+        },
+        {
+          "x-amz-cf-id": "LModLJjBuUU3HjY0zayadcTVs_lDPQK-oIK3WWYJl9ykREzfNIm9Mw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3135"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 16 Sep 2012 13:49:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 04:46:34 GMT"
+        },
+        {
+          "age": "4144497"
+        },
+        {
+          "x-amz-cf-id": "6OFsf9nPu-D4_yWQy3sINzNayyg6fm625JfZVcPmqYdOicciN0i5rg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3039"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 04 Mar 2012 12:44:05 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Fri, 02 Mar 2012 18:46:04 GMT"
+        },
+        {
+          "age": "21082822"
+        },
+        {
+          "x-amz-cf-id": "r7y3D04cQyZW1pY59rhfKoWDuC9yHfp5enkf0y9a6BKaF_6PcDVg7g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4222"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 16 Jul 2012 17:01:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Jun 2009 12:02:10 GMT"
+        },
+        {
+          "age": "9489759"
+        },
+        {
+          "x-amz-cf-id": "VmOehiu6mDUBpTHylminnvdcSz7Pz3bwA_dNil6iko3qIIKu4pvwQg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1711"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 28 Nov 2011 02:10:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 15 Nov 2007 04:25:55 GMT"
+        },
+        {
+          "age": "29501626"
+        },
+        {
+          "x-amz-cf-id": "wDhU0erCw0YoyRgAjloixwiytE5IdFT-rCT5ITwxPx5uFgGAv50Y9Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3721"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 18 Nov 2011 22:23:31 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 04 Jan 2011 18:48:20 GMT"
+        },
+        {
+          "age": "30292856"
+        },
+        {
+          "x-amz-cf-id": "YXNG-nYMiEVi0gaRGKrCIfNODPvIKOE5L-dzPeXzyYh1LuQTLjvdSA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "24369"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 07:00:00 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:43:42 GMT"
+        },
+        {
+          "age": "21867"
+        },
+        {
+          "x-amz-cf-id": "2asasoycqewuj5Fwn6w6mjCvOMdZQZLZhNhdl44Yyo1-AI9hQ7bFfg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1216"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 28 Jul 2012 05:05:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 28 Feb 2011 18:36:12 GMT"
+        },
+        {
+          "age": "8495910"
+        },
+        {
+          "x-amz-cf-id": "6h3O56dcjyQ3aM_m5a8_ir-VgVzDCmcwyIUXFSYcLFIQISyj5Q46vA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "47767"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 14:52:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 08 Oct 2012 22:30:55 GMT"
+        },
+        {
+          "age": "1289499"
+        },
+        {
+          "x-amz-cf-id": "sO6PqD2yEqaPpl5EvNYnGspKuhuAXsV3jf-Ya1imW1287RLowvVQTQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4613"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 27 Nov 2011 23:44:52 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 21:42:35 GMT"
+        },
+        {
+          "age": "29510375"
+        },
+        {
+          "x-amz-cf-id": "qv844DZxuLlk-LGj1-AJNpjz_LOzLR2cGsrHaLRm9jAHtj0ynP66dQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3934"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 00:01:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 13:30:37 GMT"
+        },
+        {
+          "age": "1256566"
+        },
+        {
+          "x-amz-cf-id": "JW5QyuWGDa5ik9AIEsBmnV6YrytP9At48rtnwWjKkn77rXOj8cx9WA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1344"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 00:59:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 18:51:08 GMT"
+        },
+        {
+          "age": "43497"
+        },
+        {
+          "x-amz-cf-id": "IKlxWmc8byHH_FJFiboqtD71dz0H-GkBay3SaG26MwMCXfLft_HgYw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 15 Aug 2012 22:51:53 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=624307871"
+        },
+        {
+          "expires": "Mon, 16 Aug 2032 07:55:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:27 GMT"
+        },
+        {
+          "content-length": "5354"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 13:25:50 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630462932"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 13:39:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:27 GMT"
+        },
+        {
+          "content-length": "3658"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 08:00:53 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=629882804"
+        },
+        {
+          "expires": "Tue, 19 Oct 2032 20:31:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:27 GMT"
+        },
+        {
+          "content-length": "7632"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4804"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 21:53:07 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 21:10:04 GMT"
+        },
+        {
+          "age": "227481"
+        },
+        {
+          "x-amz-cf-id": "bdyVYgf7boW90khU9D9kSQ4rt8H41h_yufp79zDL_rVA8a9brz2IwA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "148"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 15 Jul 2012 13:57:33 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 01 Aug 2011 23:32:56 GMT"
+        },
+        {
+          "age": "9587215"
+        },
+        {
+          "x-amz-cf-id": "Gv6tJh4vJVFIOBxlsPYY_n-mupZYOqsq0_IXHTz6WS89qWAryOKy8g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "356"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 01:43:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 21 Jul 2011 20:40:59 GMT"
+        },
+        {
+          "age": "3151251"
+        },
+        {
+          "x-amz-cf-id": "A4eNx4xBAu8rDK_SSjVdCoYo59rIc5aBFph1neHeq97ohGyzANNfoA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "6986"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 30 Sep 2012 10:59:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:06:32 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2945079"
+        },
+        {
+          "x-amz-cf-id": "BCz8ITjlEUNn-tAfee5IQYTwG9afocm__16MmahSICmeqky8tmv-qA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-amz-id-1": "0HE6SZ5H5Z4Y71SA54J9"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "x-amz-id-2": "MqdgMKxu1H6fgZ4cXY/fMQyxCVupVtmdiA3mTqc2n4+baHA/4MFE3DtVsBH6B4hp"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795"
+        },
+        {
+          "cache-control": "max-age=29030400, public"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "296"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:28 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "5728"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 10 Oct 2012 01:33:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 22 Oct 2011 00:40:50 GMT"
+        },
+        {
+          "age": "8903"
+        },
+        {
+          "x-amz-cf-id": "odznSvAIyfv7NmqZX6A2oTHE_IX5rh889vBaPKfwpg3AMo9k3ScXcA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "6951"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:28 GMT"
+        },
+        {
+          "server": "Server"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "17849"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "ZgdRydvxV2Z5YPfl9vhZZTYWMOX7vl8vIt9RuMTlm258HbYgx1yMhHsXiVTR5T1w"
+        },
+        {
+          "x-amz-request-id": "135182B51618D297"
+        },
+        {
+          "date": "Wed, 18 Jul 2012 22:57:25 GMT"
+        },
+        {
+          "last-modified": "Wed, 18 Jul 2012 22:43:26 GMT"
+        },
+        {
+          "etag": "\"08b0f3794e1b5e9a927698e159741c50\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "50666"
+        },
+        {
+          "x-amz-cf-id": "4wcVhu3OEiWfFvYvE3GH5UYO4KY8UpnlLcJRRRqZh0Q1zELrmrAmsA=="
+        },
+        {
+          "via": "1.0 c33edbf5459a4a44749c2cb5ecdb3fca.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 02:31:02 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630422753"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 02:30:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:27 GMT"
+        },
+        {
+          "content-length": "54217"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1827"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 22:12:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Mar 2012 23:57:13 GMT"
+        },
+        {
+          "age": "3163891"
+        },
+        {
+          "x-amz-cf-id": "wU_0sJ4VJxKBN-1nsDAgg_KUmfVbpaaGyo7YelU9wE9JmGGGKQ92EQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1134"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 18:09:17 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Mar 2012 23:57:13 GMT"
+        },
+        {
+          "age": "2141712"
+        },
+        {
+          "x-amz-cf-id": "SoQLSlLwLn_jdEOyiXGwginYyKphpwUS6-dbQ3wpPqBJIRg6mOrKvQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "636"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 16:53:05 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 02 Jun 2010 22:18:48 GMT"
+        },
+        {
+          "age": "1195884"
+        },
+        {
+          "x-amz-cf-id": "twHfjXTW5hFlDA9KoqKVBWXyksHgSNg4Vhy3mstETvyPHr3CpZq6_Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "246"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 26 Jul 2012 10:28:32 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 02 Jun 2010 22:19:30 GMT"
+        },
+        {
+          "age": "8649357"
+        },
+        {
+          "x-amz-cf-id": "GuAxInIiaQe4FRi5wBUXvlgCqbiXlqBaFsFj_nccpovWEb1sePoPdQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-amz-id-1": "05FGR6EKSNDPZCE5TRJQ"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "x-amz-id-2": "Tjab3PJkvWGMyS25sjt7CpJ2clcWTx72Uj5PrdRHrCIku2pHj7RnTwl293ZTfYMX"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795"
+        },
+        {
+          "cache-control": "max-age=29030400, public"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 04 Sep 2012 11:58:23 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=625532809"
+        },
+        {
+          "expires": "Mon, 30 Aug 2032 12:11:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "content-length": "656"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 01 Oct 2012 10:33:01 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=628540179"
+        },
+        {
+          "expires": "Mon, 04 Oct 2032 07:34:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "content-length": "2251"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 21 Sep 2012 09:55:10 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=627262883"
+        },
+        {
+          "expires": "Sun, 19 Sep 2032 12:45:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "content-length": "1098"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 11:48:59 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630506046"
+        },
+        {
+          "expires": "Wed, 27 Oct 2032 01:38:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "content-length": "1342"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "content-length": "1101"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 16:40:17 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "public, max-age=621651328"
+        },
+        {
+          "expires": "Fri, 16 Jul 2032 13:59:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2424"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 18 Oct 2012 18:56:17 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 07 Oct 2011 03:33:58 GMT"
+        },
+        {
+          "age": "1361293"
+        },
+        {
+          "x-amz-cf-id": "MRpSS6BPNijyVanqgR6mydKxGphIrKl9jTmcGgiX2DmcWgVdFwTQ2w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3802"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 08:34:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 31 Jan 2012 23:51:01 GMT"
+        },
+        {
+          "age": "1312203"
+        },
+        {
+          "x-amz-cf-id": "ohsa-VbEM_mSc8EnpAEXEtU6Nk599gGxk2FtaVe9QKvloqbwSCbxNA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:29 GMT"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "server": "Server"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0RMJJXGT1KVEMXX3VSJP"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "NqGNEb/SfkxLIfbOv73h5JBBcLVNGjGLK9GCNJwg5TW2rI8DxuXtaszrL5UZhTYZ"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-amz-id-1": "12MZRY3TA9X8CDYHBV5T"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "x-amz-id-2": "mlslIMHpZawNFsGF0x1LVEqrRVG3ckOj+P3RRTLmw7Th6oLI75FjRKiMc9ln/2lK"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795"
+        },
+        {
+          "cache-control": "max-age=29030400, public"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "28988"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 08:13:25 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 23 Jul 2012 20:35:57 GMT"
+        },
+        {
+          "age": "1227065"
+        },
+        {
+          "x-amz-cf-id": "mNIt-n16LCJdi8mcEtro9XVeAtGNT2eusOQLsXk2aBoA_LGn9iuGbQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "30231"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 06:32:33 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 00:00:59 GMT"
+        },
+        {
+          "age": "196317"
+        },
+        {
+          "x-amz-cf-id": "FIDb9FCQOTap3p4J66TlrId8wIZ_I0Uw8DgL3KGyPEN5FIgqZ4BPpA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "25698"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 10:39:32 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 17:12:28 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3119098"
+        },
+        {
+          "x-amz-cf-id": "hKKlixQii0vlb9a_DiDDphY3LEUoIv24q9VfC3UOtpnJV37uLWUpmw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26311"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 16:56:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 20:13:30 GMT"
+        },
+        {
+          "age": "245268"
+        },
+        {
+          "x-amz-cf-id": "lpU11IQ1j_7om8_FVILszZ1CEV-8zAg172J2ph8lsbqt3hrfJnS7eQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "34586"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 25 Oct 2012 21:34:09 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 16:33:14 GMT"
+        },
+        {
+          "age": "747021"
+        },
+        {
+          "x-amz-cf-id": "DNbatysenX2LUU6xkuO3lGcxhDVX2DG5CzqVUpLHPw-L-eSRtn7_vw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "x-amzn-requestid": "014c3370-25b7-11e2-b46a-73e2a83196ed"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0RMJJXGT1KVEMXX3VSJP"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "NqGNEb/SfkxLIfbOv73h5JBBcLVNGjGLK9GCNJwg5TW2rI8DxuXtaszrL5UZhTYZ"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT"
+        },
+        {
+          "etag": "\"4486-7c5a6340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2590"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "35541"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 07:00:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 24 Aug 2012 15:19:22 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "367469"
+        },
+        {
+          "x-amz-cf-id": "kpSB8Aj4s2QcAS66S2b7mB-wlCfwmdJWltC0f0sPcsiYvcEbitBpoQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "31343"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 21:17:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 18:24:45 GMT"
+        },
+        {
+          "age": "661610"
+        },
+        {
+          "x-amz-cf-id": "i3CTyh6smISPVQ7LqJU5PQ5QUwHdPuZiSswgKhn1iRrMR73x5YQglg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "30919"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 16:31:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 23 Aug 2012 22:11:01 GMT"
+        },
+        {
+          "age": "1283583"
+        },
+        {
+          "x-amz-cf-id": "m8mt86i5hOEx1AMpRbo6qBzFxqJqTLek8zyWFYjxj2NFT6p2yRbnZw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 15:20:43 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630213450"
+        },
+        {
+          "expires": "Sat, 23 Oct 2032 16:22:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "content-length": "3978"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Sat, 02 Jun 2012 17:24:51 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=617973507"
+        },
+        {
+          "expires": "Fri, 04 Jun 2032 00:22:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "content-length": "2352"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 07:05:33 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=628204224"
+        },
+        {
+          "expires": "Thu, 30 Sep 2032 10:14:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "content-length": "2192"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 00:31:19 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630455624"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 11:38:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "content-length": "1783"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "content-length": "3742"
+        },
+        {
+          "last-modified": "Wed, 13 Jun 2012 19:39:59 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "public, max-age=618388596"
+        },
+        {
+          "expires": "Tue, 08 Jun 2032 19:41:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "359"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 23 Jan 2012 18:47:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Aug 2011 13:43:43 GMT"
+        },
+        {
+          "age": "20390"
+        },
+        {
+          "x-amz-cf-id": "K1hCWmx7ReBxsX55XuAkjHXE0mRsJjI50uNKE5GUBq4SdF4TzxN--A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-id=A7PYmy2fB0qZnFwhmisdExM|t; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "20"
+        },
+        {
+          "content-type": "text/plain"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "217"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "158"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "160"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-location": "http://spe.atdmt.com/images/pixel.gif"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CUR ADM DEV TAIo PSAo PSDo OUR BUS UNI PUR COM NAV INT DEM STA PRE OTC\""
+        },
+        {
+          "set-cookie": "MUID=38CD881268FB628E3D318C1F6BFB6289; expires=Monday, 03-Nov-2014 00:00:00 GMT; path=/; domain=.atdmt.com"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "313"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-location": "http://spe.atdmt.com/images/pixel.gif"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CUR ADM DEV TAIo PSAo PSDo OUR BUS UNI PUR COM NAV INT DEM STA PRE OTC\""
+        },
+        {
+          "set-cookie": "MUID=39C1843BD7CB679E06238036D4CB670B; expires=Monday, 03-Nov-2014 00:00:00 GMT; path=/; domain=.atdmt.com"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "6951"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "server": "Server"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "17849"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "ZgdRydvxV2Z5YPfl9vhZZTYWMOX7vl8vIt9RuMTlm258HbYgx1yMhHsXiVTR5T1w"
+        },
+        {
+          "x-amz-request-id": "135182B51618D297"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "last-modified": "Wed, 18 Jul 2012 22:43:26 GMT"
+        },
+        {
+          "etag": "\"08b0f3794e1b5e9a927698e159741c50\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "50669"
+        },
+        {
+          "x-amz-cf-id": "UB_lB5ijt678Q2wJ3BJ-U_cVvtSnWAVfUTXcCKhh-QAhIQ9BCb3djQ=="
+        },
+        {
+          "via": "1.0 c33edbf5459a4a44749c2cb5ecdb3fca.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "x-amzn-requestid": "01a883c0-25b7-11e2-ac1e-e97d81479c85"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "set-cookie": "skin=noskin; path=/; domain=.amazon.com; expires=Sat, 03-Nov-2012 13:04:26 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-amz-id-1": "05PW0GT01QWP44EFKF0E"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "x-amz-id-2": "GCho/mJOD51Oufijqw6gqph1/1sIiACGCKJXKh2zpMaDj6u5gA1ggWuscsW3aojI"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "x-amzn-requestid": "ffd52343-25b6-11e2-ac17-5765013d7795"
+        },
+        {
+          "cache-control": "max-age=29030400, public"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "187"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "a+sM7JnK1z8XJALH7//6/PrXIyqStu8OXpFxVoaX6gaWUfZFD47Fr2QQUa/fp7AI"
+        },
+        {
+          "x-amz-request-id": "1388995ECC503151"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 17:26:53 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-07T21:33:44.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "a20db430a00109d80184570ec2b5d38e"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Tue, 08 Nov 2011 18:37:11 GMT"
+        },
+        {
+          "etag": "\"a20db430a00109d80184570ec2b5d38e\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "157059"
+        },
+        {
+          "x-amz-cf-id": "Ls6I3zhLRw-y0K8aIUpki-XaifKyUBIlqjKRtAaQI11Yw135jA8Ahg=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "232"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "j62Ubwkhgqe/6HUlxy6AgFFF3a9toD+TP5OG4thryUyvAuIRkEPZznTcEkslc2vu"
+        },
+        {
+          "x-amz-request-id": "D24296DC343E3D4D"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 17:26:53 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2012-08-30T18:01:46.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "ac923fb65b36b7e6df1b85ed9a2eeb25"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Thu, 30 Aug 2012 18:02:23 GMT"
+        },
+        {
+          "etag": "\"ac923fb65b36b7e6df1b85ed9a2eeb25\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "157059"
+        },
+        {
+          "x-amz-cf-id": "u4HxdeiPj2Z69lQ7aky8PwR3bIL1DI2LZviCrEidCeKNRXIzSU04Hw=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "246"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "A8pOeFTyzWm76hXU6FfLkQf4c9wZCOf1QF9R4TGkjXEInQJp6farkkg0WB0HfwcK"
+        },
+        {
+          "x-amz-request-id": "4B032A9637D718D5"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 17:26:53 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-08T18:38:37.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "abb0183baa0ea995b47dcc0e9972095a"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Tue, 08 Nov 2011 18:41:02 GMT"
+        },
+        {
+          "etag": "\"abb0183baa0ea995b47dcc0e9972095a\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "157059"
+        },
+        {
+          "x-amz-cf-id": "o02bJWU_jSE66IwLSFs3qnpdALQRgcE53RerA0FNaohnIpayFuIBWg=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "227"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "9LJz7DXOJVq1v+6jQBPW+PKANy+8UBrktRUpS5ldd7n64fM5B0dvTEVk3oKOAaQj"
+        },
+        {
+          "x-amz-request-id": "7E12EE38DC5DE3F0"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 20:55:51 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2012-04-11T18:59:01.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "e45b8e1074fb65e447d6d8a91eff8a94"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Wed, 11 Apr 2012 18:59:43 GMT"
+        },
+        {
+          "etag": "\"e45b8e1074fb65e447d6d8a91eff8a94\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "662921"
+        },
+        {
+          "x-amz-cf-id": "B6N7v4ZLzrFyVRVxNchTyVO2unOzJHIK39q8SJis7c6pWrIOw4rC1Q=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "236"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "3TVcuu6MQ87em+GdI+9z27lbDxXU5i9H9Zz9GIbm33BZo9vPgIC/AkilBK5tF75Q"
+        },
+        {
+          "x-amz-request-id": "F105689791C8CFC6"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 20:55:51 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2012-05-18T18:46:04.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "b1178d4fb4111d1058a187cf31c95ab9"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Fri, 18 May 2012 18:47:11 GMT"
+        },
+        {
+          "etag": "\"b1178d4fb4111d1058a187cf31c95ab9\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "662921"
+        },
+        {
+          "x-amz-cf-id": "sKPhYUyawRrJWnfWsyGL2s3ckBnoapJQYfxvp1W3KVKwMiUhkEK51w=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "p3p": "CP=\"CUR ADM OUR NOR STA NID\""
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/ecm3?ex=openx.com&id=40a611fe-06f9-cb74-26a8-7b5edc1205e7"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "set-cookie": "i=cbdc52da-b3d4-4f79-bc70-3121d006fdfa; version=1; path=/; domain=.openx.net; max-age=63072000;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "server": "TRP Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "set-cookie": "SERVERID=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"
+        },
+        {
+          "keep-alive": "timeout=5, max=200"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/plain; charset=UTF-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "10979"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 21 Oct 2012 02:44:45 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 22:20:25 GMT"
+        },
+        {
+          "age": "1160386"
+        },
+        {
+          "x-amz-cf-id": "F1Bnl4JS9Kyz-O5cpuXeg0_j5GumDg2Qt1wp0zonzvxPGICjmUSeMg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1526"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 21 Oct 2012 09:00:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 15 Jul 2011 19:42:36 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1137859"
+        },
+        {
+          "x-amz-cf-id": "JGLRgB6lNjaxDdggNb9JkO58_vLkHmUReZ84GjyLh10FHCjDZ1d15Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 10:05:40 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=614707622"
+        },
+        {
+          "expires": "Tue, 27 Apr 2032 05:11:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:30 GMT"
+        },
+        {
+          "content-length": "1095"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "11117"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 29 Oct 2012 16:56:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 24 Sep 2012 20:44:19 GMT"
+        },
+        {
+          "age": "418061"
+        },
+        {
+          "x-amz-cf-id": "5o_BiUaTAD5lYQsK4IV5TzqQ5cWYNQbnt0xLwze5jS-445EERctTFg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "31461"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 17 Oct 2012 18:29:24 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 22:41:15 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1449307"
+        },
+        {
+          "x-amz-cf-id": "tw9-4WwNBPYcd_2n5w02SSvFLzYSQr7PgoWnUBoekvj_CAvLUtzicg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 01 Sep 2009 21:16:26 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=618550558"
+        },
+        {
+          "expires": "Thu, 10 Jun 2032 16:40:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "content-length": "3215"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 08:30:59 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613322830"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 04:31:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "content-length": "3542"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2045"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 16 Jul 2012 05:26:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 13 Jul 2011 21:50:54 GMT"
+        },
+        {
+          "age": "9531474"
+        },
+        {
+          "x-amz-cf-id": "vjhm9zt0l4ak9rTfcaqoDHHqCVyjy5BT-0EXxKy0Qu1D7GuQLeuwKQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESEDp6zTGnEVOFXTsUTIntlOo&google_cver=1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "server": "Cookie Matcher"
+        },
+        {
+          "content-length": "310"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 29 May 2009 20:56:27 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613357164"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 14:03:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "content-length": "739"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "23861"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 23:49:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 23:23:03 GMT"
+        },
+        {
+          "age": "2121273"
+        },
+        {
+          "x-amz-cf-id": "6igCzs5zDRpfl3uREE8U8b7UsUeKiOXlnR5OwfDF4SRDwMzu4n2Hxw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 06:26:14 GMT"
+        },
+        {
+          "last-modified": "Wed, 05 Sep 2012 21:17:19 GMT"
+        },
+        {
+          "etag": "\"19309a1-2b15-e65bd5c0\""
+        },
+        {
+          "cache-control": "max-age=172800"
+        },
+        {
+          "server": "Apache/2.2.3 (Red Hat)"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\", CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\""
+        },
+        {
+          "content-length": "3891"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/ecm3?id=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f&ex=admeld.com"
+        },
+        {
+          "content-length": "275"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "meld_sess=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f;expires=Sun, 05 May 2013 03:59:31 GMT;path=/;domain=tag.admeld.com;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:32 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "content-length": "9834"
+        },
+        {
+          "last-modified": "Tue, 14 Aug 2012 08:19:30 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "public, max-age=623720235"
+        },
+        {
+          "expires": "Mon, 09 Aug 2032 12:41:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 25 Feb 2009 15:49:48 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=580546798"
+        },
+        {
+          "expires": "Thu, 10 Jun 2032 16:40:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:31 GMT"
+        },
+        {
+          "content-length": "349"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26111"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 20:57:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:57:01 GMT"
+        },
+        {
+          "age": "144451"
+        },
+        {
+          "x-amz-cf-id": "14X7FbQwII7W32KG_B6UnQzAAN04K4czIvpQXldrJky1-W_FKI0wsA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "expires": "Mon, 29 Oct 2012 20:03:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 10 Jul 2012 09:55:27 GMT"
+        },
+        {
+          "etag": "\"1930a25-22c7-badbe1c0\""
+        },
+        {
+          "cache-control": "max-age=90400000, public"
+        },
+        {
+          "server": "Apache/2.2.3 (Red Hat)"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\", CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\""
+        },
+        {
+          "content-length": "2708"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 18 Apr 2012 10:47:18 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=623739489"
+        },
+        {
+          "expires": "Mon, 09 Aug 2032 18:02:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:32 GMT"
+        },
+        {
+          "content-length": "2622"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 20:03:15 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 20:03:15 GMT"
+        },
+        {
+          "etag": "EDAADA0BBD2E54186FB78DECDB80E1E00940A39A"
+        },
+        {
+          "cache-control": "max-age=283721,public,no-transform,must-revalidate"
+        },
+        {
+          "x-ocsp-reponder-id": "t8edcaocsp2"
+        },
+        {
+          "content-length": "471"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 16:35:33 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 16:35:33 GMT"
+        },
+        {
+          "etag": "179CA2EEF2B7FE96BC99C52D47B1A6E9E36FF3A7"
+        },
+        {
+          "cache-control": "max-age=357659,public,no-transform,must-revalidate"
+        },
+        {
+          "x-ocsp-reponder-id": "t8edcaocsp2"
+        },
+        {
+          "content-length": "471"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:32 GMT"
+        },
+        {
+          "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.7a mod_fastcgi/2.4.2"
+        },
+        {
+          "set-cookie": "KADUSERCOOKIE=A682BC39-E933-4AED-86D3-69AAE2AAD12F; domain=pubmatic.com; expires=Sun, 03-Nov-2013 13:04:32 GMT; path=/"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\""
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:33 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:33 GMT"
+        },
+        {
+          "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.8e-fips-rhel5 mod_fastcgi/2.4.2"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\""
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 22 Oct 2010 19:31:50 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=583595968"
+        },
+        {
+          "expires": "Mon, 09 Aug 2032 18:02:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:34 GMT"
+        },
+        {
+          "content-length": "355"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 21:06:15 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630485187"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 19:51:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:34 GMT"
+        },
+        {
+          "content-length": "3398"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "24345"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 10 Oct 2012 00:37:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 23:23:04 GMT"
+        },
+        {
+          "age": "2118435"
+        },
+        {
+          "x-amz-cf-id": "tLO5krWbCYmRm9LIjXDN76fC2DJhTSiML3Wx7P5GT_QflWQzjjyLSw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 09 Apr 2012 04:08:58 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613372173"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 18:14:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:34 GMT"
+        },
+        {
+          "content-length": "3972"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "21733"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 21 Oct 2012 01:33:35 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 08 Oct 2012 20:03:10 GMT"
+        },
+        {
+          "age": "1164660"
+        },
+        {
+          "x-amz-cf-id": "boy0DjYIiv9QiDUAB5IT03oJw0Oe-TzQq2zaLbbC8-MCS_l6Jrzf5g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:55:45 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630608237"
+        },
+        {
+          "expires": "Thu, 28 Oct 2032 06:01:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:35 GMT"
+        },
+        {
+          "content-length": "17650"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "23996"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 24 Oct 2012 00:39:53 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 08 Oct 2012 16:18:49 GMT"
+        },
+        {
+          "age": "908682"
+        },
+        {
+          "x-amz-cf-id": "qC_RVL0YLxYoBvaZ0uqbs2VI6jEgUk34Rk19qpGdS2VsFUS3KkWYMg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "21582"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 18:47:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 08 Oct 2012 20:03:11 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1275397"
+        },
+        {
+          "x-amz-cf-id": "vHqKStRXJPYsiKzS0tTwY_1XKiks6HvwJGT9UArSlfAs6OnCYHQ7lA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "22139"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 18 Oct 2012 09:05:16 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 08 Oct 2012 20:03:12 GMT"
+        },
+        {
+          "age": "1396759"
+        },
+        {
+          "x-amz-cf-id": "3iqSry0i3VhqyuBUo-iRW3UgESSNBQ3lv4YeFtxPi_-Acv46jt6IAw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "849"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 07:28:18 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Jul 2011 00:30:22 GMT"
+        },
+        {
+          "age": "3216977"
+        },
+        {
+          "x-amz-cf-id": "jh36SMSXaXj_TeRR9z4Vs8-cbbEoHRGJkz-zWwqnTDkn3mU7WYIILw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 17 Jan 2012 01:18:38 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613357224"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 14:04:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:35 GMT"
+        },
+        {
+          "content-length": "2305"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2645"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 16 Oct 2012 14:50:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 22 Oct 2010 23:53:27 GMT"
+        },
+        {
+          "age": "1548848"
+        },
+        {
+          "x-amz-cf-id": "RYwtx5a09etraZHlO8Ut-TcazsQhaIMlHsC_JTzCEXAYeXfmbh0AWA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 10:05:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=623739489"
+        },
+        {
+          "expires": "Mon, 09 Aug 2032 18:02:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:35 GMT"
+        },
+        {
+          "content-length": "656"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "590"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 19 Jul 2012 07:06:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 06 Oct 2010 20:47:18 GMT"
+        },
+        {
+          "age": "9266297"
+        },
+        {
+          "x-amz-cf-id": "jMk_WLA7tRGazvX3ieenZ8uPLkOB1NVjnlmuRGPRPfUGpdfopJWMug=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "618"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 17:16:59 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 15:15:31 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1280857"
+        },
+        {
+          "x-amz-cf-id": "gsm-rW_jbFRe2Ne92Oddd13REiBnDzo9k53P59LW-6WZhjFKi2gpcg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "6409"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 06 Oct 2012 05:21:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Apr 2012 05:07:39 GMT"
+        },
+        {
+          "age": "2446958"
+        },
+        {
+          "x-amz-cf-id": "RenD1oaMDB7WDA0nJBiT78PBjnjUmYU-NT3-eSlLX03q5vM16mQthg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "13915"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 05:57:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:21:14 GMT"
+        },
+        {
+          "age": "371215"
+        },
+        {
+          "x-amz-cf-id": "y-qky_uSUebpzoYKGYMa1lzGeUux4fgnmRhwkgvrXQn78lG5AhfFmA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 06:41:37 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=621353717"
+        },
+        {
+          "expires": "Tue, 13 Jul 2032 03:19:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:36 GMT"
+        },
+        {
+          "content-length": "1580"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4456"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 05:26:53 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:26:32 GMT"
+        },
+        {
+          "age": "286663"
+        },
+        {
+          "x-amz-cf-id": "QAWFAFoQqqdK6bsebuU01EfGVCwSV_HjtTaLA-hlTAAOA6d4Wsz4wg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2951"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 18:38:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:26:34 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "66355"
+        },
+        {
+          "x-amz-cf-id": "Aubb5MuBO28D2I8jIDVYWmI2-8g4Tt0cpl6beMcpVSNTX5gZMv4wgQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4666"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 17:58:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 17:58:34 GMT"
+        },
+        {
+          "age": "155162"
+        },
+        {
+          "x-amz-cf-id": "OBft3yppuSTyI5o52ZSa5lfbjZWp3ShzF8-dM45Pf0qkJIYh24nQtQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5192"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 16:39:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 11:12:38 GMT"
+        },
+        {
+          "age": "69923"
+        },
+        {
+          "x-amz-cf-id": "Y6S4ynuqdWWDNdGNvXNtU6fnNBBOoJLWVPdhgnyEnTTMDvI_4XuMzQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5529"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 03:41:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 03:15:26 GMT"
+        },
+        {
+          "age": "293004"
+        },
+        {
+          "x-amz-cf-id": "ShMwoXym8XNH4S1fFX15TBcjBioYagCJaBprDbqaOtJjOiNkWdeg7g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3629"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 23:15:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 23 Jun 2012 21:37:13 GMT"
+        },
+        {
+          "age": "1259327"
+        },
+        {
+          "x-amz-cf-id": "HlyMS446sa886uO7DjJyUavWa-mHH0XLcyzUrb49K-G4mkqMbSOsIA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3509"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 25 May 2012 23:03:05 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 18:35:18 GMT"
+        },
+        {
+          "age": "13960891"
+        },
+        {
+          "x-amz-cf-id": "-IZ-Kzdl4oTM776x_-SdI-Sf-rdBE0xeKYvmj2otONB4guu3l0lNsA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4879"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 04:39:14 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 03:14:55 GMT"
+        },
+        {
+          "age": "289522"
+        },
+        {
+          "x-amz-cf-id": "UnkzEKXd4DwGvLUL-8-afWzVHMcB4T-tYr9-HLWFRsfbiIvYylwIxA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2809"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 17:24:44 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Tue, 11 Sep 2012 11:41:25 GMT"
+        },
+        {
+          "age": "70792"
+        },
+        {
+          "x-amz-cf-id": "ApQSczR7vg5QCdxHZR6hBm1pbl-hGvpxOz6MPp9eCEoBx99I8-atXg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1979"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 18:13:18 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 18:13:18 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "240678"
+        },
+        {
+          "x-amz-cf-id": "WvvSWSGbGBRHrBf0RFjJ3qJ_o4y9yJuT8SeGDq1dpYvwTANrwyr-Ow=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6942"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 17:58:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 17:58:34 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "155162"
+        },
+        {
+          "x-amz-cf-id": "XA_j3mVwjsJMTgHec3EMMTJ547z0XmIPH8hlMt5tuM1OEe2Kuo_A8g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1854"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 03:41:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 03:15:25 GMT"
+        },
+        {
+          "age": "293004"
+        },
+        {
+          "x-amz-cf-id": "rPNUJ_0Y4uE0WKLOFZddVt9Pt-15ixc8M9WYFxZcxUq204PEfNtVuw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3661"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 16:20:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 11 Sep 2012 21:41:22 GMT"
+        },
+        {
+          "age": "161026"
+        },
+        {
+          "x-amz-cf-id": "10WYvTpJNEH0MAP3wne0pXXNE8ZnAI4eVJA3EDPrJ6TF3rv0YJJK_A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2729"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 23:43:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 01 Jun 2011 05:24:35 GMT"
+        },
+        {
+          "age": "70759"
+        },
+        {
+          "x-amz-cf-id": "kb2nMqvt29Qj3LdcwS6ww1KobMLzUlJWjzEzfJ49hrIYV9AchOannQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3916"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 17:24:44 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 07 Sep 2012 09:03:37 GMT"
+        },
+        {
+          "age": "70792"
+        },
+        {
+          "x-amz-cf-id": "JJZDbMR4RLNK_HVvTbUnNaDilC24pIBmtY7BRd5JkQybHgLPJLr2Bw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2103"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 18:14:15 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 18:14:15 GMT"
+        },
+        {
+          "age": "240621"
+        },
+        {
+          "x-amz-cf-id": "AG9h0_9ASRuhaLjhB4fsbvE6ktpeabI5v9S-fSJ_K1SOdr8skxsQ8A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2120"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 18:29:52 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 18:15:06 GMT"
+        },
+        {
+          "age": "239684"
+        },
+        {
+          "x-amz-cf-id": "3V9zS2t71NKOHjc-zbQieHw8D15BF88HM5DVQY9j5z7qaxE8JDHbyA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2065"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 17:25:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 17:48:33 GMT"
+        },
+        {
+          "age": "70748"
+        },
+        {
+          "x-amz-cf-id": "Nkglfv_cx2pdr2EZJF0D475iF5L5LK6Fxcq0dUDPSxCVHftCYtgHng=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2131"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 18:14:15 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 18:14:15 GMT"
+        },
+        {
+          "age": "240621"
+        },
+        {
+          "x-amz-cf-id": "Xp7P1ZCF0IjKGtBRruIMsC780cNrxhNJ5960ejB13uXf3su3MHM7PQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2962"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 07:00:00 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:49:53 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "194676"
+        },
+        {
+          "x-amz-cf-id": "peTzFJr516_fOBQY5OC91FWEamWDNAqIh8_l1VUiaqrMRgGupou75w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4626"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 07:00:02 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:49:52 GMT"
+        },
+        {
+          "age": "194674"
+        },
+        {
+          "x-amz-cf-id": "VMe4jZb7miZ0G-rv3uBPNmdTpYUIYgkj8UaXTHlFZ8sd2SONziLchg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3581"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 17:29:39 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:29:39 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "243297"
+        },
+        {
+          "x-amz-cf-id": "DQkavQgzFQLKNbG-YUMaAIW1JOadibOwvA_xdhashOIKLfpQuAn2gA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5534"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 05:49:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:49:53 GMT"
+        },
+        {
+          "age": "285279"
+        },
+        {
+          "x-amz-cf-id": "Quota3IS8N_cDOH-5AgNf6IoirJJCjYpEsTfXJKx-QYO8uoPPsgF5Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3336"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 07:03:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:03:12 GMT"
+        },
+        {
+          "age": "280884"
+        },
+        {
+          "x-amz-cf-id": "nKFIlcQrEACy_wNDwvMk7o4wDqwiqg22gTbbx1GgRtKIfeQCY4rAUg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3660"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 07:05:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:04:35 GMT"
+        },
+        {
+          "age": "280738"
+        },
+        {
+          "x-amz-cf-id": "5flYXqijU45smYJrbpa6DyFQK79BKOC75IH_AD_gBLabCf2_f6JJ4w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3631"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 07:03:29 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:03:29 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "280867"
+        },
+        {
+          "x-amz-cf-id": "9zt7Ykby0o5nJUdXmLURwVG97OcVN7UDmlxqqBAr6-kpce1NUZ3vHQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4831"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 07:02:44 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:02:44 GMT"
+        },
+        {
+          "age": "280912"
+        },
+        {
+          "x-amz-cf-id": "arnnoA4osVhZ9WWxe1rw1kH36LVZpueZhg5Ij7p06zynPPuP_PbhAg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "71"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 21 Oct 2012 07:10:55 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:53:07 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1144421"
+        },
+        {
+          "x-amz-cf-id": "otV5h9P0a9-ozjyL5asNyiDOMvE4cnJFvEUCY1qCIkCO1BlYJsF-fQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4528"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 23:30:10 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 13 Oct 2012 00:03:47 GMT"
+        },
+        {
+          "age": "653666"
+        },
+        {
+          "x-amz-cf-id": "zat2zuNOe5PZPMKX9J5IIEc2EvGHW2wIWsGnPPG6NWdX7cWtkKBL3Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "4305"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 19:34:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:07:44 GMT"
+        },
+        {
+          "age": "63009"
+        },
+        {
+          "x-amz-cf-id": "P_0GsZlh-uhXRNgmMVIxDRrsh8CWCBHEX0sNhI9WcxKsR6VpK8qf1A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "8307"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 07:00:07 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 19:02:26 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "194669"
+        },
+        {
+          "x-amz-cf-id": "_1G9P5_LnBwk_k5A76Q4cs4aOE-c9Y2U6KPOYakVoWIblaFat2Quuw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3817"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 21:23:14 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 22:25:34 GMT"
+        },
+        {
+          "age": "1006882"
+        },
+        {
+          "x-amz-cf-id": "b-rYDPAafNePCeY3rEXSUu_SHu_vhZoVf-W-90RHYbQi7NMrF7IuVw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "14262"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 19:54:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 19:43:52 GMT"
+        },
+        {
+          "age": "666617"
+        },
+        {
+          "x-amz-cf-id": "DYBg6QCNjA9V6sSGrhw4w4QT--gzcIbkjjJZKjphipyO-cYwRK1p8w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:36 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT"
+        },
+        {
+          "etag": "\"4486-7c5a6340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2590"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "5639"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 16:30:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 16:30:51 GMT"
+        },
+        {
+          "age": "938026"
+        },
+        {
+          "x-amz-cf-id": "O6Rt-cRJLPLokVndpOyGdTuWoLI6bPqiRt_TrdmIiYayIHUPbzY__A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "14998"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 20:28:09 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 20:28:09 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "318987"
+        },
+        {
+          "x-amz-cf-id": "LmtQ4CHgGq-tu05FlE0VnrOXiq0ALsXRzmG89ZFrPGFrzAJOWjQADw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "5391"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 23:27:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 19 Oct 2012 17:44:45 GMT"
+        },
+        {
+          "age": "308215"
+        },
+        {
+          "x-amz-cf-id": "B9874IgNcW6Dl_iw2J-uxdH_JRYl-xRAXmd-Fx2sDQjm3zOmOAGS6A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "14682"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 00:57:21 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 21:44:15 GMT"
+        },
+        {
+          "age": "216435"
+        },
+        {
+          "x-amz-cf-id": "JNivNWPfMlDwvI1crpnpaAtSZ9ynv0-1kJNOR3Kmfy-pFt3R00dHPQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "14468"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 07:00:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 03:52:02 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "194664"
+        },
+        {
+          "x-amz-cf-id": "u_bSf4kdjci5AymBMUSnaNCb7yBkMN4vlmaw6b2yHQaKkeC6bOoqXQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "17329"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 07:00:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 19:39:30 GMT"
+        },
+        {
+          "age": "194619"
+        },
+        {
+          "x-amz-cf-id": "8NlR_O7HCbbYd6sWYXsaGIxoNNX3kno3ZaIkqqgmHYk3r7P0msD2hA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "5249"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 11 Oct 2012 22:47:04 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 19:26:45 GMT"
+        },
+        {
+          "age": "1952252"
+        },
+        {
+          "x-amz-cf-id": "P3861d5dz7qGT13WJVUssV0-8x_VFQt4TtyhgjHZkDhDFHeoBpixcA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 25 Jun 2010 18:22:49 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=623879811"
+        },
+        {
+          "expires": "Wed, 11 Aug 2032 09:01:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:36 GMT"
+        },
+        {
+          "content-length": "2903"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 00:00:56 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630492875"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 21:59:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:37 GMT"
+        },
+        {
+          "content-length": "1467"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 03:41:46 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630506567"
+        },
+        {
+          "expires": "Wed, 27 Oct 2032 01:47:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:37 GMT"
+        },
+        {
+          "content-length": "4150"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 06:41:37 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=621353716"
+        },
+        {
+          "expires": "Tue, 13 Jul 2032 03:19:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:37 GMT"
+        },
+        {
+          "content-length": "1580"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 17 Jun 2009 18:26:49 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613395574"
+        },
+        {
+          "expires": "Mon, 12 Apr 2032 00:44:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:37 GMT"
+        },
+        {
+          "content-length": "856"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 02:32:26 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630557957"
+        },
+        {
+          "expires": "Wed, 27 Oct 2032 16:03:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:36 GMT"
+        },
+        {
+          "content-length": "74964"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3564"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 21 Oct 2012 19:37:21 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 12 Sep 2012 12:02:28 GMT"
+        },
+        {
+          "age": "1099637"
+        },
+        {
+          "x-amz-cf-id": "UnPWM9TK0CYPiYCFO7JpmgG2mEPdetqHfd_sfHtz7tBC7MdT1QthvQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4267"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 04:55:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 19:55:09 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "374966"
+        },
+        {
+          "x-amz-cf-id": "cjoJQzghJEJQidTuBdcGV7vefvG_4fs26RZ_XZHGp3J47Hsqk_mYqA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:23:58 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630506503"
+        },
+        {
+          "expires": "Wed, 27 Oct 2032 01:46:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:37 GMT"
+        },
+        {
+          "content-length": "115718"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1104"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 19:46:04 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 02 Jun 2010 22:12:17 GMT"
+        },
+        {
+          "age": "1271916"
+        },
+        {
+          "x-amz-cf-id": "CWh3NmGhidrPUirYTJeaMy1q9wfohhNrJcJHsnvLdnXf-hfmvNt_Eg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "6577"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 17:59:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 17:58:26 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2532"
+        },
+        {
+          "x-amz-cf-id": "h2X5ptCOi7LbCmEDN_-FkzuUX3O9fZGO3nRZaYiuaVmjsZJVea0KlA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "469"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 21 May 2012 18:57:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 16:40:47 GMT"
+        },
+        {
+          "age": "76922"
+        },
+        {
+          "x-amz-cf-id": "cTNh37gW3aRYzh0_ymNAgRrpHgiKNyjCHWwWepii3kfSm2mifkCOuQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1628"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 17 May 2012 00:31:56 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 05:09:34 GMT"
+        },
+        {
+          "age": "35944"
+        },
+        {
+          "x-amz-cf-id": "Lg2DdGTzo_5b8Nxk_htSqW7FB2nLWjG6cKbaOt8zmZY66pVw8K4fCA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "356"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 16 May 2012 19:42:46 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 05:09:34 GMT"
+        },
+        {
+          "age": "3065596"
+        },
+        {
+          "x-amz-cf-id": "1OH_QkiX-oKt7sV0toMi-aqqotKtLvRU2cjdTLewhf5rcVlqqk1ODg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Miss from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT"
+        },
+        {
+          "etag": "\"4486-7c5a6340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2590"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "x-amzn-requestid": "070e59c2-25b7-11e2-9647-1185f0fe0569"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0D7SZ3NDXXQ10K0Y1P2W"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "Yhw+pyNdxXVfOz+enqEPz5i4xubYpPznUk/Z7jiBcq/rnwK5Kwv0df5Ff+b2ROcL"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT"
+        },
+        {
+          "etag": "\"4486-7c5a6340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2590"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "x-amzn-requestid": "0727fc26-25b7-11e2-bb20-cf84a5272b25"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4885"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 07:00:03 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Aug 2012 04:35:28 GMT"
+        },
+        {
+          "age": "21877"
+        },
+        {
+          "x-amz-cf-id": "IporfETtFCxA5v41bAp-pDjDCP4cWlKwkoaOGvvvrxS1Mw1yvUBlGQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1543"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 11 Sep 2012 13:00:00 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Jul 2010 18:12:37 GMT"
+        },
+        {
+          "age": "4579480"
+        },
+        {
+          "x-amz-cf-id": "-6t8SJvNBh6dZt3rUiRrjIVqnnVJiFbFC-QSFxcqJYuBXrzKAWWdoQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "592"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 20:03:59 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:37:57 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1011641"
+        },
+        {
+          "x-amz-cf-id": "8vWzDFif0eREdPSdflEYZlgYAymCWdiDYl8Kv7KC_Fl0ALuKJG_4ag=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1646"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 16 Feb 2012 06:11:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 13 Oct 2010 20:47:21 GMT"
+        },
+        {
+          "age": "22575162"
+        },
+        {
+          "x-amz-cf-id": "3RdIhQfLO9XOQFa49YXot07-NIDImEld2xoGH4X9880KTfwAGihvfQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:37:51 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 22:37:51 GMT"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-transfer-encoding": "binary"
+        },
+        {
+          "content-length": "1596"
+        },
+        {
+          "cache-control": "max-age=379990, public, no-transform, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:41 GMT"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 20:27:41 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 20:27:41 GMT"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-transfer-encoding": "binary"
+        },
+        {
+          "content-length": "1596"
+        },
+        {
+          "cache-control": "max-age=372180, public, no-transform, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:41 GMT"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0ZHTZBAADKEZ1K4EGBW6"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "yJRRI8wh/xPuc4C3nBZz5KNXS1OE9OJu63P/XksiIWL9W09cknSsgC8WWr29GiDY"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Tue, 21 Sep 2010 17:37:41 GMT"
+        },
+        {
+          "etag": "\"4486-7c5a6340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2590"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "x-amzn-requestid": "0727fc26-25b7-11e2-bb20-cf84a5272b25"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1ZH0W43SZ47AMV593QDH"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "wGMRjKh1Pt/o44qHjshIvp7ZIPt2LK8Cze7/o3+/lfgxPUcgTEKCAZBzlDIoLoet"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "452"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "480"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 18:39:58 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 22:20:44 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:20:44 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "43420"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "53038"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1543"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Aug 2011 13:43:43 GMT"
+        },
+        {
+          "age": "20402"
+        },
+        {
+          "x-amz-cf-id": "6gJoa6bOvFtigUntTCjVHju-EqLbWnHKw6eJPDdiGK6ocghu7-S_cg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 09:43:11 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=621326683"
+        },
+        {
+          "expires": "Mon, 12 Jul 2032 19:49:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:42 GMT"
+        },
+        {
+          "content-length": "4823"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:47 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0DHCSP7QGSTG72H1QPRB"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "iwlAGigQepIxbg6chfZtqXoGGw6vBTgxU/ol+ayO5+ttKg7WcjWBSrPG+7aY5Eey"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "06NWT8YAYSXDSXHFEBX3"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "+dgTelR5Pvj5ApOpupZ5c4EXyGBnWsp/CtTohBqWXrKuiSIBT+ZSU/92HDHIoBxS"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2393"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 30 Sep 2012 01:55:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 15 Dec 2009 04:00:19 GMT"
+        },
+        {
+          "age": "2977760"
+        },
+        {
+          "x-amz-cf-id": "iMEciUEJFtmANuUhvSWuNQKwQ56xFPVzicWdjaUIS7KD_SS41vr3pQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "599"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 14:12:09 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:32:16 GMT"
+        },
+        {
+          "age": "3106359"
+        },
+        {
+          "x-amz-cf-id": "tN10_L-OYWE-jbnsbpustU_nkePz1Ht2dF12FZfdzo8SDh6xAzABhw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3457"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 16:44:30 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 06 Aug 2012 02:14:57 GMT"
+        },
+        {
+          "age": "332418"
+        },
+        {
+          "x-amz-cf-id": "nAZvrqCa80oBwwxAEUWbmmOUITdcLIDdCpFL12zOCAKgSf4n0wfGcQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3174"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 08 Mar 2012 01:24:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 15 Oct 2010 14:25:35 GMT"
+        },
+        {
+          "age": "20777998"
+        },
+        {
+          "x-amz-cf-id": "o4ZBTBwVKGrCOxAmevzGBdf3GXvw24E_Ibo53uEwUJbXc2EdAiOMyQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "601"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 30 Sep 2012 13:45:07 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:33:44 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2935181"
+        },
+        {
+          "x-amz-cf-id": "_ELm77X7wvQxQ8ccnoUS-_woGWJlpaS6DF6N2WkCaQSwNycPUCFD4A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3446"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 05 Jan 2012 14:17:10 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT"
+        },
+        {
+          "age": "26174858"
+        },
+        {
+          "x-amz-cf-id": "-Kkrw4riucQdic2OO_FiGGTwkrKyhvjx0Mcpi0Tz7UmWTD6LAmwHeg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3793"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 19:06:32 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Aug 2012 03:08:01 GMT"
+        },
+        {
+          "age": "669496"
+        },
+        {
+          "x-amz-cf-id": "X6dyQ-kDIuminUqGxtG-vyD7eZ70sWXg-ltBtWE0KkdI8OEM-Mpleg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "609"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 25 Sep 2012 16:01:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 15:54:14 GMT"
+        },
+        {
+          "age": "3358970"
+        },
+        {
+          "x-amz-cf-id": "b_pAd8eX4r8HYc3jV3dhKukKkfwIrYz-zWqHjipfMmhJSE_781h1oQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3653"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 01 Feb 2012 02:46:14 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "23883514"
+        },
+        {
+          "x-amz-cf-id": "bjtvmLGP6K92dIdVA6duj28yhxkrL38nJMkNCptOUGcR-vblR3Dgog=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3268"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 16:12:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT"
+        },
+        {
+          "age": "939130"
+        },
+        {
+          "x-amz-cf-id": "NjXCi6TD-dhpmdMViBrtzqn_DEt71fFljKydDm_2OCDAPJEMAg5xnA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2974"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 09:47:16 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 03 Apr 2012 10:20:17 GMT"
+        },
+        {
+          "age": "357452"
+        },
+        {
+          "x-amz-cf-id": "Z_49skoUilBV6g2nhKUJZO1CTvzkPUHD_SDUxrSh1etd8GS3FknVlQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3246"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 04:05:23 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Tue, 02 Feb 2010 23:26:50 GMT"
+        },
+        {
+          "age": "723565"
+        },
+        {
+          "x-amz-cf-id": "0SbSlmo1oQR1EZaPujBcrkn2rp6-JwnKeWPjRJuZmV1Z6bYwy17-7Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3677"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 23:48:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:14:18 GMT"
+        },
+        {
+          "age": "998171"
+        },
+        {
+          "x-amz-cf-id": "kIXZdAY5Fnpheu46XC3kSBlJD9BzYrmLWTcGFXMEBT4VLXyNpe1SPw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2600"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 14 Dec 2011 20:22:55 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT"
+        },
+        {
+          "age": "28053713"
+        },
+        {
+          "x-amz-cf-id": "jdbN9e43yR0jKrrOZUnGZIUGi2GCJHSK3n2VKaDm3XT7Xy-Rj8OqNQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1489"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 18 Jul 2012 14:38:05 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 04 Jun 2010 01:32:52 GMT"
+        },
+        {
+          "age": "9325603"
+        },
+        {
+          "x-amz-cf-id": "X3VwQpWnMPHQC7MJRw6T-DaBIBalsbD0mGV4Ng9yHU5gBejjAez0dA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1C1W41NW5TYBHBJNXB7G"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "AatuyevJiRUtb6/2d9LbJJ3EZwL4Qi5oAN43fcnZTs+cBfpfR5xhWX4o6c4AFjko"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "101M70TJ0XKDRA31P9ZW"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "8Q84WjUy4qxnCmekXyK0cOh2MgfmCnF2jlIdsknvZNKQIyUhsXloJp0QYIhPIFFw"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0R7WZ6VQ04KDQ1RKBSDK"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "iCw5Tdn11Ug6Qn1eOt4uOA+JEPcRxl56zUcXJAWRQ7+nE2ZJ4m5XU7DWbrWSX6Jj"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4760"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 09:19:33 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 27 Jul 2012 14:32:32 GMT"
+        },
+        {
+          "age": "1309517"
+        },
+        {
+          "x-amz-cf-id": "wn_k8I4g86z9xU39JO_mi8Znx5qLGm-YEKtqp9bzQUcLva6y9aPWWg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3348"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 14 Sep 2012 14:36:02 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 14:38:01 GMT"
+        },
+        {
+          "age": "4314528"
+        },
+        {
+          "x-amz-cf-id": "FEA_NXcSb4YgiTvDGcoQ8YzVOim-T7ZoGwBNe_-tBm3HybITjhj1bw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "587"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 15:34:28 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 15:54:16 GMT"
+        },
+        {
+          "age": "1200622"
+        },
+        {
+          "x-amz-cf-id": "vmJhsk3IfjzGGQAAi64eB8PuL0vI87SwHahTEYuBFlmrsmi_dxZ-IA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5691"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 04:35:25 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 17:48:15 GMT"
+        },
+        {
+          "age": "2190565"
+        },
+        {
+          "x-amz-cf-id": "UiucrnKNxdras37pId8z-tCHGNPWFMZJXLOIxPAsl_08EFRty9FxZA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4764"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 16 Oct 2012 16:34:25 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 02:17:34 GMT"
+        },
+        {
+          "age": "1542625"
+        },
+        {
+          "x-amz-cf-id": "quvhesbVUpq0D4qHZPiMZU_LBC4xAEbnNL5tNfJoazAENn82wpjOFA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "588"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 12:35:39 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:41:22 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3112151"
+        },
+        {
+          "x-amz-cf-id": "RNt3gJPkHWBNRTsYRS0r-qEJUzHeKw0wd8LRUaKmPjRoB_txmvKk0g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3687"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 25 Jul 2012 15:43:46 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 14:50:09 GMT"
+        },
+        {
+          "age": "8716864"
+        },
+        {
+          "x-amz-cf-id": "P_VlWy_DI7Q9lOv31mLocJxGBGCO3x_Flg_jDhAwOvSOlHxhfkj4hA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5547"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 21 Mar 2012 20:01:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Mar 2012 14:44:09 GMT"
+        },
+        {
+          "age": "19587818"
+        },
+        {
+          "x-amz-cf-id": "gVRXsClGSK87EC1y6EX-0j9CO-BL95NF-urXdrKWurV1eDIRau04Cw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4020"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 09:18:15 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 13 Oct 2012 21:42:50 GMT"
+        },
+        {
+          "age": "1309595"
+        },
+        {
+          "x-amz-cf-id": "mvpI8qWvGHh__TojWYI7VYmcaawpJ27bnnPJ08ozq7UlLXJiYycA4g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4769"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 08 Oct 2012 21:18:35 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 31 Jul 2012 08:49:37 GMT"
+        },
+        {
+          "age": "2216775"
+        },
+        {
+          "x-amz-cf-id": "d8GIZ1IcSWZMBXJ8HsZ_vts4ysREuGFsNrOBA_iB5au7tUOZqueqQQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1759"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 01:27:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Jan 2009 18:19:36 GMT"
+        },
+        {
+          "age": "3238644"
+        },
+        {
+          "x-amz-cf-id": "bTf74h2ZtQt_I09t6RmrbYg-97o_HtttusNHsh-MGb8gUA51AY7Twg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "17741"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 12 Oct 2012 14:19:15 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Wed, 19 May 2010 09:51:41 GMT"
+        },
+        {
+          "age": "1896338"
+        },
+        {
+          "x-amz-cf-id": "UYx91fWWjcOHKIO2wY26UNYf5EQYYW4g5IWOLayy-_r3LBCjQQsV6w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 26 Mar 2012 20:19:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630656332"
+        },
+        {
+          "expires": "Thu, 28 Oct 2032 19:23:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:53 GMT"
+        },
+        {
+          "content-length": "2126"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 05:47:45 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=627946664"
+        },
+        {
+          "expires": "Mon, 27 Sep 2032 10:42:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:53 GMT"
+        },
+        {
+          "content-length": "1518"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 04 Nov 2009 06:54:44 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613395773"
+        },
+        {
+          "expires": "Mon, 12 Apr 2032 00:47:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:53 GMT"
+        },
+        {
+          "content-length": "2288"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 21 Sep 2012 07:31:02 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=626993061"
+        },
+        {
+          "expires": "Thu, 16 Sep 2032 09:49:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:53 GMT"
+        },
+        {
+          "content-length": "2752"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 04:13:23 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630408896"
+        },
+        {
+          "expires": "Mon, 25 Oct 2032 22:39:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:53 GMT"
+        },
+        {
+          "content-length": "18249"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "796"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 12 Oct 2012 10:45:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Wed, 19 May 2010 09:51:41 GMT"
+        },
+        {
+          "age": "1909174"
+        },
+        {
+          "x-amz-cf-id": "9MHc1JZ7kR7Xm1k_06GjXXBjMfsbYsbpxH549UlaToDw3PtOlOpJng=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:52 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "05Y7M552RGFYHV8MY341"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "oGWKRn1W+jjcnVaAmsQPuDLm0eqlACpITrO3bAh2oWT2VrepfzlHFl5s2S6e8ah5"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-sap-pg": "photo_display_on_website"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "expires": "-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2358"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 21 Nov 2011 14:41:51 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "30061382"
+        },
+        {
+          "x-amz-cf-id": "rRtoTrePiEQnYeC12h_GTXYCVfIghwtr3bSzq5YQmQ2ZGyWgspVhvQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2343"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 28 Nov 2011 00:30:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT"
+        },
+        {
+          "age": "29507652"
+        },
+        {
+          "x-amz-cf-id": "47jA2MZ4Sw4DCikN2VyaaWmwTHmqX3rU2MwTeNh7e1Jz_UoUPpYraQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3059"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 05 Jan 2012 13:26:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT"
+        },
+        {
+          "age": "26177906"
+        },
+        {
+          "x-amz-cf-id": "WYavyIQcFAiZj--Zhj4aZuRfOIHvmeL3UfzvuuRJG_cspyZyEBTZvw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1090"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 06:05:00 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT"
+        },
+        {
+          "age": "25193"
+        },
+        {
+          "x-amz-cf-id": "8VDa9TCRS7VKfaAxdyPoMxc3nU5HHd7-ochC_jBjm5Htnl-jkMkuTA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "730"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 25 Jul 2012 12:42:51 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 31 Jan 2011 08:00:09 GMT"
+        },
+        {
+          "age": "8727722"
+        },
+        {
+          "x-amz-cf-id": "QrXHFzwiaMq4tNw6xz1x_Fy8OExfQwsb9eYgNg9x5of9ynYhiimfqg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1271"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 05 Jan 2012 19:58:22 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT"
+        },
+        {
+          "age": "26154391"
+        },
+        {
+          "x-amz-cf-id": "zfueMiQqfM6t_I7CSioRWzJ6Ja4aCnQfweQZmxivqYZ8HJfnkGedAQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1333"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 08 Feb 2012 22:12:29 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 10 Feb 2011 01:27:46 GMT"
+        },
+        {
+          "age": "23208744"
+        },
+        {
+          "x-amz-cf-id": "ELEGmBCM3aCsE_CitSFuw5Z_9oO1nINZ1Td8UGwaW5JQqOgNgrbAgw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1361"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 07 Mar 2012 21:41:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Fri, 07 Oct 2011 06:20:36 GMT"
+        },
+        {
+          "age": "20791384"
+        },
+        {
+          "x-amz-cf-id": "pOqim5pkNLfn0oKxi7ICFEmFFenUh0PbL_R9Lb9h6TpuGt0tRp4z8Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3006"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 13 Oct 2011 00:59:11 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Feb 2010 23:33:20 GMT"
+        },
+        {
+          "age": "33480342"
+        },
+        {
+          "x-amz-cf-id": "G9CB0PE2to9TXhCktQwgI5sW6rlvjeiIaljq43R1hfimZv_emDTQ5Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3051"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 22 Nov 2011 21:04:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT"
+        },
+        {
+          "age": "29952013"
+        },
+        {
+          "x-amz-cf-id": "8B2pTWiByqir35Y8C9JwI9kCzXLE0qdWzMliO7vI6X4z0IPFb7OJSw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3784"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 24 Jan 2012 22:05:08 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 May 2010 10:34:44 GMT"
+        },
+        {
+          "age": "24505185"
+        },
+        {
+          "x-amz-cf-id": "iiwiqgcVCWG_cRsMapSsC7zbtuul0T9eNy4NjAklVsbJhZbhbNP0Hw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2439"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 20 Nov 2011 13:48:40 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT"
+        },
+        {
+          "age": "30150973"
+        },
+        {
+          "x-amz-cf-id": "N3_BBMhFY33Y_cabN1aZofeaRTYY2qxgxIlyDqqnyzTHoBb-HQQ4kA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3087"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 10:10:03 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 25 Jul 2011 21:08:27 GMT"
+        },
+        {
+          "age": "1047291"
+        },
+        {
+          "x-amz-cf-id": "pUS_TqP5ZtROVGDGuR-eDXw0ijzMiGzziwONZiQwoWOmwMrlTnRUiQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3377"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 12:55:04 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 05 Jun 2009 14:46:00 GMT"
+        },
+        {
+          "age": "1037390"
+        },
+        {
+          "x-amz-cf-id": "U8QzlM0myAnVtennCypCEE35AVBn9P7vU8rfVC-qdIV19u_F-61loA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 28 Sep 2012 12:16:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:15:32 GMT"
+        },
+        {
+          "age": "3113322"
+        },
+        {
+          "x-amz-cf-id": "yRMGD1lIFrzR7iBctL75xllVcgCY4oq5vxpU8vyBYtYIhDG4wgfhhw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2639"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 11 Jan 2011 12:36:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 21 Dec 2010 20:23:19 GMT"
+        },
+        {
+          "age": "57198492"
+        },
+        {
+          "x-amz-cf-id": "KUP-5JnHht-4Vm9AI5uL23vWqItT_PCAoTXYhS67UcTYyHi9H4qomw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "53"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 29 Sep 2012 16:43:06 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 23:12:42 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3010908"
+        },
+        {
+          "x-amz-cf-id": "9nFbAiM9DpxC3cnA__WbfWVECGjZkkgmC6B1r2D6H_pZUeOJpmckKw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1266"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 13 Dec 2011 01:03:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Dec 2011 22:30:22 GMT"
+        },
+        {
+          "age": "28209671"
+        },
+        {
+          "x-amz-cf-id": "4XS4NQ5jtAPsXr8uz5LSIhit3YaYLOacfgxTqaJdmgGUSVeVX3L52w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "549"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 17 Sep 2012 06:10:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 04:41:18 GMT"
+        },
+        {
+          "age": "4085653"
+        },
+        {
+          "x-amz-cf-id": "8cM2EbSq2xMoZmAuqaRNnHUXo5fFEkwP993iO66WXR8cQhYdXav_-A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2309"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 00:31:48 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 23:01:43 GMT"
+        },
+        {
+          "age": "1081986"
+        },
+        {
+          "x-amz-cf-id": "I_rWsREl-5AOAKtcn3LicFnMAMonpKIxSr1BGia7JpyGrtD-VJlFAw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4689"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 10 Oct 2012 00:37:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 15 Jul 2011 19:43:59 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2118462"
+        },
+        {
+          "x-amz-cf-id": "zJr0j4xcaVnqbt7keScwtlVcaVTMpKQyOnG62dfi3bC2Yn7ZUU8hmQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "304"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 24 Aug 2012 23:48:39 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Jul 2008 22:54:46 GMT"
+        },
+        {
+          "age": "6095775"
+        },
+        {
+          "x-amz-cf-id": "PKmkuepDkCjjY62A77yQuYuUte5c2Ty-_6DlKmAvhcwzRsHyn5nIrQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "3183"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 03:20:41 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:20:32 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3231853"
+        },
+        {
+          "x-amz-cf-id": "OwAw73zfegmW_QHY-kswWa1c-b8oV4xZ-5eevFXbZxfqoKPE6umE4Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "859"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 15:34:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 07:35:03 GMT"
+        },
+        {
+          "age": "163828"
+        },
+        {
+          "x-amz-cf-id": "lfeQCmQ-LTseaf2mLmw-Ec-MgECRsFNyDab6oODONovNp3KBwaWuNQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "904"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 15:34:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 21 Apr 2011 09:50:08 GMT"
+        },
+        {
+          "age": "163828"
+        },
+        {
+          "x-amz-cf-id": "fx4kuYG47HcKaHNWoFHoUpVuQ9sWagCnJ3Kox-WAsGeI9bLRuIFkZA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "988"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 15:34:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 11 Apr 2012 09:49:52 GMT"
+        },
+        {
+          "age": "163828"
+        },
+        {
+          "x-amz-cf-id": "pdz_b69t7pq2FxRxED3J9qfLWu_VlLnSgt3UkrYI2IsWgh0cxAcbRg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "7477"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 13:03:42 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:06:13 GMT"
+        },
+        {
+          "age": "1296072"
+        },
+        {
+          "x-amz-cf-id": "IpXkwhJGWUHRMnyRAQVIxqffI1_ZEyW-nzUYrSWrfr8R_Y1uuGRCCQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "702"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 14 Sep 2012 15:53:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 12 Oct 2011 01:31:30 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "4309888"
+        },
+        {
+          "x-amz-cf-id": "HsG6bJczHwzkieHglmFzE2QCmzLxTaLPXXnAy-N55tzbuvrtZRCzCw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "7983"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 12:29:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 15 Jul 2011 19:44:12 GMT"
+        },
+        {
+          "age": "1298127"
+        },
+        {
+          "x-amz-cf-id": "sCXON_3fv6WubL7uLSJaIqpVlCgjIetJyv1h_hMdF4cY17dhW5AtuQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "21587"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 07:42:49 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 18:42:30 GMT"
+        },
+        {
+          "age": "1315325"
+        },
+        {
+          "x-amz-cf-id": "T9aSuzcFAaMOSl0BfGK1RZtk2bHJRFveb6whI8ExXPmes7P1gEIr_g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "14808"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 14 Sep 2012 19:42:20 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sat, 02 Jun 2012 16:25:51 GMT"
+        },
+        {
+          "age": "4296154"
+        },
+        {
+          "x-amz-cf-id": "0V2zXn_NrH1y0_eQiJhavI_iThDjEBl3W8rbz6WK2bL14yhUFFMzMg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "929"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 15:34:26 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sun, 20 Jun 2010 09:46:10 GMT"
+        },
+        {
+          "age": "163828"
+        },
+        {
+          "x-amz-cf-id": "kSSVSJhWVu77d7bZr26ow7tGxAtxQIJKxzBSnMTb-BvsXBOXCVvmrQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "170"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "246"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "A8pOeFTyzWm76hXU6FfLkQf4c9wZCOf1QF9R4TGkjXEInQJp6farkkg0WB0HfwcK"
+        },
+        {
+          "x-amz-request-id": "4B032A9637D718D5"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "x-amz-meta-jets3t-original-file-date-iso8601": "2011-11-08T18:38:37.000Z"
+        },
+        {
+          "x-amz-meta-md5-hash": "abb0183baa0ea995b47dcc0e9972095a"
+        },
+        {
+          "cache-control": "max-age=864000"
+        },
+        {
+          "last-modified": "Thu, 30 Aug 2012 18:02:23 GMT"
+        },
+        {
+          "etag": "\"ac923fb65b36b7e6df1b85ed9a2eeb25\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "157082"
+        },
+        {
+          "x-amz-cf-id": "QZJcXJG7Ji8wu-0D789ZbWAnaHnVN-XBUkupFYbHTmHhHcHrJq7P9Q=="
+        },
+        {
+          "via": "1.0 06b38b2ddcbb45c8e33db161a2316149.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "451"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 15:21:37 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=628223582"
+        },
+        {
+          "expires": "Thu, 30 Sep 2032 15:37:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "856"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 04:12:21 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630383568"
+        },
+        {
+          "expires": "Mon, 25 Oct 2032 15:37:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "6979"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 16:08:26 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=629262241"
+        },
+        {
+          "expires": "Tue, 12 Oct 2032 16:08:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "1860"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Mon, 18 May 2009 10:07:44 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=580533835"
+        },
+        {
+          "expires": "Mon, 27 Sep 2032 10:42:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "810"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-lookup": "MISS from cdn-images.amazon.com:10080"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "516"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/ecm3?id=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f&ex=admeld.com"
+        },
+        {
+          "content-length": "275"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "meld_sess=bfd291d0-29a4-4e30-a3a2-90bfcce51d8f;expires=Sun, 05 May 2013 03:59:31 GMT;path=/;domain=tag.admeld.com;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 18:22:05 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 14:49:26 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:49:26 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "25380"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "80128"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR DSP COR\""
+        },
+        {
+          "location": "http://s.amazon-adsystem.com/iu3?d=amazon.com&a1=&a2=0101e39f75aa93465ee8202686e3f52bc2745bcaf2fc55ecfd1eae647167a83ecbb5&old_oo=0&n=1351947870865&dcc=t"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "set-cookie": "ad-privacy=0; Domain=.amazon-adsystem.com; Expires=Thu, 01-Jan-2037 00:00:01 GMT; Path=/"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "57"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 08:55:13 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=628633148"
+        },
+        {
+          "expires": "Tue, 05 Oct 2032 09:24:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "16588"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 11 Apr 2012 19:05:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=617190640"
+        },
+        {
+          "expires": "Tue, 25 May 2032 22:55:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "10742"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 04:46:13 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=621621842"
+        },
+        {
+          "expires": "Fri, 16 Jul 2032 05:48:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:55 GMT"
+        },
+        {
+          "content-length": "3960"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 09:03:20 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=630485970"
+        },
+        {
+          "expires": "Tue, 26 Oct 2032 20:04:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:54 GMT"
+        },
+        {
+          "content-length": "14019"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "16ZMB88V50KWWQXFQZNR"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "0PU9VNtv9/YHthxuwDwGQDz7kHY8GLhrhbQs/A0BbIf1y/GiCONyJttmltEgnDaZ"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "x-amzn-requestid": "10a7eef8-25b7-11e2-a2e0-8bdc8a85b675"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "16KH0V157G0TXXQVTR1Z"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "6Hy72ZQh4+twTqX90DijzRdHDpTv81nJLyxFZMBbjNHkb8qZfDO7y4+75uITFMjm"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2212"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 27 Sep 2012 04:09:18 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 03 Aug 2011 20:37:32 GMT"
+        },
+        {
+          "age": "3228938"
+        },
+        {
+          "x-amz-cf-id": "e_uegUCHnyG0CG1xWLrNCiBH1sC8uTUlb-e31fTCz2013GXiBQpv3g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1658"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 16 May 2012 17:46:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "14757493"
+        },
+        {
+          "x-amz-cf-id": "rjUV7bECb3foXt-4i01sG21mlvMgo9nOu7EtcMeIYzyJSWWqNNlDOw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "16364"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 14 Dec 2011 03:17:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Fri, 04 Nov 2011 23:48:42 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "28115238"
+        },
+        {
+          "x-amz-cf-id": "I6W0oRiMtuRDCDZetJr8DtOxr0nMh8QpK29mcgE2eMGEw69ogMaPdg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 13 Jul 2011 17:18:50 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=616029616"
+        },
+        {
+          "expires": "Wed, 12 May 2032 12:25:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "content-length": "594"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0X3NVRPASEGRWVCHH1H3"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "+dgTelR5Pvj5ApOpupZ5c4EXyGBnWsp/CtTohBqWXrKuiSIBT+ZSU/92HDHIoBxS"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2902"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 27 Oct 2012 23:34:12 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 15:59:40 GMT"
+        },
+        {
+          "age": "567044"
+        },
+        {
+          "x-amz-cf-id": "bYLWczW4h_oqRLXSyZdMo3kjSsqUZNWoGXrVLgvaIVqM8SXrlaPicA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3155"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 26 Jul 2012 09:16:33 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 19 Jul 2012 17:10:12 GMT"
+        },
+        {
+          "age": "8653703"
+        },
+        {
+          "x-amz-cf-id": "pxFBejzs4oRgmqxYc2s6mbS_QBknibmyPLQGd8Ejv-8cWl04HQGPtA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3536"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 27 May 2012 08:44:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 19 May 2011 14:46:28 GMT"
+        },
+        {
+          "age": "13839599"
+        },
+        {
+          "x-amz-cf-id": "vToxkdVmSZQS0V3iRZM-gCcaadczMLYZw_REFYGTBUn-HP5HfdAeDA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3143"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 06 Aug 2012 15:53:39 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 06 Aug 2012 03:38:02 GMT"
+        },
+        {
+          "age": "7679477"
+        },
+        {
+          "x-amz-cf-id": "752wgDaFeaq4IQjicHeqyUiLYIjEjsca-nvc2LB2o4jOXMT99M6E2g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3209"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 28 Feb 2012 22:53:21 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 21 Oct 2010 19:52:40 GMT"
+        },
+        {
+          "age": "21478295"
+        },
+        {
+          "x-amz-cf-id": "UDgO86Lg7vsbRr_HLz0bT_G-fu7CRAkkBmD_NFdclHEzx1CJpRhtKw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3210"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 27 Oct 2012 23:45:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 15:59:43 GMT"
+        },
+        {
+          "age": "566395"
+        },
+        {
+          "x-amz-cf-id": "rEUppa210byJyTItTaRQ2r-jhwUwD4c2CKORz2AGJaLhjCZ_LQ2w9w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:56 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0ESJ91CM6R89TGWH3QJG"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "Mg+wYQrytsBDnHHKyZlGNrkR5GzVMXvkIuJkR86aYslzZP5CJX/EEO5A8c1v2Jk4"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "21282"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 21:09:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 21:09:31 GMT"
+        },
+        {
+          "age": "143714"
+        },
+        {
+          "x-amz-cf-id": "jFqxNpOKI6HWPqTs3raLIRgnJcu3GReFRL3MjibUt9APw7R9CfzNqQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "439"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 19:18:25 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:16:17 GMT"
+        },
+        {
+          "age": "1187193"
+        },
+        {
+          "x-amz-cf-id": "5en8vtO00oTNRx5jsyJYxwuPMEVufg38JPIk7uytbZiFN77vUtBibg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1AB4PH2A91QH3YJJ2WCZ"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "V5wX099kS85XeVk46pZgvH7cjgKx1WawnTJkqYth5ykinf4em6ZqgNlZk9K/lPby"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 05:50:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:16:14 GMT"
+        },
+        {
+          "age": "1062871"
+        },
+        {
+          "x-amz-cf-id": "eIpkgqRGkyaTW4PSLscvrasxuDsM3f4NIrPYv6VI1sZt_IgixOKN_A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "861"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 07:26:29 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Sat, 24 Nov 2007 03:04:01 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "1316309"
+        },
+        {
+          "x-amz-cf-id": "5MBwLvJE3E5vg0khYEnuWX6RGzCOtyfFmYYy2nuztIayL9O0paE0oA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 09:12:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 04 Jun 2010 01:44:17 GMT"
+        },
+        {
+          "age": "964341"
+        },
+        {
+          "x-amz-cf-id": "W5ENbtcrY4pVK3r7ND94JJHXcEjjBccP7Q77zOSiZQUgWtPBn75lHw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1598"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 15:51:07 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:16:29 GMT"
+        },
+        {
+          "age": "1199631"
+        },
+        {
+          "x-amz-cf-id": "nFYTABAConMh8T_fXHANG9_r3FjyUfnSBWjxeb2GqJKtgi_mNRIXMw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1657"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 25 Sep 2012 17:28:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:16:30 GMT"
+        },
+        {
+          "age": "3353768"
+        },
+        {
+          "x-amz-cf-id": "ssIfXXDbBp8rP_142eUVOboNUYX4Iood5RH_Qe9W7wP1xbkZp9MChw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3013"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 28 Nov 2011 22:24:05 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "29428853"
+        },
+        {
+          "x-amz-cf-id": "vO0R09hZC6TnyhMNTV9jEegb2DgNmH-Z1KaQiyeSbsYm8eoBtHUnDw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "455"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "2522"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "dl_s": "a104"
+        },
+        {
+          "x-host": "a104 D=1922"
+        },
+        {
+          "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "558"
+        },
+        {
+          "keep-alive": "timeout=120, max=934"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "dl_s": "a104"
+        },
+        {
+          "x-host": "a103 D=213"
+        },
+        {
+          "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "78"
+        },
+        {
+          "keep-alive": "timeout=120, max=941"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "cache-control": "post-check=0, pre-check=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "PL=_974702-1-83324420; expires=Sun, 03-Nov-2013 13:04:58 GMT; path=/; domain=.questionmarket.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 17:29:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 05:34:15 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 05:34:15 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "27737"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "27043"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "dl_s": "a212"
+        },
+        {
+          "x-host": "a212 D=715"
+        },
+        {
+          "p3p": "CP=\"ALL DSP COR PSAa PSDa OUR IND COM NAV INT LOC OTC\", policyref=\"http://ch.questionmarket.com/w3c/audit2007/p3p_DynamicLogic.xml\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "keep-alive": "timeout=120, max=973"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "cache-control": "post-check=0, pre-check=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "ES=974702-1d5qN-0; expires=Wed, 25-Dec-2013 05:04:58 GMT; path=/; domain=.questionmarket.com;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "x-amzn-requestid": "123b3889-25b7-11e2-8af6-a1b44f97a3ae"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1ZP9F4EGXPG1W1PYCNJK"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "AsL0eWMF3+3wScCyR0bGR31dSLss9n05o3uERrVw6pReE9DgHJ1jKFUl9eThTjRS"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "168BW4BHQH0ZXM7FXMPB"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "cEL12N93+m4WoEqFtPIfCFUi+syrhK4ihYi/vQREHqBRscgh343Rj/z+yvBSU/1C"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:04:58 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1PF1RSF1KPZFT8AG8QH3"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "BMEF9l9idgW7J6L5kAVCmgL1L1VX3ONDIY4c/R7+/waDULftLKfFOhjdf5bX9Jgw"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "76"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 25 Sep 2012 13:31:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 15:53:50 GMT"
+        },
+        {
+          "age": "3367996"
+        },
+        {
+          "x-amz-cf-id": "ecrxOwZyLIYoOI7n1HZdjAnEynOb8rnSjf9oMBvu9l-mcg-DvsQ5tA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2953"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 14 Oct 2012 20:13:59 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2011 23:50:26 GMT"
+        },
+        {
+          "age": "1702260"
+        },
+        {
+          "x-amz-cf-id": "RRnk1cdyHejHw9mprrW3eHhVJDtMgC2-2Z_Ozk1TtfyHQbMGDRM1gQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2908"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 00:29:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT"
+        },
+        {
+          "age": "45358"
+        },
+        {
+          "x-amz-cf-id": "dVVqpxaUvghScp5L3V8knNH7yD0rPX4f2QIUqHQG7hWgDw29J2DGyQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2684"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 29 Oct 2012 09:50:03 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Feb 2010 23:26:50 GMT"
+        },
+        {
+          "age": "443696"
+        },
+        {
+          "x-amz-cf-id": "PlD1_xjVuo-YCz7_Za4wyP6LFVnojIw0t9xjXHByHBqF2ZeqI4b_qg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "879"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 08 Jul 2012 02:35:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT"
+        },
+        {
+          "age": "10232965"
+        },
+        {
+          "x-amz-cf-id": "NFgWbhPAIPS6Aa_OA1MZi4RJV38Eh2JztiuONINXzMa0bG62le6jyA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "829"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 15:46:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:49 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "29366305"
+        },
+        {
+          "x-amz-cf-id": "09OGcA01CtEV2DWxFMbKMdNmD6Wr6zUzXg6LlkVtCG84Y07dTLSY0Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "874"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 17:41:46 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT"
+        },
+        {
+          "age": "1192993"
+        },
+        {
+          "x-amz-cf-id": "rwvtxrU_8yM4vEsn3LxI68PMeCTNAaI2pID_hvPOaXhJAUXpLcUqOQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "839"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 28 Jul 2012 16:53:55 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT"
+        },
+        {
+          "age": "8453464"
+        },
+        {
+          "x-amz-cf-id": "jK_V3T8gBhnVX6aGpizNe84I03zSajHOTGC01MnF2N-ZKUFTuuznfg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "873"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 02 Oct 2012 10:07:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2775429"
+        },
+        {
+          "x-amz-cf-id": "zP8uDh7oW4qGktFpCJQlKyzDvuaUlw8SfQPZeV2OLAF_FolwTs7PYA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "839"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 04 Oct 2012 03:38:14 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:48 GMT"
+        },
+        {
+          "age": "2626005"
+        },
+        {
+          "x-amz-cf-id": "zCUT7P4ddAsA_5EOdXS-ecWSi3Caf1GD9wdw37lzeKfQj2j9AmHUiQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "829"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 18 Feb 2012 00:35:57 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:46 GMT"
+        },
+        {
+          "age": "22422542"
+        },
+        {
+          "x-amz-cf-id": "QKTCegDFqVr3XC8HIuieCb-HlLFpsf1vJJyDKhTn9DFbJiLWVXQjLQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "874"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sun, 29 Jul 2012 00:33:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:47 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "8425881"
+        },
+        {
+          "x-amz-cf-id": "FQmsZuwjmRdgwUM5HxTx27tY2H27QOrbg1DJdNz_RrAOa991o5Lvyw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "1KF6CJF0ZA3T90MCGE8X"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "EhBekXVsIWcz6GtFV9/VWJHMzQoVZUur+CK0EG1dAElJjqTWpGnJuKNs84/dLZ0q"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "394"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 23 Oct 2012 16:46:08 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:46:54 GMT"
+        },
+        {
+          "age": "937134"
+        },
+        {
+          "x-amz-cf-id": "L9oihLkhCsGUlU-3jqFLwWX3TyuBQLcp_cHchbBiCmtUA736X8Kphg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "627"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 11 Oct 2012 14:33:21 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:15:44 GMT"
+        },
+        {
+          "age": "1981901"
+        },
+        {
+          "x-amz-cf-id": "7ml4lF66qQTzIXFECW3ocZ5nG9vHHfuYDmXpdeBjLVSaQQolCys92A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "621"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 10 Oct 2012 11:21:25 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:15:46 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "2079817"
+        },
+        {
+          "x-amz-cf-id": "CoLcmSXF2suFL6QBnOjjLxEUhf72VKlrplyC4RYJlfNREf6-Xi0pXw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2358"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 01:52:38 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "29416344"
+        },
+        {
+          "x-amz-cf-id": "dRi8YsVC5rJM48lwap3Mh06QHVr9w6Oq0Pfg31QRRKiDl1QSIT3zdg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1594"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 10:14:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:15:59 GMT"
+        },
+        {
+          "age": "1219843"
+        },
+        {
+          "x-amz-cf-id": "1biuu9U97pslYVYAmMFhrwSwOBYVwXiLgwm1MRKI7_h7l2zmYZZEaQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 26 Sep 2012 22:18:37 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 25 Sep 2012 20:26:21 GMT"
+        },
+        {
+          "age": "3249985"
+        },
+        {
+          "x-amz-cf-id": "fX317kpOFNd5ZTVD5dUMrmSEeYRzqm4WpyDuKNG28yJ4O9eAvvazUw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1061"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 19 Oct 2012 11:04:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:18:05 GMT"
+        },
+        {
+          "age": "1303243"
+        },
+        {
+          "x-amz-cf-id": "mAtXqkAkC4DjophBzYEW5S6QprX5KyDZpPzyK9EozCLiukdFrBze5A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "850"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 19 Nov 2011 02:02:32 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:12:52 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "30279750"
+        },
+        {
+          "x-amz-cf-id": "V9zouqOby7zTdw8N1UFD-7MjNT6Is1zC6qGyOi0cvSwTqMJZ1Qkygw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2561"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 01:47:15 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "1077467"
+        },
+        {
+          "x-amz-cf-id": "S275mzRyfiEZwFTcPfyW0eoYH91UX_599Ev_ECgM6b_xOLfjspcbHg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "564"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 11:54:46 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 04 Jun 2010 01:27:32 GMT"
+        },
+        {
+          "age": "29380216"
+        },
+        {
+          "x-amz-cf-id": "R7S8on0vdk1HXxrim-2c2Zh8aNdO6mf4C0WS3tKHegaM2jWsiM5epQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1698"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 12:21:20 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:03:45 GMT"
+        },
+        {
+          "age": "29378622"
+        },
+        {
+          "x-amz-cf-id": "YvMqD5UqqFKzy1f2mFcHqX7aM_4HxOmRkYus-RhWfCdy_pqhPAEz_g=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "558"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 11:34:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Fri, 04 Jun 2010 01:27:17 GMT"
+        },
+        {
+          "age": "1215028"
+        },
+        {
+          "x-amz-cf-id": "cVa44QM2u8IAuUF9QEfpfnoTg8a0J18iQn7wd2DQr-jo-fY8BpiHkQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2268"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 28 Jul 2012 02:30:22 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:00:18 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "8505280"
+        },
+        {
+          "x-amz-cf-id": "22Ju-KfgdJeRvZSlX5DsdLObbhPEZeBSd4Gc72ZIaWMiVqmbMkB3Bg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "161"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 25 Sep 2012 20:28:46 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:15:25 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "3342976"
+        },
+        {
+          "x-amz-cf-id": "qmBPDk2JKVaJRpv7A4mhguHOgSAQ224UfofPNOhYc7AXsZ28LFXM-Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1567"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 29 Sep 2012 12:18:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:14:03 GMT"
+        },
+        {
+          "age": "3026779"
+        },
+        {
+          "x-amz-cf-id": "9apayreRLqLNv5SP9KNS5EuSvY5sPVDHoDgblKHgUdkUCoUDFfPCbw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2075"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 08 Feb 2012 03:25:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:19:09 GMT"
+        },
+        {
+          "age": "23276352"
+        },
+        {
+          "x-amz-cf-id": "x7eg4fYYkTWpaWFE4nN7BtaqRyiZfNva-voci7p3Xzbfipq19svpKQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1703"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 29 Nov 2011 09:32:04 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:14:39 GMT"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "age": "29388778"
+        },
+        {
+          "x-amz-cf-id": "Sud7TM_0UEovovJxWwSbgeoYTXcAYAv14GhdR63hJZOjeBUYsvtKqQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"01-XuHrwcHL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2601"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 25 Jul 2012 12:53:34 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:17:36 GMT"
+        },
+        {
+          "age": "8727088"
+        },
+        {
+          "x-amz-cf-id": "mAk0OO6evBoCPjFxnJqirH_8vom2gwHEBysCZcqQfQejl1rp3OGD1Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1581"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 11:57:50 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:13:01 GMT"
+        },
+        {
+          "age": "1040832"
+        },
+        {
+          "x-amz-cf-id": "Dib_HmcmgtWNGzNtGv3F6ZAXixIagykEiamEBmt2obULi0G_yrbohw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "etag": "\"01+KP3cIDVL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "44"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 20 Oct 2012 02:45:35 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 16:13:49 GMT"
+        },
+        {
+          "age": "1246767"
+        },
+        {
+          "x-amz-cf-id": "wjm3efkQaATVWVoZIxXYwJ9h7_UJVQWBeywk_XevnjWO-aG5dXU1uw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Thu, 12 Mar 2009 22:20:15 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613385389"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 21:54:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:02 GMT"
+        },
+        {
+          "content-length": "1167"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"11Z3ZviGhqL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:02 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0N0ET7DXR0Z0S958XDT2"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "rVbwKM7uj9c8KPLYmRAVt4kYRdMGzqE9h6Tyc+UcXD6y0h6n5t1Qps2dG4l0erjn"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1419"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 21 Nov 2011 14:19:01 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:29 GMT"
+        },
+        {
+          "age": "30062762"
+        },
+        {
+          "x-amz-cf-id": "V720Rh4VXwLpavgc0gzogCAvcfu8eju-6aTUgkZ0KVqt2Dmee6LRbA=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3603"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 06:00:11 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Apr 2010 23:10:58 GMT"
+        },
+        {
+          "age": "25492"
+        },
+        {
+          "x-amz-cf-id": "fQb0nipMtXJuYbIZySKBDRsrklJuv7qAkK8XsAxNdlaxuu3_Nb882A=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "610"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 10 Oct 2012 05:09:08 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 01:30:08 GMT"
+        },
+        {
+          "age": "2102155"
+        },
+        {
+          "x-amz-cf-id": "CaXyn6Of0tMpboI2JSReSog7OZegmXSk2HeG_0TZ-GXKneON61wt4Q=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"11+dlfeUrBL#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6063"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 28 Sep 2010 14:19:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Sun, 23 May 2010 07:31:32 GMT"
+        },
+        {
+          "age": "66264320"
+        },
+        {
+          "x-amz-cf-id": "Xi5psl_5u_FA8F_cxp1Bgg5JQqekzjzXubyxkq6OioH5vJa_xpl7bg=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3808"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Mon, 23 Jan 2012 20:55:29 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 28 Sep 2011 08:02:37 GMT"
+        },
+        {
+          "age": "24595774"
+        },
+        {
+          "x-amz-cf-id": "YCExo8QCW6i8b43rK1WKdbqGi4BBr67tDQvHKeByUOjFZWkYcGmSVw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4743"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Thu, 16 Feb 2012 18:43:39 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 21 Nov 2011 14:13:47 GMT"
+        },
+        {
+          "age": "22530084"
+        },
+        {
+          "x-amz-cf-id": "f-ZNWJJlfQWW0yKzQd7uCRUJaMBxf_uM7iH1fbKBNdQQggwy-fMhMQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5433"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 10 Apr 2012 03:22:11 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 15 Feb 2012 16:43:09 GMT"
+        },
+        {
+          "age": "17919772"
+        },
+        {
+          "x-amz-cf-id": "d_if579P0cd1V3nzUXiXXtDTylQLMz1X-zUPk2ry79G_nUYX-N0rAQ=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4449"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Fri, 23 Mar 2012 00:45:43 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "etag": "\"41YZLkI+UsL_SL135_#1\""
+        },
+        {
+          "last-modified": "Fri, 09 Sep 2011 07:00:28 GMT"
+        },
+        {
+          "age": "19484360"
+        },
+        {
+          "x-amz-cf-id": "XHbZSMpsPMFYPGHelyqQvYo133-6UF8nzLJrfmuubfb8md_c3wKN8w=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4065"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Tue, 25 Sep 2012 13:07:27 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Feb 2010 16:43:55 GMT"
+        },
+        {
+          "age": "3369456"
+        },
+        {
+          "x-amz-cf-id": "cqvYtZEgzgfwS7oAvqOkuzRizhSe9arLcRGaP5nnF2izwecHSwS-Cw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"31-ris0UMaL_SL500_SS100_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4778"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Wed, 14 Sep 2011 17:50:19 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "cache-control": "max-age=630720000,public"
+        },
+        {
+          "expires": "Wed, 18 May 2033 03:33:20 GMT"
+        },
+        {
+          "last-modified": "Mon, 24 Aug 2009 16:48:22 GMT"
+        },
+        {
+          "age": "35925284"
+        },
+        {
+          "x-amz-cf-id": "wXY9DDbUrHJoSYufMPmtErRRutYkp32cOy1b07_NcZFdUScDaLORpw=="
+        },
+        {
+          "via": "1.0 e0361d2450a4995d92d661bf6b825ede.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        },
+        {
+          "etag": "\"41+6XVdi5mL_SX36_SY36_CR,0,0,36,36_#1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "last-modified": "Wed, 22 Sep 2010 23:59:48 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=613358641"
+        },
+        {
+          "expires": "Sun, 11 Apr 2032 14:29:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:02 GMT"
+        },
+        {
+          "content-length": "22760"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:03 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0M6TJE3FZYTXRNRY512Y"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "uk/tDjh11RBjIvdv0Gj9JUCG/M9iirulGzM8OhRvjW/qch4hPreEf7n4VnzczAr6"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:05:03 GMT"
+        },
+        {
+          "server": "Server"
+        },
+        {
+          "x-amz-id-1": "0DNVGFVH4CF96QBN4TM9"
+        },
+        {
+          "p3p": "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \""
+        },
+        {
+          "x-amz-id-2": "vE+1ySfLV/mErY5cd7s2NdxUOOOUvbYCVUyYCdjxcxbN3eyQRj3PwWhhDk9+xh+Q"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "session-id=178-5926262-3769435; path=/; domain=.amazon.com; expires=Tue, 01-Jan-2036 08:00:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_22.json b/jetty-http2/http2-hpack/src/test/resources/data/story_22.json
new file mode 100644
index 0000000..a2d7031
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_22.json
@@ -0,0 +1,14947 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:56:30 GMT"
+        },
+        {
+          "last-modified": "Tue, 12 Jan 2010 13:48:00 GMT"
+        },
+        {
+          "etag": "\"51-4b4c7d90\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "81"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:56:30 GMT"
+        },
+        {
+          "last-modified": "Mon, 24 Jan 2011 11:52:00 GMT"
+        },
+        {
+          "etag": "\"13e-4d3d67e0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "318"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/plain"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:32 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-length": "4034"
+        },
+        {
+          "content-type": "text/html;charset=gbk"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 12:56:32 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "set-cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1; expires=Sat, 03-Nov-42 12:56:32 GMT; path=/; domain=.baidu.com"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:32 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 20 Jan 2011 07:15:35 GMT"
+        },
+        {
+          "etag": "\"65e-49a41e65933c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1630"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:32 GMT"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:32 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 19 Apr 2012 09:51:20 GMT"
+        },
+        {
+          "etag": "\"5b-4be051d263600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "91"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:32 GMT"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "set-cookie": "BAIDUID=94A36D239683687B3C92793A22BA0C93:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1"
+        },
+        {
+          "last-modified": "Thu, 11 Aug 2011 07:44:31 GMT"
+        },
+        {
+          "etag": "\"57d9-4aa35f79b95c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:33 GMT"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8000"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "set-cookie": "BAIDUID=129ADB92B43CFC527CA7FB93BCB8AB88:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 06:54:50 GMT"
+        },
+        {
+          "etag": "\"5555-4cd7d9cac8280\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:33 GMT"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7499"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "set-cookie": "BAIDUID=CC2AAA2AE3AF303A945CAF8E9945BC2D:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1"
+        },
+        {
+          "last-modified": "Thu, 20 Sep 2012 04:32:55 GMT"
+        },
+        {
+          "etag": "\"26fa-4ca1a9df6cbc0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:33 GMT"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3586"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:33 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "set-cookie": "BAIDUID=6C1D358E43AAD143080C18E498033F71:FG=1; expires=Sun, 03-Nov-13 12:56:33 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1"
+        },
+        {
+          "last-modified": "Thu, 30 Jun 2011 10:56:51 GMT"
+        },
+        {
+          "etag": "\"25f-4a6ebc21c42c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "607"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "expires": "Tue, 01 Nov 2022 12:56:33 GMT"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/png"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:34 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "147"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 12:56:32 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "set-cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1; expires=Sat, 03-Nov-42 12:56:32 GMT; path=/; domain=.baidu.com"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "last-modified": "Mon, 24 Jan 2011 11:52:05 GMT"
+        },
+        {
+          "etag": "\"13e-49a963a8e0340\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 12:56:39 GMT"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:39 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"2880337125\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "795"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"1970946457\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 21 Aug 2012 12:19:47 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"3508231446\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Wed, 12 Sep 2012 06:59:30 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "4465"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "5928"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "etag": "\"3116325809147476198\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 02:09:15 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:07:33 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "10550"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "etag": "\"13813589230791420108\""
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 10:53:47 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 06:05:04 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "etag": "\"991580451\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:07:04 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11081"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"2826587238\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 06:59:28 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:41 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "1803"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"2820264983\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 02:45:17 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:41 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "3703"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"779014302\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Mon, 06 Aug 2012 10:17:50 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:41 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "2053"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"439052966\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "38609"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1503293558\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:41 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13174"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:41 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"790245820\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:07:03 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:40 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "33536"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:40 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1136345403\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 17:08:02 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "3731"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1881822353\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 15:28:36 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1007"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"55301462\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 19 Oct 2012 15:59:17 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2179"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"2082195828\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 18 Jan 2011 06:39:02 GMT"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"2082195828\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 18 Jan 2011 06:39:02 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"1129043035\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 19 Oct 2012 15:58:50 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1962"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "1076"
+        },
+        {
+          "etag": "\"2330871933\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 03:17:42 GMT"
+        },
+        {
+          "expires": "Sat, 12 Jan 2013 11:31:05 GMT"
+        },
+        {
+          "cache-control": "max-age=15552000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"2084456863\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 18 Jan 2011 03:02:19 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:43 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:43 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:44 GMT"
+        },
+        {
+          "server": "ECOM Apache 1.0.13.0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"1905870111\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Wed, 18 Nov 2009 09:44:09 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 12:56:44 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:44 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.15"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:18 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "No-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "set-cookie": "JSESSIONID=24206446514B3C020AC50919B9330503; Path=/"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "x-powered-by": "PHP/5.2.3"
+        },
+        {
+          "cache-control": "max-age=259200"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 12:56:46 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "set-cookie": "loc=1%7C%B1%B1%BE%A9%7C%B1%B1%BE%A9; expires=Tue, 06-Nov-2012 12:56:46 GMT; path=/; domain=.hao123.com"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "684"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:46 GMT"
+        },
+        {
+          "server": "lighttpd"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "media": "media"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 12:24:13 GMT"
+        },
+        {
+          "last-modified": "Sat, 25 Apr 2009 07:04:00 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:46 GMT"
+        },
+        {
+          "server": "apache"
+        },
+        {
+          "content-length": "8992"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:47 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 10:00:20 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:26:47 GMT"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "set-cookie": "id58=05eNElCVFI9c8Hfk16UMAg==; expires=Tue, 01-Nov-22 12:56:47 GMT; domain=58.com; path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"CUR ADM OUR NOR STA NID\""
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1840151033\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:47 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4959"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:47 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1236171233\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 14 Feb 2012 03:23:36 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:47 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4571"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:47 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "BAIDUID=7B3F07DA7EB7581C6AAAAC2399C0F469:FG=1; max-age=31536000; expires=Sun, 03-Nov-13 12:56:39 GMT; domain=.hao123.com; path=/; version=1"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 12:56:47 GMT"
+        },
+        {
+          "cache-control": "max-age=31104000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:47 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "etag": "\"567172269\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 01 Mar 2012 02:31:58 GMT"
+        },
+        {
+          "content-length": "1150"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:54:27 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "last-modified": "Thu, 16 Aug 2012 08:37:54 GMT"
+        },
+        {
+          "cache-control": "max-age=300"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 bjgm232:8102 (Cdn Cache Server V2.0), 1.1 stsz70:8105 (Cdn Cache Server V2.0), 1.1 gdyf13:9080 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 04:02:33 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "22332"
+        },
+        {
+          "last-modified": "Mon, 25 Apr 2011 10:41:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 gm240:8104 (Cdn Cache Server V2.0), 1.1 stcz163:8106 (Cdn Cache Server V2.0), 1.1 gdyf13:8184 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 12:49:31 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "9309"
+        },
+        {
+          "last-modified": "Mon, 25 Apr 2011 08:07:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 gm243:8106 (Cdn Cache Server V2.0), 1.1 stsz75:8104 (Cdn Cache Server V2.0), 1.1 gdyf16:9080 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.2.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:49 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 16 Aug 2012 08:37:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 12:49:31 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "23163"
+        },
+        {
+          "last-modified": "Mon, 25 Apr 2011 10:46:11 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 gm240:8101 (Cdn Cache Server V2.0), 1.1 stsz74:8080 (Cdn Cache Server V2.0), 1.1 gdyf17:8184 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Fri, 26 Oct 2012 12:49:21 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "281"
+        },
+        {
+          "last-modified": "Mon, 25 Apr 2011 08:07:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 gm239:8102 (Cdn Cache Server V2.0), 1.1 stsz70:88 (Cdn Cache Server V2.0), 1.1 gdyf20:8184 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 04:29:06 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "183"
+        },
+        {
+          "last-modified": "Wed, 11 Jan 2012 07:50:38 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 tjtg100:80 (Cdn Cache Server V2.0), 1.1 gm240:8106 (Cdn Cache Server V2.0), 1.1 stsz75:8107 (Cdn Cache Server V2.0), 1.1 gdyf18:8360 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:50 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Sun, 24 Apr 2011 02:10:42 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:26:50 GMT"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "set-cookie": "id58=05eNElCVFI9c8Hfk16UMAg==; expires=Tue, 01-Nov-22 12:56:47 GMT; domain=58.com; path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"CUR ADM OUR NOR STA NID\""
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.2.3"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:50 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 03:32:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 18 Oct 2012 03:17:25 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "11545"
+        },
+        {
+          "last-modified": "Mon, 25 Apr 2011 09:08:36 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "x-via": "1.1 gm240:8107 (Cdn Cache Server V2.0), 1.1 stcz158:8104 (Cdn Cache Server V2.0), 1.1 gdyf16:8184 (Cdn Cache Server V2.0)"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:51 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34115693691177833738110320"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.15"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:24 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "No-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "set-cookie": "JSESSIONID=24206446514B3C020AC50919B9330503; Path=/"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "W/\"4286-1337327987000\""
+        },
+        {
+          "last-modified": "Fri, 18 May 2012 07:59:47 GMT"
+        },
+        {
+          "content-length": "4286"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "5352"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "etag": "\"3854054371452794933\""
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 07:42:36 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 07:18:44 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "20557"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 01:59:00 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"1496242645\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "content-length": "1574"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "13644"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:33:51 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "8122"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 06:49:50 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:51 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:28:20 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "19956"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:36:26 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:23:32 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4240"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"464442779\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "content-length": "231"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"531551641\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Sun, 15 Aug 2010 16:00:00 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "content-length": "339"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "server": "ECOM Apache 1.0.13.0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "7748"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:02:59 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34115693691177833738110320"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "29476"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:31:40 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 05:21:05 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7301"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "7993"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 07:14:19 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "last-modified": "Thu, 14 Oct 2010 10:10:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 29 Oct 2010 06:30:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "35637"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 04:22:40 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34115693691177833738110320"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "4997"
+        },
+        {
+          "last-modified": "Thu, 21 Jun 2012 03:57:37 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 29 Jun 2012 10:13:16 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2267"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1480"
+        },
+        {
+          "last-modified": "Mon, 21 May 2012 07:58:06 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "8922"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 03:21:07 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "etag": "\"4172175030\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 10:48:27 GMT"
+        },
+        {
+          "content-length": "9393"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "9294"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:16:26 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "40299"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 04:07:00 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8579"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "18605"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34115693691177833738110320"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "20099"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "18865"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "20123"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "location": "http://msg.baidu.com/msg/msg_dataGetmsgCount?from=msg"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "206"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "17869"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "18072"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "21328"
+        },
+        {
+          "last-modified": "Wed, 19 Jan 2011 09:16:11 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1481"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "220"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "etag": "\"3965408141\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 06:54:58 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:52 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "content-length": "39993"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:52 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "11279"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:44 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "22384"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBAUID=cb23caae14130a0d384a57f1; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34115693691177833738110320"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "20962"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "61444"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 07:13:16 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:54 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "17732"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 09:16:23 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 12:58:13 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:53 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:53 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 11 Oct 2011 07:38:09 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "999"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "3949"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 06:36:50 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1158"
+        },
+        {
+          "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1008"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 08:26:17 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3059"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "text/html; charset=GBK"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "TIEBA_USERTYPE=7a2a671a262b15b7e6f4819b; expires=Thu, 31-Dec-2020 15:59:59 GMT; path=/; domain=tieba.baidu.com"
+        },
+        {
+          "location": "http://tieba.baidu.com/index.html"
+        },
+        {
+          "tracecode": "34173872330388372234110320"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-length": "20962"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:36:43 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:54 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "text/html; charset=GBK"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1158"
+        },
+        {
+          "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34176809970478157322110320"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "607"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2921"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2832"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3059"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2801"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2923"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "20220"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 07:56:05 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2830"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2877"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2967"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "177"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "text/html; charset=GBK"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1158"
+        },
+        {
+          "last-modified": "Mon, 03 Sep 2012 03:47:57 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:57 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34180192590438703882110320"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "7067"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:12:51 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "288"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "8236"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:13:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2842"
+        },
+        {
+          "last-modified": "Tue, 17 May 2011 06:39:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:59 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"4291424757\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 21 Jun 2012 08:04:46 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:59 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3558"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "etag": "\"4232694198\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 21 Jun 2012 08:04:45 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:59 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10901"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=44849399"
+        },
+        {
+          "expires": "Sun, 06 Apr 2014 15:06:58 GMT"
+        },
+        {
+          "last-modified": "Thu, 31 Dec 2009 08:37:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=40280084"
+        },
+        {
+          "expires": "Wed, 12 Feb 2014 17:51:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 16 Apr 2010 03:07:31 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12713623"
+        },
+        {
+          "expires": "Sat, 30 Mar 2013 16:30:42 GMT"
+        },
+        {
+          "last-modified": "Sat, 14 Jan 2012 05:49:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=33539862"
+        },
+        {
+          "expires": "Tue, 26 Nov 2013 17:34:41 GMT"
+        },
+        {
+          "last-modified": "Sun, 19 Sep 2010 03:41:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4405195"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 12:36:54 GMT"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 13:37:09 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "media": "media"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 12:24:13 GMT"
+        },
+        {
+          "last-modified": "Sat, 25 Apr 2009 07:04:00 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:58 GMT"
+        },
+        {
+          "server": "apache"
+        },
+        {
+          "content-length": "27159"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"2269828500\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 24 Aug 2010 14:26:41 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:59 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "571"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=25111771"
+        },
+        {
+          "expires": "Wed, 21 Aug 2013 04:26:30 GMT"
+        },
+        {
+          "last-modified": "Sat, 02 Apr 2011 05:57:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9297121"
+        },
+        {
+          "expires": "Tue, 19 Feb 2013 03:29:00 GMT"
+        },
+        {
+          "last-modified": "Mon, 02 Apr 2012 07:52:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=41820075"
+        },
+        {
+          "expires": "Sun, 02 Mar 2014 13:38:14 GMT"
+        },
+        {
+          "last-modified": "Thu, 11 Mar 2010 11:34:29 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10209204"
+        },
+        {
+          "expires": "Fri, 01 Mar 2013 16:50:23 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Mar 2012 05:10:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "etag": "eab7a0d6b87c3b4ed2c270c0380dbf29"
+        },
+        {
+          "cache-control": "max-age=0, must-revalidate"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "set-cookie": "HMACCOUNT=0F8500D919421ADB; Path=/; Domain=hm.baidu.com; Expires=Sun, 18 Jan 2038 00:00:00 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "5779"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=8515483"
+        },
+        {
+          "expires": "Sun, 10 Feb 2013 02:21:42 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 10:07:32 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, max-age=0, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:00 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:00 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1158"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:00 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34180192590438703882110320"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:00 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "1158"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:00 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34180192590438703882110320"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:00 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "3949"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 12:11:36 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:00 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "BAIDUID=53B0A4069A29BECD16EF519984CCA005:FG=1; max-age=946080000; expires=Mon, 27-Oct-42 12:57:02 GMT; domain=.baidu.com; path=/; version=1"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"1698673572\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:49:58 GMT"
+        },
+        {
+          "expires": "Fri, 01 Feb 2013 12:57:02 GMT"
+        },
+        {
+          "cache-control": "max-age=7776000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "502"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:02 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "BAIDUID=53B0A4069A29BECDD09DC829CEEA31EE:FG=1; max-age=946080000; expires=Mon, 27-Oct-42 12:57:02 GMT; domain=.baidu.com; path=/; version=1"
+        },
+        {
+          "p3p": "CP=\" OTI DSP COR IVA OUR IND COM \""
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"2769205800\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:49:58 GMT"
+        },
+        {
+          "expires": "Fri, 01 Feb 2013 12:57:02 GMT"
+        },
+        {
+          "cache-control": "max-age=7776000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3712"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:02 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"1610142698\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 21 Jun 2012 08:04:47 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:56:59 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "158920"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:56:59 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:04 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "2550"
+        },
+        {
+          "last-modified": "Tue, 30 Mar 2010 09:25:50 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:04 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34180192590438703882110320"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:07 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:11:42 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:56:58 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"1905870111\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Wed, 18 Nov 2009 09:44:09 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 12:57:07 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:07 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, max-age=0, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:07 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:21:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "787"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-length": "2550"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=14920916"
+        },
+        {
+          "expires": "Thu, 25 Apr 2013 05:39:04 GMT"
+        },
+        {
+          "last-modified": "Thu, 24 Nov 2011 03:33:15 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=20272763"
+        },
+        {
+          "expires": "Wed, 26 Jun 2013 04:16:31 GMT"
+        },
+        {
+          "last-modified": "Sat, 23 Jul 2011 06:18:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3386843"
+        },
+        {
+          "expires": "Wed, 12 Dec 2012 17:44:31 GMT"
+        },
+        {
+          "last-modified": "Fri, 17 Aug 2012 03:22:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=319801"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 05:47:09 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 03:17:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "etag": "\"2813066485\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 12 Aug 2010 08:49:52 GMT"
+        },
+        {
+          "expires": "Mon, 12 Sep 2022 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=311040000"
+        },
+        {
+          "content-length": "1490"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4715"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5848"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Thu, 29 Mar 2012 08:20:20 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1173183"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 02:50:11 GMT"
+        },
+        {
+          "last-modified": "Sun, 07 Oct 2012 09:11:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=131604"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 01:30:32 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 11:50:19 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=305486"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 01:48:34 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 11:14:16 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10106809"
+        },
+        {
+          "expires": "Thu, 28 Feb 2013 12:23:57 GMT"
+        },
+        {
+          "last-modified": "Wed, 14 Mar 2012 14:03:29 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=11660411"
+        },
+        {
+          "expires": "Mon, 18 Mar 2013 11:57:19 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Feb 2012 14:56:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1356978"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 05:53:26 GMT"
+        },
+        {
+          "last-modified": "Wed, 03 Oct 2012 03:04:31 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10204165"
+        },
+        {
+          "expires": "Fri, 01 Mar 2013 15:26:33 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Mar 2012 07:58:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9726906"
+        },
+        {
+          "expires": "Sun, 24 Feb 2013 02:52:14 GMT"
+        },
+        {
+          "last-modified": "Fri, 23 Mar 2012 09:06:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2265452"
+        },
+        {
+          "expires": "Thu, 29 Nov 2012 18:14:40 GMT"
+        },
+        {
+          "last-modified": "Wed, 12 Sep 2012 02:22:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "8761"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5828"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "6430"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6892"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "4639"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:10:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "853"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6834284"
+        },
+        {
+          "expires": "Mon, 21 Jan 2013 15:21:52 GMT"
+        },
+        {
+          "last-modified": "Tue, 29 May 2012 08:07:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=8117075"
+        },
+        {
+          "expires": "Tue, 05 Feb 2013 11:41:43 GMT"
+        },
+        {
+          "last-modified": "Sun, 29 Apr 2012 15:27:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6108255"
+        },
+        {
+          "expires": "Sun, 13 Jan 2013 05:41:23 GMT"
+        },
+        {
+          "last-modified": "Fri, 15 Jun 2012 03:28:38 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2157496"
+        },
+        {
+          "expires": "Wed, 28 Nov 2012 12:15:24 GMT"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 14:20:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7406109"
+        },
+        {
+          "expires": "Mon, 28 Jan 2013 06:12:17 GMT"
+        },
+        {
+          "last-modified": "Wed, 16 May 2012 02:26:49 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5979956"
+        },
+        {
+          "expires": "Fri, 11 Jan 2013 18:03:04 GMT"
+        },
+        {
+          "last-modified": "Mon, 18 Jun 2012 02:45:15 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12913110"
+        },
+        {
+          "expires": "Mon, 01 Apr 2013 23:55:38 GMT"
+        },
+        {
+          "last-modified": "Mon, 09 Jan 2012 15:00:07 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "4639"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:08 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3673"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "834"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:10:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5828"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "586"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "581"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5746593"
+        },
+        {
+          "expires": "Wed, 09 Jan 2013 01:13:42 GMT"
+        },
+        {
+          "last-modified": "Sat, 23 Jun 2012 12:24:03 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4420208"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 16:47:17 GMT"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 05:16:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "text/html; charset=GBK"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "2550"
+        },
+        {
+          "last-modified": "Tue, 30 Mar 2010 09:25:50 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:04 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34277428450405149450110320"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=750933"
+        },
+        {
+          "expires": "Mon, 12 Nov 2012 05:32:42 GMT"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 03:46:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=31704989"
+        },
+        {
+          "expires": "Tue, 05 Nov 2013 11:53:37 GMT"
+        },
+        {
+          "last-modified": "Sun, 31 Oct 2010 15:04:09 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2436757"
+        },
+        {
+          "expires": "Sat, 01 Dec 2012 17:49:46 GMT"
+        },
+        {
+          "last-modified": "Sat, 08 Sep 2012 03:11:54 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=108530"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 19:05:59 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 00:39:29 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=519223"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 13:10:52 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:29:43 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3860382"
+        },
+        {
+          "expires": "Tue, 18 Dec 2012 05:16:51 GMT"
+        },
+        {
+          "last-modified": "Mon, 06 Aug 2012 04:17:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:21:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2820"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "618"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "572"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9498052"
+        },
+        {
+          "expires": "Thu, 21 Feb 2013 11:18:01 GMT"
+        },
+        {
+          "last-modified": "Wed, 28 Mar 2012 16:15:24 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4541952"
+        },
+        {
+          "expires": "Wed, 26 Dec 2012 02:36:21 GMT"
+        },
+        {
+          "last-modified": "Sat, 21 Jul 2012 09:38:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4854455"
+        },
+        {
+          "expires": "Sat, 29 Dec 2012 17:24:44 GMT"
+        },
+        {
+          "last-modified": "Sat, 14 Jul 2012 04:01:58 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=217395"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 01:20:24 GMT"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 12:10:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=606214"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:20:43 GMT"
+        },
+        {
+          "last-modified": "Sat, 20 Oct 2012 12:10:00 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10024120"
+        },
+        {
+          "expires": "Wed, 27 Feb 2013 13:25:49 GMT"
+        },
+        {
+          "last-modified": "Fri, 16 Mar 2012 11:59:49 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4573190"
+        },
+        {
+          "expires": "Wed, 26 Dec 2012 11:16:59 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 16:17:28 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=8773628"
+        },
+        {
+          "expires": "Wed, 13 Feb 2013 02:04:17 GMT"
+        },
+        {
+          "last-modified": "Sat, 14 Apr 2012 10:42:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "10566"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "840"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "10010"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "5929"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1970"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2878"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2367"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "138"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "248"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "340"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1284"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "142"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2867849"
+        },
+        {
+          "expires": "Thu, 06 Dec 2012 17:34:38 GMT"
+        },
+        {
+          "last-modified": "Wed, 29 Aug 2012 03:42:11 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=742724"
+        },
+        {
+          "expires": "Mon, 12 Nov 2012 03:15:53 GMT"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 08:19:41 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1777991"
+        },
+        {
+          "expires": "Sat, 24 Nov 2012 02:50:20 GMT"
+        },
+        {
+          "last-modified": "Sun, 23 Sep 2012 09:10:47 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=962398"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 16:17:07 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 06:17:12 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=14125794"
+        },
+        {
+          "expires": "Tue, 16 Apr 2013 00:47:03 GMT"
+        },
+        {
+          "last-modified": "Mon, 12 Dec 2011 13:17:20 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=431506"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 12:48:55 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 13:13:37 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=11487816"
+        },
+        {
+          "expires": "Sat, 16 Mar 2013 12:00:45 GMT"
+        },
+        {
+          "last-modified": "Sat, 11 Feb 2012 14:49:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2738958"
+        },
+        {
+          "expires": "Wed, 05 Dec 2012 05:46:27 GMT"
+        },
+        {
+          "last-modified": "Sat, 01 Sep 2012 03:18:32 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5566505"
+        },
+        {
+          "expires": "Sun, 06 Jan 2013 23:12:14 GMT"
+        },
+        {
+          "last-modified": "Wed, 27 Jun 2012 16:26:59 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "3063"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:10:36 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "539"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17226"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "833"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "820"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:12:46 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4911"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1394"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "5772"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10954"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "994"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=54046405"
+        },
+        {
+          "expires": "Tue, 22 Jul 2014 01:50:34 GMT"
+        },
+        {
+          "last-modified": "Mon, 01 Jun 2009 11:10:18 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=707871"
+        },
+        {
+          "expires": "Sun, 11 Nov 2012 17:35:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 03:41:27 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=362012"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 17:30:42 GMT"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 03:50:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=18793623"
+        },
+        {
+          "expires": "Sun, 09 Jun 2013 01:24:13 GMT"
+        },
+        {
+          "last-modified": "Fri, 26 Aug 2011 12:03:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=430516"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 12:32:26 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 13:46:37 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=32880607"
+        },
+        {
+          "expires": "Tue, 19 Nov 2013 02:27:17 GMT"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 09:56:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3367264"
+        },
+        {
+          "expires": "Wed, 12 Dec 2012 12:18:14 GMT"
+        },
+        {
+          "last-modified": "Fri, 17 Aug 2012 14:15:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3543896"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 13:22:06 GMT"
+        },
+        {
+          "last-modified": "Mon, 13 Aug 2012 12:07:18 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "2725"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:54:28 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4823"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 06:12:46 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "598"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "4344"
+        },
+        {
+          "last-modified": "Fri, 09 Sep 2011 07:29:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=920631"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 04:41:01 GMT"
+        },
+        {
+          "last-modified": "Sat, 13 Oct 2012 05:29:27 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10801080"
+        },
+        {
+          "expires": "Fri, 08 Mar 2013 13:15:10 GMT"
+        },
+        {
+          "last-modified": "Mon, 27 Feb 2012 12:21:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=19349568"
+        },
+        {
+          "expires": "Sat, 15 Jun 2013 11:49:58 GMT"
+        },
+        {
+          "last-modified": "Sat, 13 Aug 2011 15:11:34 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2597506"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 14:28:56 GMT"
+        },
+        {
+          "last-modified": "Tue, 04 Sep 2012 09:53:37 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=27218873"
+        },
+        {
+          "expires": "Sat, 14 Sep 2013 13:45:03 GMT"
+        },
+        {
+          "last-modified": "Sat, 12 Feb 2011 11:21:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3377775"
+        },
+        {
+          "expires": "Wed, 12 Dec 2012 15:13:25 GMT"
+        },
+        {
+          "last-modified": "Fri, 17 Aug 2012 08:24:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4247008"
+        },
+        {
+          "expires": "Sat, 22 Dec 2012 16:40:38 GMT"
+        },
+        {
+          "last-modified": "Sat, 28 Jul 2012 05:30:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1815543"
+        },
+        {
+          "expires": "Sat, 24 Nov 2012 13:16:13 GMT"
+        },
+        {
+          "last-modified": "Sat, 22 Sep 2012 12:19:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=270710"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 16:09:00 GMT"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 06:33:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1790915"
+        },
+        {
+          "expires": "Sat, 24 Nov 2012 06:25:45 GMT"
+        },
+        {
+          "last-modified": "Sun, 23 Sep 2012 02:00:00 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=14218"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 16:54:08 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:03:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3723118"
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 15:09:08 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Aug 2012 08:33:13 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4635533"
+        },
+        {
+          "expires": "Thu, 27 Dec 2012 04:36:03 GMT"
+        },
+        {
+          "last-modified": "Thu, 19 Jul 2012 05:39:24 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12138710"
+        },
+        {
+          "expires": "Sun, 24 Mar 2013 00:49:00 GMT"
+        },
+        {
+          "last-modified": "Fri, 27 Jan 2012 13:13:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=19371229"
+        },
+        {
+          "expires": "Sat, 15 Jun 2013 17:50:59 GMT"
+        },
+        {
+          "last-modified": "Sat, 13 Aug 2011 03:09:31 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3202347"
+        },
+        {
+          "expires": "Mon, 10 Dec 2012 14:29:37 GMT"
+        },
+        {
+          "last-modified": "Tue, 21 Aug 2012 09:52:15 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3678437"
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 02:44:27 GMT"
+        },
+        {
+          "last-modified": "Fri, 10 Aug 2012 09:22:36 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1085523"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 02:29:13 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 09:53:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=51122420"
+        },
+        {
+          "expires": "Wed, 18 Jun 2014 05:37:30 GMT"
+        },
+        {
+          "last-modified": "Sat, 08 Aug 2009 03:36:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4381984"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 06:10:14 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 02:31:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7305155"
+        },
+        {
+          "expires": "Sun, 27 Jan 2013 02:09:45 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 May 2012 10:32:00 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13340027"
+        },
+        {
+          "expires": "Sat, 06 Apr 2013 22:30:57 GMT"
+        },
+        {
+          "last-modified": "Fri, 30 Dec 2011 17:49:36 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3517984"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 06:10:14 GMT"
+        },
+        {
+          "last-modified": "Tue, 14 Aug 2012 02:31:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4872542"
+        },
+        {
+          "expires": "Sat, 29 Dec 2012 22:26:12 GMT"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 17:59:05 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "48731"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1855967"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 00:29:57 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Sep 2012 13:51:36 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1357261"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 05:58:11 GMT"
+        },
+        {
+          "last-modified": "Wed, 03 Oct 2012 02:55:08 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12271010"
+        },
+        {
+          "expires": "Mon, 25 Mar 2013 13:34:00 GMT"
+        },
+        {
+          "last-modified": "Tue, 24 Jan 2012 11:43:29 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1069555"
+        },
+        {
+          "expires": "Thu, 15 Nov 2012 22:03:05 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 18:45:20 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3114138"
+        },
+        {
+          "expires": "Sun, 09 Dec 2012 13:59:29 GMT"
+        },
+        {
+          "last-modified": "Thu, 23 Aug 2012 10:52:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=15254111"
+        },
+        {
+          "expires": "Mon, 29 Apr 2013 02:12:22 GMT"
+        },
+        {
+          "last-modified": "Wed, 16 Nov 2011 10:26:48 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:10 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "6834"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1956253"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 04:21:24 GMT"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 06:08:44 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3164696"
+        },
+        {
+          "expires": "Mon, 10 Dec 2012 04:02:07 GMT"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 06:47:19 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=15466892"
+        },
+        {
+          "expires": "Wed, 01 May 2013 13:18:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 11 Nov 2011 12:14:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=56032"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:31:03 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:49:26 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7623169"
+        },
+        {
+          "expires": "Wed, 30 Jan 2013 18:30:00 GMT"
+        },
+        {
+          "last-modified": "Fri, 11 May 2012 01:51:32 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12924665"
+        },
+        {
+          "expires": "Tue, 02 Apr 2013 03:08:16 GMT"
+        },
+        {
+          "last-modified": "Mon, 09 Jan 2012 08:35:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2176101"
+        },
+        {
+          "expires": "Wed, 28 Nov 2012 17:25:32 GMT"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 04:00:28 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=14007174"
+        },
+        {
+          "expires": "Sun, 14 Apr 2013 15:50:05 GMT"
+        },
+        {
+          "last-modified": "Thu, 15 Dec 2011 07:11:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1438855"
+        },
+        {
+          "expires": "Tue, 20 Nov 2012 04:38:06 GMT"
+        },
+        {
+          "last-modified": "Mon, 01 Oct 2012 05:35:21 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6323658"
+        },
+        {
+          "expires": "Tue, 15 Jan 2013 17:31:29 GMT"
+        },
+        {
+          "last-modified": "Sun, 10 Jun 2012 03:48:34 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=41611"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:30:42 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:50:08 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=25072164"
+        },
+        {
+          "expires": "Tue, 20 Aug 2013 17:26:35 GMT"
+        },
+        {
+          "last-modified": "Sun, 03 Apr 2011 03:58:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13004317"
+        },
+        {
+          "expires": "Wed, 03 Apr 2013 01:15:48 GMT"
+        },
+        {
+          "last-modified": "Sat, 07 Jan 2012 12:19:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=778015"
+        },
+        {
+          "expires": "Mon, 12 Nov 2012 13:04:06 GMT"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 12:43:21 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1778334"
+        },
+        {
+          "expires": "Sat, 24 Nov 2012 02:56:05 GMT"
+        },
+        {
+          "last-modified": "Sun, 23 Sep 2012 08:59:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5531525"
+        },
+        {
+          "expires": "Sun, 06 Jan 2013 13:29:16 GMT"
+        },
+        {
+          "last-modified": "Thu, 28 Jun 2012 11:53:00 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2468675"
+        },
+        {
+          "expires": "Sun, 02 Dec 2012 02:41:46 GMT"
+        },
+        {
+          "last-modified": "Fri, 07 Sep 2012 09:28:00 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1223853"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 16:54:44 GMT"
+        },
+        {
+          "last-modified": "Sat, 06 Oct 2012 05:02:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3496295"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 00:08:46 GMT"
+        },
+        {
+          "last-modified": "Tue, 14 Aug 2012 14:34:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:09 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:09 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=20150086"
+        },
+        {
+          "expires": "Mon, 24 Jun 2013 18:11:57 GMT"
+        },
+        {
+          "last-modified": "Tue, 26 Jul 2011 02:27:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:11 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5057999"
+        },
+        {
+          "expires": "Tue, 01 Jan 2013 01:57:10 GMT"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 10:57:13 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2613405"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 18:53:57 GMT"
+        },
+        {
+          "last-modified": "Tue, 04 Sep 2012 01:03:41 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4365433"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 01:34:25 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 11:42:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=19834480"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 02:31:52 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Aug 2011 09:47:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=11268"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 16:05:00 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:41:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5616267"
+        },
+        {
+          "expires": "Mon, 07 Jan 2013 13:01:39 GMT"
+        },
+        {
+          "last-modified": "Tue, 26 Jun 2012 12:48:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7263532"
+        },
+        {
+          "expires": "Sat, 26 Jan 2013 14:36:04 GMT"
+        },
+        {
+          "last-modified": "Sat, 19 May 2012 09:39:27 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "94544"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "etag": "\"1031174008914679718\""
+        },
+        {
+          "expires": "Tue, 20 Aug 2013 13:41:19 GMT"
+        },
+        {
+          "last-modified": "Sun, 08 Jul 2012 14:17:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "723"
+        },
+        {
+          "last-modified": "Tue, 24 Jul 2012 03:59:23 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34277428450405149450110320"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "3728"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "987"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "3108"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:25:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 09:07:40 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "598"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "717"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "973"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "386"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 07:00:44 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-length": "584"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "last-modified": "Wed, 30 May 2012 03:14:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "429"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2725"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "last-modified": "Thu, 14 Oct 2010 10:10:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:10 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1633"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "733"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1647"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:49:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1217631"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 15:11:03 GMT"
+        },
+        {
+          "last-modified": "Sat, 06 Oct 2012 08:29:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4935379"
+        },
+        {
+          "expires": "Sun, 30 Dec 2012 15:53:31 GMT"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 07:04:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=94090"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 15:05:22 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 08:40:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=268205"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 15:27:17 GMT"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 07:57:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3501790"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 01:40:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 14 Aug 2012 11:30:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1089367"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 03:33:19 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 07:44:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5175917"
+        },
+        {
+          "expires": "Wed, 02 Jan 2013 10:42:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 17:26:38 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2826947"
+        },
+        {
+          "expires": "Thu, 06 Dec 2012 06:12:59 GMT"
+        },
+        {
+          "last-modified": "Thu, 30 Aug 2012 02:25:38 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:37:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "560"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2850"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:31:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1196"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "1804"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:09:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1320"
+        },
+        {
+          "last-modified": "Wed, 30 May 2012 03:19:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Wed, 30 May 2012 03:19:18 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1990"
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=14263076"
+        },
+        {
+          "expires": "Wed, 17 Apr 2013 14:55:08 GMT"
+        },
+        {
+          "last-modified": "Fri, 09 Dec 2011 09:01:20 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2086351"
+        },
+        {
+          "expires": "Tue, 27 Nov 2012 16:29:43 GMT"
+        },
+        {
+          "last-modified": "Sun, 16 Sep 2012 05:52:10 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6392807"
+        },
+        {
+          "expires": "Wed, 16 Jan 2013 12:43:59 GMT"
+        },
+        {
+          "last-modified": "Fri, 08 Jun 2012 13:23:38 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4373528"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 03:49:20 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 07:12:56 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=960053"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 15:38:05 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 07:35:25 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1446556"
+        },
+        {
+          "expires": "Tue, 20 Nov 2012 06:46:28 GMT"
+        },
+        {
+          "last-modified": "Mon, 01 Oct 2012 01:18:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13730089"
+        },
+        {
+          "expires": "Thu, 11 Apr 2013 10:52:01 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Dec 2011 17:07:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4447089"
+        },
+        {
+          "expires": "Tue, 25 Dec 2012 00:15:21 GMT"
+        },
+        {
+          "last-modified": "Mon, 23 Jul 2012 14:20:53 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1048930"
+        },
+        {
+          "expires": "Thu, 15 Nov 2012 16:19:22 GMT"
+        },
+        {
+          "last-modified": "Wed, 10 Oct 2012 06:12:51 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"4013610198\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Wed, 20 Jun 2012 16:39:57 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1828"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=23765568"
+        },
+        {
+          "expires": "Mon, 05 Aug 2013 14:30:00 GMT"
+        },
+        {
+          "last-modified": "Tue, 03 May 2011 09:51:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "9466"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 06:58:47 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2736291"
+        },
+        {
+          "expires": "Wed, 05 Dec 2012 05:02:03 GMT"
+        },
+        {
+          "last-modified": "Sat, 01 Sep 2012 04:47:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7202517"
+        },
+        {
+          "expires": "Fri, 25 Jan 2013 21:39:09 GMT"
+        },
+        {
+          "last-modified": "Sun, 20 May 2012 19:33:18 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=962816"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 16:24:09 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 06:03:21 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=28898351"
+        },
+        {
+          "expires": "Fri, 04 Oct 2013 00:16:24 GMT"
+        },
+        {
+          "last-modified": "Tue, 04 Jan 2011 14:18:50 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=26910239"
+        },
+        {
+          "expires": "Wed, 11 Sep 2013 00:01:12 GMT"
+        },
+        {
+          "last-modified": "Sat, 19 Feb 2011 14:49:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=314449"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 04:18:02 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 06:15:34 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=17303680"
+        },
+        {
+          "expires": "Wed, 22 May 2013 19:31:53 GMT"
+        },
+        {
+          "last-modified": "Thu, 29 Sep 2011 23:47:53 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=8742316"
+        },
+        {
+          "expires": "Tue, 12 Feb 2013 17:22:29 GMT"
+        },
+        {
+          "last-modified": "Sun, 15 Apr 2012 04:06:41 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=951041"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 13:07:54 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 12:35:50 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12357995"
+        },
+        {
+          "expires": "Tue, 26 Mar 2013 13:43:48 GMT"
+        },
+        {
+          "last-modified": "Sun, 22 Jan 2012 11:24:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-length": "30289"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:14:30 GMT"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "tracecode": "34277428450405149450110320"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "set-cookie": "wise_device=0; expires=Sun, 03-Nov-2013 12:57:07 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6924353"
+        },
+        {
+          "expires": "Tue, 22 Jan 2013 16:23:06 GMT"
+        },
+        {
+          "last-modified": "Sun, 27 May 2012 06:05:27 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=35998348"
+        },
+        {
+          "expires": "Wed, 25 Dec 2013 04:29:41 GMT"
+        },
+        {
+          "last-modified": "Sat, 24 Jul 2010 05:52:16 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=403161"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 04:56:34 GMT"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 04:58:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=11795987"
+        },
+        {
+          "expires": "Wed, 20 Mar 2013 01:37:00 GMT"
+        },
+        {
+          "last-modified": "Sat, 04 Feb 2012 11:37:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4466678"
+        },
+        {
+          "expires": "Tue, 25 Dec 2012 05:41:51 GMT"
+        },
+        {
+          "last-modified": "Mon, 23 Jul 2012 03:27:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4380824"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 05:50:57 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 03:09:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4370018"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 02:50:51 GMT"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 09:09:57 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=22046695"
+        },
+        {
+          "expires": "Tue, 16 Jul 2013 17:02:08 GMT"
+        },
+        {
+          "last-modified": "Sun, 12 Jun 2011 04:47:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "etag": "\"1795935374\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Thu, 20 Sep 2012 06:30:31 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "490"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1813409"
+        },
+        {
+          "expires": "Sat, 24 Nov 2012 12:40:42 GMT"
+        },
+        {
+          "last-modified": "Sat, 22 Sep 2012 13:30:14 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2381150"
+        },
+        {
+          "expires": "Sat, 01 Dec 2012 02:23:03 GMT"
+        },
+        {
+          "last-modified": "Sun, 09 Sep 2012 10:05:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12085408"
+        },
+        {
+          "expires": "Sat, 23 Mar 2013 10:00:41 GMT"
+        },
+        {
+          "last-modified": "Sat, 28 Jan 2012 18:50:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7660325"
+        },
+        {
+          "expires": "Thu, 31 Jan 2013 04:49:18 GMT"
+        },
+        {
+          "last-modified": "Thu, 10 May 2012 05:13:02 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=20831903"
+        },
+        {
+          "expires": "Tue, 02 Jul 2013 15:35:36 GMT"
+        },
+        {
+          "last-modified": "Sun, 10 Jul 2011 07:40:26 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "42293"
+        },
+        {
+          "last-modified": "Wed, 30 May 2012 03:19:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:57:12 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13227345"
+        },
+        {
+          "expires": "Fri, 05 Apr 2013 15:12:58 GMT"
+        },
+        {
+          "last-modified": "Mon, 02 Jan 2012 08:25:43 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5658505"
+        },
+        {
+          "expires": "Tue, 08 Jan 2013 00:45:38 GMT"
+        },
+        {
+          "last-modified": "Mon, 25 Jun 2012 13:20:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1397477"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 17:08:30 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 04:34:38 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3108210"
+        },
+        {
+          "expires": "Sun, 09 Dec 2012 12:20:43 GMT"
+        },
+        {
+          "last-modified": "Thu, 23 Aug 2012 14:10:13 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1080824"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 01:10:57 GMT"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 12:29:45 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=10544861"
+        },
+        {
+          "expires": "Tue, 05 Mar 2013 14:04:54 GMT"
+        },
+        {
+          "last-modified": "Sun, 04 Mar 2012 10:41:50 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9336177"
+        },
+        {
+          "expires": "Tue, 19 Feb 2013 14:20:10 GMT"
+        },
+        {
+          "last-modified": "Sun, 01 Apr 2012 10:11:18 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=947069"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 12:01:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 14:48:15 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1473803"
+        },
+        {
+          "expires": "Tue, 20 Nov 2012 14:20:37 GMT"
+        },
+        {
+          "last-modified": "Sun, 30 Sep 2012 10:10:28 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1395562"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 16:36:36 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 05:38:29 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4082149"
+        },
+        {
+          "expires": "Thu, 20 Dec 2012 18:53:02 GMT"
+        },
+        {
+          "last-modified": "Wed, 01 Aug 2012 01:05:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4020129"
+        },
+        {
+          "expires": "Thu, 20 Dec 2012 01:39:23 GMT"
+        },
+        {
+          "last-modified": "Thu, 02 Aug 2012 11:32:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=30533221"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 22:24:15 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Nov 2010 18:03:12 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9250886"
+        },
+        {
+          "expires": "Mon, 18 Feb 2013 14:38:40 GMT"
+        },
+        {
+          "last-modified": "Tue, 03 Apr 2012 09:34:21 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=7796153"
+        },
+        {
+          "expires": "Fri, 01 Feb 2013 18:33:07 GMT"
+        },
+        {
+          "last-modified": "Mon, 07 May 2012 01:45:28 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12403487"
+        },
+        {
+          "expires": "Wed, 27 Mar 2013 02:22:01 GMT"
+        },
+        {
+          "last-modified": "Sat, 21 Jan 2012 10:07:40 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=342416"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 12:04:10 GMT"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 14:43:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13044961"
+        },
+        {
+          "expires": "Wed, 03 Apr 2013 12:33:15 GMT"
+        },
+        {
+          "last-modified": "Fri, 06 Jan 2012 13:45:12 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=90589"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 14:07:03 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 10:37:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=13128536"
+        },
+        {
+          "expires": "Thu, 04 Apr 2013 11:46:10 GMT"
+        },
+        {
+          "last-modified": "Wed, 04 Jan 2012 15:19:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3557238"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 17:04:32 GMT"
+        },
+        {
+          "last-modified": "Mon, 13 Aug 2012 04:42:37 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=2348339"
+        },
+        {
+          "expires": "Fri, 30 Nov 2012 17:16:13 GMT"
+        },
+        {
+          "last-modified": "Mon, 10 Sep 2012 04:19:15 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=303065"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 01:08:19 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 12:35:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3713169"
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 12:23:23 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Aug 2012 14:04:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3556632"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 16:54:26 GMT"
+        },
+        {
+          "last-modified": "Mon, 13 Aug 2012 05:02:50 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4793201"
+        },
+        {
+          "expires": "Sat, 29 Dec 2012 00:23:55 GMT"
+        },
+        {
+          "last-modified": "Sun, 15 Jul 2012 14:03:52 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=488079"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 04:31:53 GMT"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 05:47:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=12998284"
+        },
+        {
+          "expires": "Tue, 02 Apr 2013 23:35:18 GMT"
+        },
+        {
+          "last-modified": "Sat, 07 Jan 2012 15:41:05 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=38194284"
+        },
+        {
+          "expires": "Sun, 19 Jan 2014 14:28:38 GMT"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 09:54:26 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:13 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "17574"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 03:00:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:57:13 GMT"
+        },
+        {
+          "cache-control": "max-age=3600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1010448"
+        },
+        {
+          "expires": "Thu, 15 Nov 2012 05:38:02 GMT"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 03:35:37 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=573690"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:18:44 GMT"
+        },
+        {
+          "last-modified": "Sun, 21 Oct 2012 06:14:13 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=9690556"
+        },
+        {
+          "expires": "Sat, 23 Feb 2013 16:46:30 GMT"
+        },
+        {
+          "last-modified": "Sat, 24 Mar 2012 05:18:41 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=20727056"
+        },
+        {
+          "expires": "Mon, 01 Jul 2013 10:28:10 GMT"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 17:55:22 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5867076"
+        },
+        {
+          "expires": "Thu, 10 Jan 2013 10:41:50 GMT"
+        },
+        {
+          "last-modified": "Wed, 20 Jun 2012 17:28:01 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1938815"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:30:49 GMT"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 15:50:04 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:14 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=25417039"
+        },
+        {
+          "expires": "Sat, 24 Aug 2013 17:14:33 GMT"
+        },
+        {
+          "last-modified": "Sat, 26 Mar 2011 04:22:35 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1258204"
+        },
+        {
+          "expires": "Sun, 18 Nov 2012 02:27:19 GMT"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 09:57:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1855684"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 00:25:19 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Sep 2012 14:01:06 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=6489659"
+        },
+        {
+          "expires": "Thu, 17 Jan 2013 15:38:14 GMT"
+        },
+        {
+          "last-modified": "Wed, 06 Jun 2012 07:35:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4972705"
+        },
+        {
+          "expires": "Mon, 31 Dec 2012 02:15:40 GMT"
+        },
+        {
+          "last-modified": "Wed, 11 Jul 2012 10:20:25 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4075979"
+        },
+        {
+          "expires": "Thu, 20 Dec 2012 17:10:14 GMT"
+        },
+        {
+          "last-modified": "Wed, 01 Aug 2012 04:31:16 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-length": "16"
+        },
+        {
+          "content-type": "text/html;charset=gbk"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "set-cookie": "BDRCVFR[RQbEFtOPS6t]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-length": "16"
+        },
+        {
+          "content-type": "text/html;charset=gbk"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "set-cookie": "BDRCVFR[74hAi0as9Oc]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-length": "16"
+        },
+        {
+          "content-type": "text/html;charset=gbk"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "set-cookie": "BDRCVFR[INlq_Cf3RCm]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "BWS/1.0"
+        },
+        {
+          "content-length": "16"
+        },
+        {
+          "content-type": "text/html;charset=gbk"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "set-cookie": "BDRCVFR[wqXIM55hsyY]=mbxnW11j9Dfmh7GuZR8mvqV; path=/; domain=rp.baidu.com"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "17574"
+        },
+        {
+          "last-modified": "Sat Nov  3 20:57:15 2012"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "cache-control": "post-check=0, pre-check=0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=433162"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 13:16:37 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 12:18:30 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=701481"
+        },
+        {
+          "expires": "Sun, 11 Nov 2012 15:48:36 GMT"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 07:14:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=473366"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 00:26:41 GMT"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 13:58:23 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=5523078"
+        },
+        {
+          "expires": "Sun, 06 Jan 2013 11:08:33 GMT"
+        },
+        {
+          "last-modified": "Thu, 28 Jun 2012 16:34:39 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=16759229"
+        },
+        {
+          "expires": "Thu, 16 May 2013 12:17:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 12 Oct 2011 14:16:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=4189499"
+        },
+        {
+          "expires": "Sat, 22 Dec 2012 00:42:14 GMT"
+        },
+        {
+          "last-modified": "Sun, 29 Jul 2012 13:27:17 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "etag": "\"2607371477\""
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 05:49:17 GMT"
+        },
+        {
+          "expires": "Sun, 17 Mar 2013 06:26:16 GMT"
+        },
+        {
+          "cache-control": "max-age=15552000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "etag": "\"2063226227\""
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:39:26 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:09:38 GMT"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=1345881"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 02:48:36 GMT"
+        },
+        {
+          "last-modified": "Wed, 03 Oct 2012 09:14:33 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=96063"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 15:38:18 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 07:35:08 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=3617766"
+        },
+        {
+          "expires": "Sat, 15 Dec 2012 09:53:21 GMT"
+        },
+        {
+          "last-modified": "Sat, 11 Aug 2012 19:05:03 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=11496580"
+        },
+        {
+          "expires": "Sat, 16 Mar 2013 14:26:55 GMT"
+        },
+        {
+          "last-modified": "Sat, 11 Feb 2012 09:57:55 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "server": "apache 1.1.26.0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=307195"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 02:17:10 GMT"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 10:17:24 GMT"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:15 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "etag": "\"618192838\""
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 12:49:53 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "JSP2/1.0.2"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:57:16 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "9799"
+        },
+        {
+          "etag": "\"2773371803\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 03:58:12 GMT"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 09:54:56 GMT"
+        },
+        {
+          "cache-control": "max-age=604800"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_23.json b/jetty-http2/http2-hpack/src/test/resources/data/story_23.json
new file mode 100644
index 0000000..935e29d
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_23.json
@@ -0,0 +1,13406 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:10 GMT"
+        },
+        {
+          "server": "Apache/2.2.22 (Unix)"
+        },
+        {
+          "set-cookie": "BBC-UID=557049b5114e60f649a3590541375a237274de5c1020f1118262d353e424f5650Mozilla%2f5%2e0%20%28Macintosh%3b%20Intel%20Mac%20OS%20X%2010%2e8%3b%20rv%3a16%2e0%29%20Gecko%2f20100101%20Firefox%2f16%2e0; expires=Sun, 03-Nov-13 13:37:10 GMT; path=/; domain=.bbc.co.uk;"
+        },
+        {
+          "location": "http://www.bbc.co.uk/"
+        },
+        {
+          "content-length": "229"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "private, max-age=60"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "etag": "\"dfc69d0362a1518353bddd8fa0dcc7cf-49cffe7f817cb754d3241794c0a3e991\""
+        },
+        {
+          "x-pal-host": "pal047.cwwtf.bbc.co.uk:80"
+        },
+        {
+          "content-length": "25186"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:11 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "PASS (non-cacheable)"
+        },
+        {
+          "x-cache-age": "33"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:12 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 10:42:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=900"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:52:11 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2414"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "keep-alive": "timeout=4, max=175"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:37:12 GMT"
+        },
+        {
+          "etag": "\"dfc69d0362a1518353bddd8fa0dcc7cf-49cffe7f817cb754d3241794c0a3e991\""
+        },
+        {
+          "x-pal-host": "pal047.cwwtf.bbc.co.uk:80"
+        },
+        {
+          "content-length": "958"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:12 GMT"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "x-cache-action": "PASS (non-cacheable)"
+        },
+        {
+          "x-cache-age": "33"
+        },
+        {
+          "vary": "X-CDN"
+        },
+        {
+          "last-modified": "Wed, 28 Jun 2006 14:32:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "keep-alive": "timeout=4, max=190"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 05 May 2011 09:15:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4786"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=30845970"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 13:56:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "etag": "\"d1a-4af7eb4dd8880\""
+        },
+        {
+          "expires": "Tue, 13 Nov 2012 11:52:05 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Oct 2011 13:37:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1227"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "etag": "\"677-4af7eb4bf0400\""
+        },
+        {
+          "expires": "Tue, 13 Nov 2012 11:49:51 GMT"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Oct 2011 13:37:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "644"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:31:55 GMT"
+        },
+        {
+          "etag": "\"3c9-4cd32b163a8c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:47:52 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "418"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:31:55 GMT"
+        },
+        {
+          "etag": "\"217-4cd32b163a8c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:48:03 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "211"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:28 GMT"
+        },
+        {
+          "etag": "\"7316-4cbc5c0a6df00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:20:52 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5855"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:33:03 GMT"
+        },
+        {
+          "etag": "\"714c-4cd32b57141c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:48:07 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5891"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 16 Nov 2011 15:42:16 GMT"
+        },
+        {
+          "etag": "\"5ec2-4b1dbf2c82600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:45:35 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7383"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:26 GMT"
+        },
+        {
+          "etag": "\"41d9-4cbc5c0885a80\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:21:11 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "content-length": "5723"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:32:01 GMT"
+        },
+        {
+          "etag": "\"9029-4cd32b1bf3640\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:47:52 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11967"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 26 Apr 2010 14:22:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "916"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=27418917"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:59:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 06 Jul 2011 17:14:05 GMT"
+        },
+        {
+          "etag": "\"20a0c-4a769ba3ff140\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:50:03 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "37892"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 26 Apr 2010 14:18:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "31308"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=27418893"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:58:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://www.googleadservices.com/pagead/p3p.xml\", CP=\"NOI DEV PSA PSD IVA IVD OTP OUR OTR IND OTC\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "etag": "16031183393755591049"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:45:54 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:45:54 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "content-length": "11145"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "3084"
+        },
+        {
+          "cache-control": "public, max-age=3600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:31:56 GMT"
+        },
+        {
+          "etag": "\"722a-4cd32b172eb00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:48:06 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5813"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "302"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "302"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:19 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Tue, 08 May 2012 20:06:18 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 14:30:10 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:30:10 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "83229"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:37:19 GMT"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:37:19 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "x-proc-data": "pd3-bgas02-0"
+        },
+        {
+          "content-type": "application/javascript;charset=ISO-8859-1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 03 Oct 2012 14:20:11 GMT"
+        },
+        {
+          "etag": "\"1fbb-4cb2856215cc0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=2592000"
+        },
+        {
+          "expires": "Fri, 30 Nov 2012 15:42:45 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3254"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"3fc-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:21:03 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1020"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"bc-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:20:59 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT"
+        },
+        {
+          "etag": "\"293-4caac394743c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 09:51:46 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "content-length": "659"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "etag": "\"11e-4caac394743c0\""
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 09:51:45 GMT"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "286"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "etag": "\"25d-4caac394743c0\""
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 09:51:56 GMT"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 10:15:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "605"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:32 GMT"
+        },
+        {
+          "etag": "\"121f4-4cd5e1b17b100\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470349"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:32 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10750"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2378"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:19 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Fri, 24 Jun 2011 10:14:39 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 22:58:53 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:58:53 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "12034"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "52707"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "set-cookie": "s1=50951E1074D40255; expires=Thu, 02-Nov-2017 13:37:20 GMT; path=/; domain=.bbc.co.uk"
+        },
+        {
+          "location": "http://sa.bbc.co.uk/bbc/bbc/s?name=home.page&ns_m2=yes&ns_setsiteck=50951E1074D40255&geo_edition=int&pal_route=default&ml_name=barlesque&app_type=web&language=en-GB&ml_version=0.14.2&pal_webapp=wwhomepage&bbc_mc=not_set&screen_resolution=1366x768&blq_s=3.5&blq_r=3.5&blq_v=default-worldwide&ns__t=1351949839865&ns_c=UTF-8&ns_ti=BBC%20-%20Homepage&ns_jspageurl=http%3A//www.bbc.co.uk/&ns_referrer="
+        },
+        {
+          "content-length": "656"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:32 GMT"
+        },
+        {
+          "etag": "\"608f-4cd5e1b17b100\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470342"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:32 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6150"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"223-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:20:57 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "547"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"89f-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:20:51 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2207"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 13:32:08 GMT"
+        },
+        {
+          "etag": "\"11d21-4cd32b22a0600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 08:48:10 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "24284"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "3291"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 18:25:49 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:14:11 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:14:11 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "1581"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "62589"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"1b7f-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470341"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7039"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"20a3-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470356"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8355"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"3038-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470335"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "content-length": "12344"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "last-modified": "Fri, 07 Sep 2012 16:46:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 10:27:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:27:06 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "23913"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "11414"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"1ff0-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470356"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8176"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 06:54:04 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:50:43 GMT"
+        },
+        {
+          "content-length": "3810"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 21:56:00 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 21:51:59 GMT"
+        },
+        {
+          "content-length": "5049"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 09:47:13 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 09:31:24 GMT"
+        },
+        {
+          "content-length": "5071"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Thu, 19 Jul 2012 22:49:47 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 22:03:55 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:03:55 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "31936"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "56006"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"323-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470350"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "803"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "347"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 06 Jul 2011 17:14:01 GMT"
+        },
+        {
+          "etag": "\"1a56e-4a769ba02e840\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:50:28 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "30642"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 14:27:29 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:29:16 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:29:16 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "18065"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "61685"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lFpER0UXYGEV+3P4; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:37:21 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas08-1"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 12:03:34 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:02:09 GMT"
+        },
+        {
+          "content-length": "13746"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:19:26 GMT"
+        },
+        {
+          "etag": "\"136-4cd5e1abc2380\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31470294"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 17:19:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "content-length": "310"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 08:07:24 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 08:04:03 GMT"
+        },
+        {
+          "content-length": "10701"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 11:46:30 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:37:23 GMT"
+        },
+        {
+          "content-length": "4375"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 03:14:26 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:10:05 GMT"
+        },
+        {
+          "content-length": "3965"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 12:49:53 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 12:39:23 GMT"
+        },
+        {
+          "content-length": "4844"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:23:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31490899"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 13:28:30 GMT"
+        },
+        {
+          "content-length": "18949"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 17:01:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 02:00:11 GMT"
+        },
+        {
+          "content-length": "25085"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:30:25 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=31493423"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 14:10:58 GMT"
+        },
+        {
+          "content-length": "27938"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 05:49:17 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:43:46 GMT"
+        },
+        {
+          "content-length": "5569"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "server": "Omniture DC/2.0.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu,  2 Nov 2017 13:37:22 GMT; Domain=sa.bbc.com; Path=/"
+        },
+        {
+          "location": "http://sa.bbc.com/b/ss/bbcwglobalprod/1/H.22.1/s0268806509673?AQB=1&pccr=true&vidn=284A8F0905160D8B-600001A1C0108CD4&&ndh=1&t=3%2F10%2F2012%209%3A37%3A21%206%20240&vmt=4F9A739C&vmf=bbc.112.2o7.net&ce=UTF-8&cdp=3&pageName=bbc%20%7C%20homepage&g=http%3A%2F%2Fwww.bbc.co.uk%2F&cc=USD&ch=homepage&events=event2&h1=bbc%7Chomepage&v2=D%3DpageName&c5=INDEX&v5=D%3Dc5&c6=homepage&v6=D%3Dc6&c11=saturday%7C1%3A30pm&c15=%2F&v15=D%3Dc15&c17=bbc%20%7C%20homepage&v17=D%3Dc17&c31=HTML&v31=D%3Dc31&c32=Not%20available&v32=D%3Dc32&v49=Direct%20Load&c53=www.bbc.co.uk&v53=D%3Dc53&c54=http%3A%2F%2Fwww.bbc.co.uk&v54=D%3Dc54&c55=bbc.com&v55=D%3Dc55&c56=D%3DpageName&v56=D%3Dc56&c57=yes&v57=D%3Dc57&c62=wpp%7Cldb%7Cm08%7Cm2l%7Cm6i%7Cm1f%7Cmpu%7Cm29%7Cm4t%7Cm80&v62=D%3Dc62&s=1366x768&c=24&j=1.7&v=Y&k=Y&bw=994&bh=649&p=Java%20Applet%20Plug-in%3BQuickTime%20Plug-in%207.7.1%3B&AQE=1"
+        },
+        {
+          "x-c": "ms-4.4.9"
+        },
+        {
+          "expires": "Fri, 02 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "last-modified": "Sun, 04 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "cache-control": "no-cache, no-store, max-age=0, no-transform, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\""
+        },
+        {
+          "xserver": "www614"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "keep-alive": "timeout=15"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/plain"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:02:56 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 09:46:49 GMT"
+        },
+        {
+          "content-length": "2041"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"c82a-4cd8003bbf440\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:34:34 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:33:07 GMT"
+        },
+        {
+          "content-length": "5173"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"3ca55-4cd817fe482c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "server": "Omniture DC/2.0.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu,  2 Nov 2017 13:37:22 GMT; Domain=sa.bbc.com; Path=/"
+        },
+        {
+          "location": "http://sa.bbc.com/b/ss/bbcwglobalprod/1/H.22.1/s0268806509673?AQB=1&pccr=true&vidn=284A8F0905160D8B-600001A1C0108CD4&&ndh=1&t=3%2F10%2F2012%209%3A37%3A21%206%20240&vmt=4F9A739C&vmf=bbc.112.2o7.net&ce=UTF-8&cdp=3&pageName=bbc%20%7C%20homepage&g=http%3A%2F%2Fwww.bbc.co.uk%2F&cc=USD&ch=homepage&events=event2&h1=bbc%7Chomepage&v2=D%3DpageName&c5=INDEX&v5=D%3Dc5&c6=homepage&v6=D%3Dc6&c11=saturday%7C1%3A30pm&c15=%2F&v15=D%3Dc15&c17=bbc%20%7C%20homepage&v17=D%3Dc17&c31=HTML&v31=D%3Dc31&c32=Not%20available&v32=D%3Dc32&v49=Direct%20Load&c53=www.bbc.co.uk&v53=D%3Dc53&c54=http%3A%2F%2Fwww.bbc.co.uk&v54=D%3Dc54&c55=bbc.com&v55=D%3Dc55&c56=D%3DpageName&v56=D%3Dc56&c57=yes&v57=D%3Dc57&c62=wpp%7Cldb%7Cm08%7Cm2l%7Cm6i%7Cm1f%7Cmpu%7Cm29%7Cm4t%7Cm80&v62=D%3Dc62&s=1366x768&c=24&j=1.7&v=Y&k=Y&bw=994&bh=649&p=Java%20Applet%20Plug-in%3BQuickTime%20Plug-in%207.7.1%3B&AQE=1"
+        },
+        {
+          "x-c": "ms-4.4.9"
+        },
+        {
+          "expires": "Fri, 02 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "last-modified": "Sun, 04 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "cache-control": "no-cache, no-store, max-age=0, no-transform, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\""
+        },
+        {
+          "xserver": "www620"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "keep-alive": "timeout=15"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "etag": "\"50951E12-5F83-53505C0B\""
+        },
+        {
+          "vary": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:24:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31480349"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 10:32:40 GMT"
+        },
+        {
+          "content-length": "34963"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 19:51:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:52:27 GMT"
+        },
+        {
+          "content-length": "16335"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"4627f-4ccbf4cca7880\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-transform, max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Omniture DC/2.0.0"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 16:00:20 GMT"
+        },
+        {
+          "etag": "\"115240-38-b5f12d00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "56"
+        },
+        {
+          "cache-control": "max-age=7776000"
+        },
+        {
+          "expires": "Sun, 07 Oct 2012 17:35:44 GMT"
+        },
+        {
+          "xserver": "www465"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:25:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=31535948"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 01:59:43 GMT"
+        },
+        {
+          "content-length": "41157"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 15:49:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31535796"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 04:08:52 GMT"
+        },
+        {
+          "content-length": "43495"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 11:29:44 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:15:24 GMT"
+        },
+        {
+          "content-length": "83456"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:57:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 11:13:50 GMT"
+        },
+        {
+          "content-length": "18324"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"8c10d-4cd6f66d2d640\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 15:44:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 18:39:25 GMT"
+        },
+        {
+          "content-length": "24118"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"bae19-4cd48aa479540\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.22 (Unix) mod_ssl/2.2.22 OpenSSL/0.9.7d"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:01:50 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 21:25:25 GMT"
+        },
+        {
+          "content-length": "21999"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"8cfa9-4ccfcf53bbb40\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:27:36 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 19:32:42 GMT"
+        },
+        {
+          "content-length": "29003"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"b3983-4cbe1c0594a80\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:14:22 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:56:52 GMT"
+        },
+        {
+          "content-length": "28742"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"9b7c0-4cd6f64243100\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=31457054"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 12:04:47 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 11:57:38 GMT"
+        },
+        {
+          "content-length": "24526"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"3ca55-4cd817fe482c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "cache-control": "max-age=86400"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 17:24:54 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 14:40:40 GMT"
+        },
+        {
+          "content-length": "45064"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "etag": "\"fcf54-4cd841e9faa00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 03:17:34 GMT"
+        },
+        {
+          "server": "collection8"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "public, max-age=604800"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:23 GMT"
+        },
+        {
+          "content-length": "5450"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:24 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=848381a268c12381e2d991b8bfad50951e1458d396-6634083950951e14834_3366; expires=Sat, 03-Nov-2012 14:07:24 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 16:02:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "928"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=27418899"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:59:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:27 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:26:47 GMT"
+        },
+        {
+          "cache-control": "max-age=62707765"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "3417"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT"
+        },
+        {
+          "content-length": "2419"
+        },
+        {
+          "cache-control": "max-age=62707751"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT"
+        },
+        {
+          "content-length": "1281"
+        },
+        {
+          "cache-control": "max-age=62707783"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:28 GMT"
+        },
+        {
+          "cache-control": "max-age=62707813"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "56"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 18 Nov 2009 12:17:02 GMT"
+        },
+        {
+          "content-length": "1275"
+        },
+        {
+          "cache-control": "max-age=345600"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "vary": "X-CDN"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "keep-alive": "timeout=5, max=778"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 09:35:09 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-length": "941"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 22 Nov 2011 09:50:32 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1409"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=33813709"
+        },
+        {
+          "expires": "Fri, 29 Nov 2013 22:19:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 22 Nov 2011 09:39:54 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3436"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=33814374"
+        },
+        {
+          "expires": "Fri, 29 Nov 2013 22:30:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 22 Nov 2011 09:31:26 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "348"
+        },
+        {
+          "cache-control": "max-age=33076455"
+        },
+        {
+          "expires": "Thu, 21 Nov 2013 09:31:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 11:26:22 GMT"
+        },
+        {
+          "content-length": "3667"
+        },
+        {
+          "cache-control": "max-age=53347413"
+        },
+        {
+          "expires": "Mon, 14 Jul 2014 00:21:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 11:26:27 GMT"
+        },
+        {
+          "content-length": "1999"
+        },
+        {
+          "cache-control": "max-age=53214541"
+        },
+        {
+          "expires": "Sat, 12 Jul 2014 11:26:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "location": "http://emp.bbci.co.uk/emp/releases/bump/revisions/905298/embed.js?emp=worldwide&enableClear=1"
+        },
+        {
+          "content-length": "305"
+        },
+        {
+          "cache-control": "max-age=211"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:21 GMT"
+        },
+        {
+          "cache-control": "max-age=62707796"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "303"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:37 GMT"
+        },
+        {
+          "content-length": "4740"
+        },
+        {
+          "cache-control": "max-age=62707822"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:37:27 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "91216"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:27 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 17:14:09 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "446"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 28 Jul 2010 11:07:36 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8432"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=33813771"
+        },
+        {
+          "expires": "Fri, 29 Nov 2013 22:20:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:23 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2234"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "max-age=53344068"
+        },
+        {
+          "expires": "Sun, 13 Jul 2014 23:25:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 07:38:38 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1657"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "max-age=62100138"
+        },
+        {
+          "expires": "Thu, 23 Oct 2014 07:39:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:43:33 GMT"
+        },
+        {
+          "content-length": "5496"
+        },
+        {
+          "cache-control": "max-age=63033059"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 02:48:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:02:09 GMT"
+        },
+        {
+          "content-length": "4994"
+        },
+        {
+          "cache-control": "max-age=63062731"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 11:03:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "BGUID=65e0995521ce0199c628d193f15847bbfbb0331236b8ab2579e9db3ae85993f0; expires=Wed, 02-Nov-16 13:37:29 GMT; path=/; domain=bbc.co.uk;"
+        },
+        {
+          "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "max-age=0, no-cache=Set-Cookie"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "keep-alive": "timeout=10, max=182"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "location": "http://emp.bbci.co.uk/emp/releases/bump/revisions/905298/embed.js?emp=worldwide&enableClear=1"
+        },
+        {
+          "content-length": "2628"
+        },
+        {
+          "cache-control": "max-age=166"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 11 Jul 2012 23:13:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:21:03 GMT"
+        },
+        {
+          "cache-control": "max-age=63024342"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 00:23:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "3624"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:21:28 GMT"
+        },
+        {
+          "content-length": "4643"
+        },
+        {
+          "cache-control": "max-age=63024320"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 00:22:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT"
+        },
+        {
+          "content-length": "9275"
+        },
+        {
+          "cache-control": "max-age=62711088"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:22:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:55 GMT"
+        },
+        {
+          "cache-control": "max-age=62711138"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:23:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "11982"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:29:54 GMT"
+        },
+        {
+          "content-length": "5363"
+        },
+        {
+          "cache-control": "max-age=63064402"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 11:30:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"3ff-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:22:26 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1023"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:34:55 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5633"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=63025209"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 00:37:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 07 Mar 2012 10:43:47 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7269"
+        },
+        {
+          "cache-control": "max-age=43235623"
+        },
+        {
+          "expires": "Tue, 18 Mar 2014 23:31:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:20:54 GMT"
+        },
+        {
+          "cache-control": "max-age=62707524"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:22:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:29 GMT"
+        },
+        {
+          "content-length": "34395"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:57 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "24217"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=62711138"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:23:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 15:48:27 GMT"
+        },
+        {
+          "content-length": "20316"
+        },
+        {
+          "cache-control": "max-age=63051888"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 08:02:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 15:59:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "31310"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=27418847"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:58:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 15:59:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "31708"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=27418799"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:57:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 10:02:19 GMT"
+        },
+        {
+          "cache-control": "max-age=53347291"
+        },
+        {
+          "expires": "Mon, 14 Jul 2014 00:19:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:34 GMT"
+        },
+        {
+          "content-length": "358"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 15:59:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5794"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "max-age=27418850"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:58:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:34 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 10:02:20 GMT"
+        },
+        {
+          "cache-control": "max-age=53394356"
+        },
+        {
+          "expires": "Mon, 14 Jul 2014 13:23:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:35 GMT"
+        },
+        {
+          "content-length": "3759"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 26 Apr 2012 15:23:19 GMT"
+        },
+        {
+          "etag": "\"453b-4be96914da7c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:52:07 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3403"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 10:02:24 GMT"
+        },
+        {
+          "cache-control": "max-age=53487765"
+        },
+        {
+          "expires": "Tue, 15 Jul 2014 15:20:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:35 GMT"
+        },
+        {
+          "content-length": "6382"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:55 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1304"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "max-age=62711132"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:23:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:37 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"392d4eaba4ddbcf7bb408352be465c19\""
+        },
+        {
+          "cache-control": "max-age=1728000, private"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "286"
+        },
+        {
+          "keep-alive": "timeout=45"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT"
+        },
+        {
+          "cache-control": "max-age=62711099"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:22:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:37 GMT"
+        },
+        {
+          "content-length": "5788"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2410"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Thu, 19 Apr 2012 16:34:19 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 23:06:55 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 23:06:55 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "9836"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "52243"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:37 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"392d4eaba4ddbcf7bb408352be465c19\""
+        },
+        {
+          "cache-control": "private, max-age=30"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "47"
+        },
+        {
+          "keep-alive": "timeout=45"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "327"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "970"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "max-age=52968695"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:21 GMT"
+        },
+        {
+          "content-length": "126"
+        },
+        {
+          "cache-control": "max-age=52968716"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:16 GMT"
+        },
+        {
+          "cache-control": "max-age=62707784"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "content-length": "3595"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:26:49 GMT"
+        },
+        {
+          "content-length": "1859"
+        },
+        {
+          "cache-control": "max-age=62707757"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "location": "http://emp.bbci.co.uk/emp/releases/worldwide/revisions/749603_749269_749444_6/embed.js?mediaset=journalism-pc"
+        },
+        {
+          "content-length": "317"
+        },
+        {
+          "cache-control": "max-age=160"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 11 Jul 2012 23:13:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 09:22:54 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1014"
+        },
+        {
+          "cache-control": "max-age=62711082"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 09:22:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "location": "http://emp.bbci.co.uk/emp/releases/worldwide/revisions/749603_749269_749444_6/embed.js?mediaset=journalism-pc"
+        },
+        {
+          "content-length": "6090"
+        },
+        {
+          "cache-control": "max-age=167"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:39 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 12:56:25 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 10:08:24 GMT"
+        },
+        {
+          "etag": "\"adb-4cbc5c069d600\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 08:21:42 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2779"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1545"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2506"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Tue, 15 Feb 2011 16:39:27 GMT"
+        },
+        {
+          "etag": "\"6414-49c54cec44dc0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:49:13 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7619"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:39 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 20:42:56 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 15:05:54 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:05:54 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "37317"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "81106"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "327"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT"
+        },
+        {
+          "cache-control": "max-age=52968720"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "content-length": "36830"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-length": "359"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "530"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:26:46 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4729"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "max-age=62707754"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:33 GMT"
+        },
+        {
+          "content-length": "130"
+        },
+        {
+          "cache-control": "max-age=62707807"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 13:37:38 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "81990"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        },
+        {
+          "last-modified": "Wed, 26 Sep 2012 09:35:41 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "nginx/1.2.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:43 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "location": "http://ad-emea.doubleclick.net/adj/N2581.122656.2214702362621/B6422491.8;sz=120x30;click0=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/q%3B264679025%3B0-0%3B1%3B49066565%3B47-120/30%3B47423100/47438653/1%3B%3B%7Eokv%3D%3Bslot%3Dpartner_button1%3Bsz%3D120x30%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Damerica%3Breferrer%3D%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dromneypromisesus%2527realchang%3B%7Esscs%3D%3f;ord=835861?"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.2.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:43 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "483"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 22:04:59 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 16:00:52 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 16:00:52 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "4146"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "77812"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Fri, 11 Mar 2011 22:15:34 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 19:51:36 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 19:51:36 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "3834"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "63968"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "326"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "212"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lFpGQscUZ2EV0HP8; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:37:44 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas06-9"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=1de6548e4a0d3e45a7c991b8bfad50951e1458d396-6634083950951e28834_3366; expires=Sat, 03-Nov-2012 14:07:44 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:50 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "188"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "age": "245581"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:45 GMT"
+        },
+        {
+          "last-modified": "Mon, 14 Nov 2011 18:32:16 GMT"
+        },
+        {
+          "content-length": "4442"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:50 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "4449"
+        },
+        {
+          "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "age": "73519"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:45 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 15:50:57 GMT"
+        },
+        {
+          "content-length": "1709"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "age": "172785"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:45 GMT"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 17:58:48 GMT"
+        },
+        {
+          "content-length": "4036"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "age": "120980"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:45 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Dec 2011 21:51:59 GMT"
+        },
+        {
+          "content-length": "4919"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:22 GMT"
+        },
+        {
+          "cache-control": "max-age=52968714"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        },
+        {
+          "content-length": "1128"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 12 Jul 2011 15:59:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "207"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "max-age=27418929"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 21:59:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 19:57:24 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "26021"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62403629"
+        },
+        {
+          "expires": "Sun, 26 Oct 2014 19:58:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "max-age=300, public, s-maxage=120"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:28 GMT"
+        },
+        {
+          "keep-alive": "timeout=5, max=852"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:42:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8550-4c7d8d79b86c0\""
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 11:14:11 GMT"
+        },
+        {
+          "content-length": "12181"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 11:14:13 GMT"
+        },
+        {
+          "etag": "\"31a9-4c7d8d7ba0b40\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=300, public, s-maxage=120"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2364"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:46 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "application/json;charset=UTF-8"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "access-control-allow-methods": "POST, GET, PUT, OPTIONS"
+        },
+        {
+          "access-control-allow-headers": "Content-Type, X-Requested-With, *"
+        },
+        {
+          "content-length": "117"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 11:14:08 GMT"
+        },
+        {
+          "etag": "\"212e-4c7d8d76dc000\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "expires": "Tue, 17 Sep 2013 11:50:39 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8494"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:57 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:23 GMT"
+        },
+        {
+          "cache-control": "max-age=52968675"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:57 GMT"
+        },
+        {
+          "content-length": "126"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "575"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "location": "http://mp.apmebf.com/ad/fm/13001-83639-22765-1?mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f&host=altfarm.mediaplex.com"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "max-age=0, no-cache=Set-Cookie"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:37:58 GMT"
+        },
+        {
+          "keep-alive": "timeout=10, max=176"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "341"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1387"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:50:47 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4705"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=63047620"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 06:51:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\""
+        },
+        {
+          "set-cookie": "S=g14vo-413-1351949879145-ya; domain=.apmebf.com; path=/; expires=Mon, 03-Nov-2014 13:37:59 GMT"
+        },
+        {
+          "location": "http://altfarm.mediaplex.com/ad/fm/13001-83639-22765-1?mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f&no_cj_c=1&upsid=545485072431"
+        },
+        {
+          "content-length": "711"
+        },
+        {
+          "keep-alive": "timeout=5"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\""
+        },
+        {
+          "set-cookie": "mojo3=13001:22765; expires=Sun, 2-Nov-2014 16:28:10 GMT; path=/; domain=.mediaplex.com;"
+        },
+        {
+          "location": "http://img.mediaplex.com/content/0/13001/728x90_090512_MVT_Standard.html?mpck=altfarm.mediaplex.com%2Fad%2Fck%2F13001-83639-22765-1%3Fmpt%3D853079&mpt=853079&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/v%3B264640753%3B0-0%3B0%3B73659506%3B3454-728/90%3B47524155/47539673/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dcontent%3Bnews%3Dworld%3Breferrer%3Dnewsworlduscanada20104929%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3D%3Bheadline%3Dbombkillspakistanipolitician%3B%7Esscs%3D%3f"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 13:34:50 GMT"
+        },
+        {
+          "etag": "\"a5f202-357-4cba066fe7280\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1285"
+        },
+        {
+          "keep-alive": "timeout=5"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2518"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "339"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:26:09 GMT"
+        },
+        {
+          "cache-control": "max-age=63064269"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 11:29:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:58 GMT"
+        },
+        {
+          "content-length": "18429"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "332"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-length": "332"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "339"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:37:55 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "84226"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "expires": "Sat Nov 03 13:37:59 UTC 2012"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "1273"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "212"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:05 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuB86QsXkGiDUw6LAw6IpFSRlNUwBT4lNpFQ0QUg4OfFcQQ1VXgXlFGVpIpliI6eB4eKxBjZB19azY=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:00 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas01-1"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "expires": "Sat Nov 03 13:37:59 UTC 2012"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "7375"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:05 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "4449"
+        },
+        {
+          "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "56812"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:45:03 GMT"
+        },
+        {
+          "server": "Apache/2.2.3 (CentOS)"
+        },
+        {
+          "last-modified": "Sat, 18 Aug 2012 06:04:35 GMT"
+        },
+        {
+          "etag": "\"5d0aba4-ddec-4c7840d06c2c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=3600"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:45:03 GMT"
+        },
+        {
+          "x-permitted-cross-domain-policies": "all"
+        },
+        {
+          "age": "3177"
+        },
+        {
+          "x-amz-cf-id": "Nqvl7hdh1ZID-spjM3MSj_rmvJrOblt2qYh9QKaP4AUq-J79-UBaKg=="
+        },
+        {
+          "via": "1.0 f9710778d388f0645feb35b6ec48d316.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:00 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=51bfcbb530581eaf84e991b8bfad50951e1458d396-6634083950951e38834_3366; expires=Sat, 03-Nov-2012 14:08:00 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:37:59 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "application/json;charset=UTF-8"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "access-control-allow-methods": "POST, GET, PUT, OPTIONS"
+        },
+        {
+          "access-control-allow-headers": "Content-Type, X-Requested-With, *"
+        },
+        {
+          "content-length": "111"
+        },
+        {
+          "cache-control": "max-age=31"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:27:19 GMT"
+        },
+        {
+          "cache-control": "max-age=62707764"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:27:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:06 GMT"
+        },
+        {
+          "content-length": "297"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:06 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "max-age=0, no-cache=Set-Cookie"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:06 GMT"
+        },
+        {
+          "keep-alive": "timeout=10, max=162"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 10:02:19 GMT"
+        },
+        {
+          "cache-control": "max-age=53487737"
+        },
+        {
+          "expires": "Tue, 15 Jul 2014 15:20:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "content-length": "7969"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 16:22:37 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4852"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62995766"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 16:27:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:13:05 GMT"
+        },
+        {
+          "content-length": "6548"
+        },
+        {
+          "cache-control": "max-age=63020343"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 23:17:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 08:04:19 GMT"
+        },
+        {
+          "cache-control": "max-age=62880339"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 08:23:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "content-length": "4144"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 14:00:52 GMT"
+        },
+        {
+          "content-length": "3761"
+        },
+        {
+          "cache-control": "max-age=62901025"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 14:08:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:22:05 GMT"
+        },
+        {
+          "content-length": "6600"
+        },
+        {
+          "cache-control": "max-age=62916820"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 18:31:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "454"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 14:39:26 GMT"
+        },
+        {
+          "content-length": "6851"
+        },
+        {
+          "cache-control": "max-age=62989321"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 14:40:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 11:27:56 GMT"
+        },
+        {
+          "content-length": "5411"
+        },
+        {
+          "cache-control": "max-age=62320782"
+        },
+        {
+          "expires": "Sat, 25 Oct 2014 20:57:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "location": "http://img.mediaplex.com/content/0/18916/LT_XML_RateTable_ScrollingHeadline_PurpleArrows_RecordLows_728x90_050112.js?mpck=altfarm.mediaplex.com%2Fad%2Fck%2F18916-133472-32866-8%3Fmpt%3D862767&mpt=862767&mpvc=http://ad.doubleclick.net/click%3Bh%3Dv8/3d22/3/0/%2a/o%3B264441578%3B0-0%3B0%3B19196826%3B3454-728/90%3B49903581/49895429/1%3B%3B%7Eokv%3D%3Bslot%3Dleaderboard%3Bsz%3D728x90%2C970x66%2C970x90%2C970x250%3Bsectn%3Dnews%3Bctype%3Dindex%3Bnews%3Dworld%3Breferrer%3Dnewsworldasia20190337%3Bdomain%3Dwww.bbc.co.uk%3Breferrer_domain%3Dwww.bbc.co.uk%3Brsi%3DJ08781_10132%3Brsi%3DJ08781_10628%3B%7Esscs%3D%3f"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV\""
+        },
+        {
+          "set-cookie": "mojo3=18916:32866/13001:22765; expires=Sun, 2-Nov-2014 16:53:09 GMT; path=/; domain=.mediaplex.com;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 01 May 2012 19:15:40 GMT"
+        },
+        {
+          "etag": "\"2119c1-1526-4befe65754f00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "6980"
+        },
+        {
+          "keep-alive": "timeout=5"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:05 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "90666"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 19 Oct 2011 07:28:39 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "18359"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=52349338"
+        },
+        {
+          "expires": "Wed, 02 Jul 2014 11:07:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:19:24 GMT"
+        },
+        {
+          "cache-control": "max-age=63002534"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 18:20:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "content-length": "5791"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 09:30:47 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5035"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=63057300"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 09:33:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 06:55:42 GMT"
+        },
+        {
+          "cache-control": "max-age=62961571"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 06:57:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "content-length": "6266"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 15:53:37 GMT"
+        },
+        {
+          "content-length": "4757"
+        },
+        {
+          "cache-control": "max-age=62820986"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 15:54:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 09:01:42 GMT"
+        },
+        {
+          "cache-control": "max-age=62882710"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 09:03:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "content-length": "5396"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:09:30 GMT"
+        },
+        {
+          "content-length": "4759"
+        },
+        {
+          "cache-control": "max-age=62965934"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 08:10:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:24:17 GMT"
+        },
+        {
+          "content-length": "3202"
+        },
+        {
+          "cache-control": "max-age=62989607"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 14:44:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:01:25 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4022"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62983627"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 13:05:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 08:54:55 GMT"
+        },
+        {
+          "cache-control": "max-age=62970180"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 09:21:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "content-length": "4853"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 13:44:04 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3289"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "max-age=62901702"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 14:19:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 16:55:01 GMT"
+        },
+        {
+          "content-length": "7105"
+        },
+        {
+          "cache-control": "max-age=62911093"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 16:56:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 07:57:36 GMT"
+        },
+        {
+          "cache-control": "max-age=58732357"
+        },
+        {
+          "expires": "Sun, 14 Sep 2014 08:10:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "content-length": "3960"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Tue, 21 Aug 2012 07:36:37 GMT"
+        },
+        {
+          "content-length": "3948"
+        },
+        {
+          "cache-control": "max-age=56656721"
+        },
+        {
+          "expires": "Thu, 21 Aug 2014 07:36:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 09 Mar 2006 21:32:31 GMT"
+        },
+        {
+          "etag": "\"9f40d-3a-40e969d2259c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "content-length": "63"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 05 Mar 2012 12:15:23 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "59958"
+        },
+        {
+          "cache-control": "max-age=42071869"
+        },
+        {
+          "expires": "Wed, 05 Mar 2014 12:15:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "pragma": ""
+        },
+        {
+          "content-length": "479"
+        },
+        {
+          "cache-control": "max-age=30"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2493"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "321"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-length": "363"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "212"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:14 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:14 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "P3P - policyref=\"http://www.adfusion.com/w3c/adfusion.xml\", CP=\"NON DSP COR CURa TIA\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.adfusion.com/AdServer/default.aspx?e=i&lid=10641&ct="
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-length": "4449"
+        },
+        {
+          "set-cookie": "cid=6f010485-f507-4a4e-a485-feb7619db013; domain=.adfusion.com; expires=Wed, 01-Jan-2020 06:00:00 GMT; path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1396"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+ZjtUnj+OABraDN8bCZzDmjhJGhbKAxEWBcNLyPWU8lPaSzTe300; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:09 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas04-1"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=d12d53fe4bd39099b1d991b8bfad50951e1458d396-6634083950951e41834_3366; expires=Sat, 03-Nov-2012 14:08:09 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 09 Jul 2012 15:09:21 GMT"
+        },
+        {
+          "cache-control": "max-age=52968683"
+        },
+        {
+          "expires": "Wed, 09 Jul 2014 15:09:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "content-length": "11937"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:26:43 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1594"
+        },
+        {
+          "cache-control": "max-age=62707699"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 16 Jul 2012 20:54:14 GMT"
+        },
+        {
+          "etag": "\"6d6c23-816c-4c4f8a1e64980\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "33132"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "317"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "1222"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "4631"
+        },
+        {
+          "set-cookie": "PRpc=|HrYvHDG1:1|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:23 GMT;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 12:33:21 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17839"
+        },
+        {
+          "cache-control": "max-age=62987851"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 14:15:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:51:54 GMT"
+        },
+        {
+          "cache-control": "max-age=62946923"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 02:53:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "content-length": "4827"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 15:48:41 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5891"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62993480"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 15:49:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:44:04 GMT"
+        },
+        {
+          "content-length": "3664"
+        },
+        {
+          "cache-control": "max-age=62975317"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 10:46:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 13:08:31 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5589"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62813487"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 13:49:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 11:47:26 GMT"
+        },
+        {
+          "content-length": "6787"
+        },
+        {
+          "cache-control": "max-age=62806355"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 11:50:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "max-age=0, no-cache=Set-Cookie"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "keep-alive": "timeout=10, max=150"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "private, max-age=30"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "47"
+        },
+        {
+          "keep-alive": "timeout=45"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "1232"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "4657"
+        },
+        {
+          "set-cookie": "PRpc=|HrYwHDG0:1|HrYvHDG1:1|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:23 GMT;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 12:54:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6289"
+        },
+        {
+          "cache-control": "max-age=62291861"
+        },
+        {
+          "expires": "Sat, 25 Oct 2014 12:56:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 05:59:50 GMT"
+        },
+        {
+          "cache-control": "max-age=62871966"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 06:04:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "content-length": "4071"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 09:39:39 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6862"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62885045"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 09:42:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 24 Sep 2012 12:45:46 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4014"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=59612845"
+        },
+        {
+          "expires": "Wed, 24 Sep 2014 12:45:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "360"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:12:35 GMT"
+        },
+        {
+          "content-length": "6772"
+        },
+        {
+          "cache-control": "max-age=62955857"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 05:22:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-length": "548"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "545"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "545"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Tue, 01 Feb 2011 16:45:17 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 19:49:21 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 19:49:21 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "4447"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "64143"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Tue, 25 Sep 2012 20:37:11 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:14:54 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:14:54 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "2993"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "62610"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:21 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "103860"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 18:53:42 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:59:32 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 21:59:32 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "5619"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "56332"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 18:54:38 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:59:33 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 21:59:33 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "5379"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "56331"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 05 Nov 2010 18:11:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 08:14:05 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:05 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "19459"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-type": "text/plain"
+        },
+        {
+          "content-length": "3528"
+        },
+        {
+          "cache-control": "private, max-age=506694"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "882"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 07:32:16 GMT"
+        },
+        {
+          "cache-control": "max-age=62963730"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 07:33:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "content-length": "6112"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:53:00 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6904"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62947059"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 02:56:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 23:54:38 GMT"
+        },
+        {
+          "content-length": "6467"
+        },
+        {
+          "cache-control": "max-age=62677369"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 00:01:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 01:56:44 GMT"
+        },
+        {
+          "content-length": "5790"
+        },
+        {
+          "cache-control": "max-age=62943937"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 02:04:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Thu, 15 Dec 2011 11:42:59 GMT"
+        },
+        {
+          "content-length": "13166"
+        },
+        {
+          "cache-control": "max-age=60312573"
+        },
+        {
+          "expires": "Thu, 02 Oct 2014 15:07:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:47:01 GMT"
+        },
+        {
+          "content-length": "6715"
+        },
+        {
+          "cache-control": "max-age=63007794"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 19:48:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Sun, 05-Jun-2005 22:00:00 GMT"
+        },
+        {
+          "set-cookie": "u2=0c1d5772-7a75-4913-9e34-91b1ec36e6763Qv0b0; expires=Fri, 01-Feb-2013 09:38:24 GMT; domain=.serving-sys.com; path=/"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"NOI DEVa OUR BUS UNI\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "2370"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 13:38:24 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "17960"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        },
+        {
+          "last-modified": "Mon, 08 Nov 2010 14:53:56 GMT"
+        },
+        {
+          "keep-alive": "timeout=5, max=713"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 20:52:06 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:45:30 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:45:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "18377"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "60774"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+ZhxgFZ2Xd28p4N8+qai9qH+vXEtJkM6N3AzKCRseBomFyz6/H0m; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:24 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas09-1"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 08 Nov 2010 14:53:48 GMT"
+        },
+        {
+          "content-length": "17610"
+        },
+        {
+          "cache-control": "max-age=63072000"
+        },
+        {
+          "expires": "Mon, 03 Nov 2014 13:38:23 GMT"
+        },
+        {
+          "vary": "X-CDN"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "keep-alive": "timeout=5, max=793"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "server": "Omniture DC/2.0.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu,  2 Nov 2017 13:38:24 GMT; Domain=sa.bbc.com; Path=/"
+        },
+        {
+          "x-c": "ms-4.4.9"
+        },
+        {
+          "expires": "Fri, 02 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "last-modified": "Sun, 04 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "cache-control": "no-cache, no-store, max-age=0, no-transform, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "etag": "\"50951E50-1A84-669E56BC\""
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\""
+        },
+        {
+          "xserver": "www665"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "keep-alive": "timeout=15"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:08:06 GMT"
+        },
+        {
+          "cache-control": "max-age=62937399"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 00:15:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "content-length": "7180"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 15:54:41 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4902"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62848278"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 23:29:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 23:33:51 GMT"
+        },
+        {
+          "content-length": "3930"
+        },
+        {
+          "cache-control": "max-age=62935245"
+        },
+        {
+          "expires": "Sat, 01 Nov 2014 23:39:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=72911efde47ed7df994991b8bfad50951e1458d396-6634083950951e50834_3366; expires=Sat, 03-Nov-2012 14:08:24 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:02:53 GMT"
+        },
+        {
+          "content-length": "3589"
+        },
+        {
+          "cache-control": "max-age=62846973"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 23:07:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-type": "text/plain"
+        },
+        {
+          "content-length": "15586"
+        },
+        {
+          "cache-control": "private, max-age=506675"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "20151"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 17:13:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0544416d4b2cd1:b56\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 05 Mar 2012 12:20:37 GMT"
+        },
+        {
+          "cache-control": "max-age=42072135"
+        },
+        {
+          "expires": "Wed, 05 Mar 2014 12:20:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:22 GMT"
+        },
+        {
+          "content-length": "59958"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 08:26:48 GMT"
+        },
+        {
+          "cache-control": "max-age=62707710"
+        },
+        {
+          "expires": "Thu, 30 Oct 2014 08:26:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "content-length": "189"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 15:18:41 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5471"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62387032"
+        },
+        {
+          "expires": "Sun, 26 Oct 2014 15:22:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 15 Nov 2011 09:49:33 GMT"
+        },
+        {
+          "content-length": "3645"
+        },
+        {
+          "cache-control": "max-age=59275525"
+        },
+        {
+          "expires": "Sat, 20 Sep 2014 15:03:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 01:30:29 GMT"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5937"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "max-age=62942201"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 01:35:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 17:42:14 GMT"
+        },
+        {
+          "cache-control": "max-age=63000297"
+        },
+        {
+          "expires": "Sun, 02 Nov 2014 17:43:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "content-length": "6807"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "x-pad": "avoid browser bug"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:03:40 GMT"
+        },
+        {
+          "content-length": "4382"
+        },
+        {
+          "cache-control": "max-age=62846946"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 23:07:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 23:49:59 GMT"
+        },
+        {
+          "content-length": "5299"
+        },
+        {
+          "cache-control": "max-age=62768266"
+        },
+        {
+          "expires": "Fri, 31 Oct 2014 01:16:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:26 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:26 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "29965"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 17:12:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"02d8becd3b2cd1:b56\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:31 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:31 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.nedstat.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND NAV COM\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:31 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 01 Mar 2006 15:13:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "max-age=0, no-cache=Set-Cookie"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:31 GMT"
+        },
+        {
+          "keep-alive": "timeout=10, max=91"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "312"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:32 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "1216"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:32 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:32 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "4631"
+        },
+        {
+          "set-cookie": "PRpc=|HrYwHDG0:1|HrYvHDG1:2|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:38:32 GMT;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "322"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 11:50:26 GMT"
+        },
+        {
+          "cache-control": "max-age=53907180"
+        },
+        {
+          "expires": "Sun, 20 Jul 2014 11:51:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:32 GMT"
+        },
+        {
+          "content-length": "2149"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-disposition": "attachment"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1660"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "609"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "291301914"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:32 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "2882"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "320"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "50"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 10:23:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "nginx/0.8.54"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:26 GMT"
+        },
+        {
+          "content-type": "application/xml"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "set-cookie": "pixel_f52666608=1; Domain=.dimestore.com; Expires=Sun, 03-Nov-2013 13:38:26 GMT"
+        },
+        {
+          "location": "http://content.dimestore.com/pixel.gif"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:30 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "91710"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cache-action": "MISS"
+        },
+        {
+          "x-cache-age": "0"
+        },
+        {
+          "cache-control": "private, max-age=0, must-revalidate"
+        },
+        {
+          "x-lb-nocache": "true"
+        },
+        {
+          "vary": "X-CDN"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "538"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "356"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "539"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-length": "545"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:34 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "321"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:34 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "18600"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:03:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:34 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Sun, 05-Jun-2005 22:00:00 GMT"
+        },
+        {
+          "set-cookie": "u2=0c1d5772-7a75-4913-9e34-91b1ec36e6763Qv0bg; expires=Fri, 01-Feb-2013 09:38:34 GMT; domain=.serving-sys.com; path=/"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"NOI DEVa OUR BUS UNI\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:33 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "245"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:34 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.6.35"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "last-modified": "Fri, 05 Aug 2011 18:45:32 GMT"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:34 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:35 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 23:30:39 GMT"
+        },
+        {
+          "etag": "\"bed15b-d00-4ca1664f965c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "3328"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "set-cookie": "BMX_3PC=1; path=/; domain=.voicefive.com;"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI COR NID CUR DEV TAI PSA IVA OUR STA UNI NAV INT\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "User-Agent,Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8240"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "content-length": "392"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "CMDD=AAIWeQE*;domain=casalemedia.com;path=/;expires=Sun, 04 Nov 2012 13:38:37 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLuBg59Xwl/EEO1FURBA3cAlgmns+bAxJsyTL2hw/WD8n92ZW/I4JwcH7E4ANXFCKgXlxsjUzY2F7dfMxN21mUJt+5Zxhw==; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:38:37 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas02-1"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "server": "Omniture DC/2.0.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "set-cookie": "s_vi=[CS]v1|284A8F0905160D8B-600001A1C0108CD4[CE]; Expires=Thu,  2 Nov 2017 13:38:37 GMT; Domain=sa.bbc.com; Path=/"
+        },
+        {
+          "x-c": "ms-4.4.9"
+        },
+        {
+          "expires": "Fri, 02 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "last-modified": "Sun, 04 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "cache-control": "no-cache, no-store, max-age=0, no-transform, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "etag": "\"50951E5D-2288-2D7FF956\""
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA OUR IND COM NAV STA\""
+        },
+        {
+          "xserver": "www381"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "keep-alive": "timeout=15"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-length": "173"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "v=b90bb042855f902565c991b8bfad50951e1458d396-6634083950951e5d834_3366; expires=Sat, 03-Nov-2012 14:08:37 GMT; path=/; domain=.effectivemeasure.net"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "server": "collection10"
+        },
+        {
+          "cache-directive": "no-cache"
+        },
+        {
+          "pragma-directive": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache/2.2.19 (Unix)"
+        },
+        {
+          "content-type": "application/json;charset=UTF-8"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "access-control-allow-methods": "POST, GET, PUT, OPTIONS"
+        },
+        {
+          "access-control-allow-headers": "Content-Type, X-Requested-With, *"
+        },
+        {
+          "content-length": "112"
+        },
+        {
+          "cache-control": "max-age=17"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 24 Jun 2005 22:51:33 GMT"
+        },
+        {
+          "etag": "\"fec19c-1b-3fa51a4b8c740\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "38"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 15:55:36 GMT"
+        },
+        {
+          "etag": "\"4016f-8a-4cca7e25a0e00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "135"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "273"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:38 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/2179194/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:38:38 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:41 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_24.json b/jetty-http2/http2-hpack/src/test/resources/data/story_24.json
new file mode 100644
index 0000000..c294895
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_24.json
@@ -0,0 +1,1187 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "location": "http://www.craigslist.org/about/sites/"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:34:16 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=14400"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 10:03:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 10:03:45 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "10344"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 10:03:45 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 22:03:00 GMT"
+        },
+        {
+          "date": "Tue, 16 Oct 2012 22:03:00 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1099"
+        },
+        {
+          "content-type": "text/css; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 15 Nov 2012 22:03:00 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=15, public"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:33:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:33:59 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "6344"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:34:14 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 06:13:28 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 06:13:28 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "28017"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:13:28 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "last-modified": "Mon, 23 Jun 2008 23:06:11 GMT"
+        },
+        {
+          "cache-control": "public, max-age=315360000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 05:33:00 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1150"
+        },
+        {
+          "content-type": "text/plain"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Fri, 07 Oct 2022 05:33:00 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=3600, public"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 12:36:54 GMT"
+        },
+        {
+          "set-cookie": "cl_def_hp=shoals; domain=.craigslist.org; path=/; expires=Sun, 03-Nov-13 12:36:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:36:54 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "6245"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:36:54 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:53:37 GMT"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 20:53:37 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "6047"
+        },
+        {
+          "content-type": "text/css; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Dec 2012 20:53:37 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:53:17 GMT"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 20:53:17 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "6344"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Dec 2012 20:53:17 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 06:01:51 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 06:01:51 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "473"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:01:51 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 06:01:55 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 06:01:55 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "28017"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:01:55 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "last-modified": "Mon, 23 Jun 2008 23:06:11 GMT"
+        },
+        {
+          "cache-control": "public, max-age=315360000"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 05:33:00 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1150"
+        },
+        {
+          "content-type": "text/plain"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Fri, 07 Oct 2022 05:33:00 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=600"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:34:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:34:21 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "9660"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:49:21 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 06:21:38 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 06:21:38 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "225"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:21:38 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 07:20:18 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 07:20:18 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "2857"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 07:20:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 21:50:50 GMT"
+        },
+        {
+          "date": "Tue, 30 Oct 2012 21:50:50 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1398"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 29 Nov 2012 21:50:50 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 21:26:48 GMT"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 21:26:48 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "40353"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 01 Dec 2012 21:26:48 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 21:46:27 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:46:27 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "2458"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sun, 02 Dec 2012 21:46:27 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 22:07:17 GMT"
+        },
+        {
+          "date": "Mon, 15 Oct 2012 22:07:17 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "727"
+        },
+        {
+          "content-type": "text/javascript; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Wed, 14 Nov 2012 22:07:17 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:46:28 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:46:27 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:46:28 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 21:46:27 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=600"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:34:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:34:17 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "10780"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:49:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:17:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:17:50 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "2245"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 13:17:50 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 22:00:11 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 27 Oct 2012 12:09:05 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 27 Oct 2012 07:36:12 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=2592000"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Mon, 22 Oct 2012 22:00:12 GMT"
+        },
+        {
+          "server": "Apache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=14400"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 12:53:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:53:23 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "5733"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 12:53:23 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=14400"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 10:58:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 10:58:55 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1480"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 10:58:55 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "public, max-age=14400"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 09:53:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 09:53:38 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "10400"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Mon, 03 Dec 2012 09:53:38 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "max-age=2592000, public"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 06:01:47 GMT"
+        },
+        {
+          "date": "Tue, 09 Oct 2012 06:01:47 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "4861"
+        },
+        {
+          "content-type": "text/css; charset=iso-8859-1"
+        },
+        {
+          "x-frame-options": "Allow-From https://forums.craigslist.org"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:01:47 GMT"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_25.json b/jetty-http2/http2-hpack/src/test/resources/data/story_25.json
new file mode 100644
index 0000000..a974038
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_25.json
@@ -0,0 +1,8637 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "etag": ""
+        },
+        {
+          "last-modified": "Sat, 3 Nov 2012 13:18:25 GMT"
+        },
+        {
+          "location": "http://www.ebay.com"
+        },
+        {
+          "rlogid": "p4fug%60fvehq%60%3C%3Dsm%2Bpu56*a37%3Fb0%60-13ac6788085"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:56 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:57 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "14114"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:56 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:07:22 GMT"
+        },
+        {
+          "etag": "\"558014-cc3-4cd77eb75a280\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "3267"
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.g15ea31-13ac67885c6-0x1a1"
+        },
+        {
+          "set-cookie": "npii=bcguid/c67885c613a0a0a9f6568b16ff5917ee5276504e^tguid/c67883f113a0a56964e646c6ffaa1ac15276504e^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:58 GMT; Path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\""
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:57 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:31:45 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "49"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 23:53:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "2539"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "expires": "Mon, 10 Dec 2012 22:14:50 GMT"
+        },
+        {
+          "last-modified": "Tue, 10 Jul 2012 00:18:56 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "219"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "last-modified": "Tue, 10 Jul 2012 00:17:53 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"808e7072315ecd1:5f1\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "201"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "last-modified": "Wed, 18 Jul 2012 20:33:33 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "1623"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F72%3D-13ac6788850-0x16f"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7E6-13ac678862e-0xfb"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:57 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7Eb-13ac6788670-0x141"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:57 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07p-13a4b38c06e-0x161"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 23:50:57 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "4212"
+        },
+        {
+          "cache-control": "max-age=29468235"
+        },
+        {
+          "expires": "Thu, 10 Oct 2013 15:09:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07%3B-13a65e7cdbc-0x16b"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 19:11:16 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "5662"
+        },
+        {
+          "cache-control": "max-age=29915920"
+        },
+        {
+          "expires": "Tue, 15 Oct 2013 19:30:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07m-13abdd493d5-0x16d"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:39:43 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "9184"
+        },
+        {
+          "cache-control": "max-age=31391044"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 21:16:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 31 Jan 2012 02:58:34 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "3282"
+        },
+        {
+          "cache-control": "max-age=23333195"
+        },
+        {
+          "expires": "Wed, 31 Jul 2013 14:58:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 06 Sep 2012 16:51:31 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "5440"
+        },
+        {
+          "cache-control": "max-age=26536771"
+        },
+        {
+          "expires": "Fri, 06 Sep 2013 16:51:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 19:15:19 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5148"
+        },
+        {
+          "cache-control": "max-age=31458789"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 16:05:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5679"
+        },
+        {
+          "cache-control": "public, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:31:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 19:19:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7150"
+        },
+        {
+          "cache-control": "max-age=31468533"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 18:47:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 05:51:41 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "5679"
+        },
+        {
+          "cache-control": "max-age=30644382"
+        },
+        {
+          "expires": "Thu, 24 Oct 2013 05:51:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 21:24:39 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5636"
+        },
+        {
+          "cache-control": "max-age=31450187"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 13:41:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 23:03:23 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7177"
+        },
+        {
+          "cache-control": "max-age=31488510"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 00:20:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:41:38 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8702"
+        },
+        {
+          "cache-control": "max-age=31321403"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 01:55:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 14:29:39 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13046"
+        },
+        {
+          "cache-control": "max-age=29637746"
+        },
+        {
+          "expires": "Sat, 12 Oct 2013 14:14:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*tm63.%3C72om6%3E-13abcb35937-0x14e"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 21:07:34 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "60906"
+        },
+        {
+          "cache-control": "max-age=31372049"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 15:59:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 18 Sep 2012 01:10:29 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "42205"
+        },
+        {
+          "cache-control": "max-age=27517110"
+        },
+        {
+          "expires": "Wed, 18 Sep 2013 01:10:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53359"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "private, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:31:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 18:06:59 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "2583"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F710-13ac67892f3-0x131"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "set-cookie": "PS=T.0; Domain=main.ebayrtm.com; Expires=Sun, 03-Nov-2013 13:32:01 GMT; Path=/rtm"
+        },
+        {
+          "location": "http://srx.main.ebayrtm.com/rtm?RtmCmd&a=json&l=@@__@@__@@&g=c67883f113a0a56964e646c6ffaa1ac1&c=1H4sIAAAAAAAAAB2OwWrCQBCG74LvMOClLXR3Zsckm8gevLR4SEuJhx5ySdMVg6krujXap%2B8kMDDD%2F%2F18zKJqIryFKyADpgVTkWRQVlswSGY%2BOzGjK8Nf1%2FeNThTCQ9m03TGGy34Fm2P0PUgA7xV8AqGyKzhf64JShY%2Fw6ttD0OJBGYKX7ux34aZHKGIyTlbbfTu29S9KR0LDS%2Fec5yO27BLKs%2BkkJw6cvjFuH%2BOpLrQehkH5r%2Bau2vAzIWkxKjK5Sq3KeMxs5vzmY90flk%2Fz2T9Cveg66wAAAA%3D%3D&p=11527:11528:11529&di=11527:11528:11529&v=4&enc=UTF-8&bm=286807&ord=1351949521580&cg=c67885c613a0a0a9f6568b16ff5917ee&cb=vjo.dsf.assembly.VjClientAssembler._callback0&_vrdm=1351949521581&r=yes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "Mon, 10 Dec 2012 02:40:28 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Jul 2009 18:33:39 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "1406"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:56 GMT"
+        },
+        {
+          "last-modified": "Mon, 13 Jul 2009 22:43:33 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8018ba59b4ca1:5d2\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "386"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Jul 2009 18:33:41 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "3155"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F715-13ac6789351-0x12a"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "4320"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908; Domain=main.ebayrtm.com; Path=/rtm"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 01:07:49 GMT"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 18:48:16 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "92574"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "last-modified": "Thu, 29 Mar 2012 22:36:00 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"048ac50fcdcd1:603\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "35128"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07m-133f0e5fedc-0x142"
+        },
+        {
+          "last-modified": "Tue, 29 Nov 2011 19:19:17 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-length": "545"
+        },
+        {
+          "cache-control": "max-age=30563305"
+        },
+        {
+          "expires": "Wed, 23 Oct 2013 07:20:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:02 GMT"
+        },
+        {
+          "expires": "Tue, 18 Dec 2012 00:25:08 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:26:02 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "22428"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:02 GMT"
+        },
+        {
+          "expires": "Tue, 18 Dec 2012 00:25:05 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:28:28 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "33895"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:02 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 16:09:55 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:41:38 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "38761"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:02 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 15:00:24 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 14:28:46 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "60078"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750d%7F23-13abd599c11-0x167"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 20:14:10 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "72619"
+        },
+        {
+          "cache-control": "max-age=31382938"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 19:00:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*tm63.%3C72om6%3E-13ac20abb51-0x14c"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 16:52:54 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "69800"
+        },
+        {
+          "cache-control": "max-age=31461635"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 16:52:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:31:57 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-length": "1150"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:06 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:31:45 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 23:53:57 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "2539"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "last-modified": "Thu, 30 Jul 2009 23:41:29 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "53"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:14:28 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 05:56:41 GMT"
+        },
+        {
+          "last-modified": "Thu, 30 Jul 2009 23:41:33 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "53"
+        },
+        {
+          "etag": "\"80b4fd446f11ca1:876\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:07 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "24567"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 17:51:49 GMT"
+        },
+        {
+          "last-modified": "Sun, 26 Feb 2012 07:40:00 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1968"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 16:37:50 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Jul 2009 20:18:42 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "613"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:57 GMT"
+        },
+        {
+          "last-modified": "Thu, 23 Aug 2007 20:40:22 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "229"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 05:56:41 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2007 21:44:36 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "1887"
+        },
+        {
+          "etag": "\"0bad4c1cf6c81:682\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:31:45 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "49"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 22:20:32 GMT"
+        },
+        {
+          "last-modified": "Sat, 23 Apr 2011 09:37:40 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3936"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Thu, 13 Dec 2012 18:43:54 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4059"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "expires": "Thu, 13 Dec 2012 18:24:38 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:15:08 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4397"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 19 Jan 2012 01:26:02 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "10248"
+        },
+        {
+          "cache-control": "max-age=22290839"
+        },
+        {
+          "expires": "Fri, 19 Jul 2013 13:26:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 10 Nov 2011 13:27:41 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "1794"
+        },
+        {
+          "cache-control": "max-age=16286156"
+        },
+        {
+          "expires": "Sat, 11 May 2013 01:28:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 19 May 2012 13:20:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2031"
+        },
+        {
+          "cache-control": "max-age=4358180"
+        },
+        {
+          "expires": "Mon, 24 Dec 2012 00:08:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 14:04:13 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2394"
+        },
+        {
+          "cache-control": "max-age=31533954"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 12:58:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 13:43:50 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3680"
+        },
+        {
+          "cache-control": "max-age=31532824"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 12:39:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 16 Jun 2012 04:23:57 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3263"
+        },
+        {
+          "cache-control": "max-age=10191966"
+        },
+        {
+          "expires": "Fri, 01 Mar 2013 12:38:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 04 Sep 2012 13:46:03 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2469"
+        },
+        {
+          "cache-control": "max-age=26067492"
+        },
+        {
+          "expires": "Sun, 01 Sep 2013 06:30:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 17 Dec 2011 17:14:44 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "2521"
+        },
+        {
+          "cache-control": "max-age=19496613"
+        },
+        {
+          "expires": "Mon, 17 Jun 2013 05:15:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 15 Dec 2011 00:35:12 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "9133"
+        },
+        {
+          "cache-control": "max-age=19263809"
+        },
+        {
+          "expires": "Fri, 14 Jun 2013 12:35:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 14:11:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3761"
+        },
+        {
+          "cache-control": "max-age=31534424"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:05:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 23 Sep 2012 00:16:12 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2956"
+        },
+        {
+          "cache-control": "max-age=27524859"
+        },
+        {
+          "expires": "Wed, 18 Sep 2013 03:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 14:13:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2236"
+        },
+        {
+          "cache-control": "max-age=31105641"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 13:59:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 07 May 2012 03:34:14 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1500"
+        },
+        {
+          "cache-control": "max-age=4657042"
+        },
+        {
+          "expires": "Thu, 27 Dec 2012 11:09:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 21:46:06 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2528"
+        },
+        {
+          "cache-control": "max-age=28697569"
+        },
+        {
+          "expires": "Tue, 01 Oct 2013 17:04:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 21:27:24 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1930"
+        },
+        {
+          "cache-control": "max-age=28812498"
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 01:00:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 20 Oct 2012 02:57:28 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1722"
+        },
+        {
+          "cache-control": "max-age=30889406"
+        },
+        {
+          "expires": "Sun, 27 Oct 2013 01:55:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 14:30:13 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2961"
+        },
+        {
+          "cache-control": "max-age=16431611"
+        },
+        {
+          "expires": "Sun, 12 May 2013 17:52:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 14:14:04 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2160"
+        },
+        {
+          "cache-control": "max-age=30945129"
+        },
+        {
+          "expires": "Sun, 27 Oct 2013 17:24:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 14:11:43 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2841"
+        },
+        {
+          "cache-control": "max-age=30221178"
+        },
+        {
+          "expires": "Sat, 19 Oct 2013 08:18:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 07 May 2012 13:59:59 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1541"
+        },
+        {
+          "cache-control": "max-age=7259332"
+        },
+        {
+          "expires": "Sat, 26 Jan 2013 14:00:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 06 Jun 2012 14:05:14 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2123"
+        },
+        {
+          "cache-control": "max-age=12334548"
+        },
+        {
+          "expires": "Tue, 26 Mar 2013 07:47:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 14:21:18 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "947"
+        },
+        {
+          "cache-control": "max-age=27136636"
+        },
+        {
+          "expires": "Fri, 13 Sep 2013 15:29:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 14:45:15 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1846"
+        },
+        {
+          "cache-control": "max-age=29813010"
+        },
+        {
+          "expires": "Mon, 14 Oct 2013 14:55:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 14:17:41 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2166"
+        },
+        {
+          "cache-control": "max-age=30506466"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 15:33:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 13:48:57 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3964"
+        },
+        {
+          "cache-control": "max-age=31161579"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 05:31:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 13:43:32 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4653"
+        },
+        {
+          "cache-control": "max-age=30556712"
+        },
+        {
+          "expires": "Wed, 23 Oct 2013 05:30:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 11 Sep 2012 18:42:51 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "31476"
+        },
+        {
+          "cache-control": "max-age=26975444"
+        },
+        {
+          "expires": "Wed, 11 Sep 2013 18:42:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 17 Dec 2011 17:14:45 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "11181"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "max-age=19496528"
+        },
+        {
+          "expires": "Mon, 17 Jun 2013 05:14:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 14:19:33 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5580"
+        },
+        {
+          "cache-control": "max-age=31535661"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:26:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9vl*th%7Fbad%7F714-13ac678af80-0x141"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "903"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:08 GMT"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908%011351949527269%02981%04-1%060%03980%04-1%060%03979%04-1%060%03688%04-1%060%03255%04-1%060; Domain=main.ebayrtm.com; Path=/rtm"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:09 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 16:40:39 GMT"
+        },
+        {
+          "last-modified": "Wed, 10 Jun 2009 16:58:56 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "1161"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:09 GMT"
+        },
+        {
+          "expires": "Wed, 28 Nov 2012 05:06:23 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 May 2009 01:16:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "1180"
+        },
+        {
+          "etag": "\"04864dfc3d5c91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "66"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 19 Jun 2009 17:50:32 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"064b8706f1c91:682\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:09 GMT"
+        },
+        {
+          "expires": "Sat, 27 Oct 2012 08:29:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:09 GMT"
+        },
+        {
+          "expires": "Thu, 13 Dec 2012 19:35:46 GMT"
+        },
+        {
+          "last-modified": "Thu, 17 Mar 2011 21:09:01 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "13713"
+        },
+        {
+          "etag": "\"0bad4c1cf6c81:682\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 14 Feb 2012 08:00:47 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "53098"
+        },
+        {
+          "cache-control": "max-age=24560912"
+        },
+        {
+          "expires": "Wed, 14 Aug 2013 20:00:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 23:46:15 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "27209"
+        },
+        {
+          "cache-control": "max-age=31054448"
+        },
+        {
+          "expires": "Mon, 28 Oct 2013 23:46:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "397"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:10 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:10 GMT"
+        },
+        {
+          "expires": "Sat, 15 Dec 2012 09:56:28 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Aug 2003 20:42:27 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "49"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:10 GMT"
+        },
+        {
+          "last-modified": "Mon, 08 Mar 2010 19:32:35 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "146"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 20:38:55 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1918"
+        },
+        {
+          "cache-control": "max-age=30051310"
+        },
+        {
+          "expires": "Thu, 17 Oct 2013 09:07:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:00:33 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 18:12:07 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 18:12:07 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "26810"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "69603"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-length": "1150"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:11 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 00:29:24 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:03:54 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "260"
+        },
+        {
+          "etag": "\"04864dfc3d5c91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "expires": "Tue, 11 Dec 2012 20:45:48 GMT"
+        },
+        {
+          "last-modified": "Fri, 27 Aug 2010 00:22:53 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:04:39 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "172"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 16:57:28 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:12 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "90925"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:11 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "expires": "Thu, 13 Dec 2012 19:00:40 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "11504"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "expires": "Thu, 13 Dec 2012 19:00:40 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "11504"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 18 Oct 2012 22:46:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3962"
+        },
+        {
+          "cache-control": "max-age=29068398"
+        },
+        {
+          "expires": "Sun, 06 Oct 2013 00:05:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:53:50 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4670"
+        },
+        {
+          "cache-control": "max-age=31276058"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 13:19:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 01:52:55 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5679"
+        },
+        {
+          "cache-control": "max-age=28834042"
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 06:59:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 25 Jul 2012 20:50:41 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3929"
+        },
+        {
+          "cache-control": "max-age=17978904"
+        },
+        {
+          "expires": "Thu, 30 May 2013 15:40:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 06 Aug 2012 06:13:28 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2473"
+        },
+        {
+          "cache-control": "max-age=22036778"
+        },
+        {
+          "expires": "Tue, 16 Jul 2013 14:51:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6172"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "private, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 16 Mar 2012 00:40:23 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "52950"
+        },
+        {
+          "cache-control": "max-age=27212892"
+        },
+        {
+          "expires": "Sat, 14 Sep 2013 12:40:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 27 May 2012 12:26:18 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6163"
+        },
+        {
+          "cache-control": "max-age=17941535"
+        },
+        {
+          "expires": "Thu, 30 May 2013 05:17:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 13 Aug 2012 06:52:35 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4526"
+        },
+        {
+          "cache-control": "max-age=24498920"
+        },
+        {
+          "expires": "Wed, 14 Aug 2013 02:47:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "48924"
+        },
+        {
+          "cache-control": "public, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 16:40:39 GMT"
+        },
+        {
+          "last-modified": "Wed, 19 Oct 2011 00:48:19 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "275"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "1145"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Tue, 15 Feb 2011 17:36:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80b7dad536cdcb1:854\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:59:25 GMT"
+        },
+        {
+          "last-modified": "Wed, 02 Feb 2011 19:43:17 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "3546"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "expires": "Thu, 27 Sep 2012 23:15:40 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "6342"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 03:40:20 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "10896"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 05:44:38 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:57 GMT"
+        },
+        {
+          "last-modified": "Fri, 22 Jun 2012 22:09:21 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "59719"
+        },
+        {
+          "etag": "\"04864dfc3d5c91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        },
+        {
+          "last-modified": "Fri, 22 Jun 2012 22:09:21 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "59719"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:57 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.62d5%3C%3E7-13ac678c943-0x1a4"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/json"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:14 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:16 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "80046"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:15 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 13:46:54 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "739"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Thu, 22 Nov 2012 14:19:41 GMT"
+        },
+        {
+          "last-modified": "Sat, 23 Apr 2011 09:37:40 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1649"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 06:10:27 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:01:04 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "134"
+        },
+        {
+          "etag": "\"078525ce2cc51:586\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 05:08:13 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Oct 2005 18:47:40 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "231"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Sun, 09 Dec 2012 06:52:18 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Sep 2005 19:37:46 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "643"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 04:43:31 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "369"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "199"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 21 Oct 2005 18:47:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80b7dad536cdcb1:854\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "last-modified": "Wed, 04 Mar 2009 03:12:30 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "2388"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        },
+        {
+          "expires": "Sun, 16 Dec 2012 05:44:38 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Mon, 19 Nov 2012 22:20:46 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:31:30 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1713"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Sun, 11 Nov 2012 06:40:21 GMT"
+        },
+        {
+          "last-modified": "Thu, 09 Sep 2010 17:30:38 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1389"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 04:31:42 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:04:34 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "141"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:56 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:05:11 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "136"
+        },
+        {
+          "etag": "\"80ad8befe2cc51:8e4\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Thu, 29 Nov 2012 16:39:21 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Aug 2011 07:55:09 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6651"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:16 GMT"
+        },
+        {
+          "expires": "Thu, 06 Dec 2012 09:42:11 GMT"
+        },
+        {
+          "last-modified": "Mon, 28 Mar 2011 14:55:59 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13825"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Sat, 16 Aug 2003 20:42:25 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:57 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890;Domain=.ebay.com;Expires=Thu, 02-Nov-2017 13:32:21 GMT;Path=/ "
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "80046"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "expires": "Sun, 18 Nov 2012 22:28:04 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2007 21:44:39 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "3179"
+        },
+        {
+          "etag": "\"078525ce2cc51:586\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Fri, 27 Aug 2010 00:22:48 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "391"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:13:22 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Fri, 18 Mar 2005 23:05:11 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "136"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Sep 2007 00:11:47 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "542"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Jul 2006 00:07:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0aa151a90a0c61:5e2\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 24 May 2011 22:33:41 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "1351"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 15:13:22 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Sep 2007 00:21:31 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80f7a0df1bf0c71:5b1\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "6386"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 23:31:47 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "3276"
+        },
+        {
+          "cache-control": "max-age=30794366"
+        },
+        {
+          "expires": "Fri, 25 Oct 2013 23:31:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 23:31:47 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "668"
+        },
+        {
+          "cache-control": "max-age=30794366"
+        },
+        {
+          "expires": "Fri, 25 Oct 2013 23:31:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 14 Jul 2012 00:50:47 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "44"
+        },
+        {
+          "cache-control": "max-age=21813506"
+        },
+        {
+          "expires": "Sun, 14 Jul 2013 00:50:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:56 GMT"
+        },
+        {
+          "last-modified": "Tue, 02 Feb 2010 19:44:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "13817"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-language": "cs-CZ"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6172"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "private, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:28:30 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "6661"
+        },
+        {
+          "cache-control": "max-age=31413369"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 03:28:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 01:08:44 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "351"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "max-age=21123378"
+        },
+        {
+          "expires": "Sat, 06 Jul 2013 01:08:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 03:07:31 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4553"
+        },
+        {
+          "cache-control": "max-age=29866596"
+        },
+        {
+          "expires": "Tue, 15 Oct 2013 05:48:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 22 Sep 2012 19:51:38 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4694"
+        },
+        {
+          "cache-control": "max-age=24377502"
+        },
+        {
+          "expires": "Mon, 12 Aug 2013 17:04:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 21:48:15 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5307"
+        },
+        {
+          "cache-control": "max-age=31498703"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 03:10:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 23:32:05 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "3014"
+        },
+        {
+          "cache-control": "max-age=30794343"
+        },
+        {
+          "expires": "Fri, 25 Oct 2013 23:31:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "expires": "Tue, 18 Dec 2012 13:32:22 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:53:41 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "15981"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "expires": "Sun, 18 Nov 2012 22:28:04 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 Jun 2010 01:28:28 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "578"
+        },
+        {
+          "etag": "\"0c688b6514cb1:586\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-language": "pt-BR"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9688"
+        },
+        {
+          "cache-control": "public, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 20 Sep 2011 23:59:47 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "1780"
+        },
+        {
+          "etag": "\"80e3ea8c9abcd1:639\""
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 00:03:41 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07p-139944fe49b-0x176"
+        },
+        {
+          "last-modified": "Thu, 23 Aug 2012 17:24:32 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-length": "8722"
+        },
+        {
+          "cache-control": "max-age=26399474"
+        },
+        {
+          "expires": "Thu, 05 Sep 2013 02:43:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "last-modified": "Wed, 12 Jan 2011 20:27:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "342"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 16:35:19 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:55 GMT"
+        },
+        {
+          "last-modified": "Wed, 19 Oct 2011 01:17:47 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "6641"
+        },
+        {
+          "etag": "\"80af29e9fc8dcc1:8e4\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 11 Jul 2012 18:03:37 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2752"
+        },
+        {
+          "cache-control": "max-age=14608007"
+        },
+        {
+          "expires": "Sun, 21 Apr 2013 15:19:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Jul 2009 20:18:42 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "613"
+        },
+        {
+          "expires": "Mon, 26 Nov 2012 16:35:19 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "etag": "\"03d21f40ffc91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 22:44:28 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "551"
+        },
+        {
+          "cache-control": "max-age=21719526"
+        },
+        {
+          "expires": "Fri, 12 Jul 2013 22:44:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "expires": "Mon, 17 Dec 2012 20:39:34 GMT"
+        },
+        {
+          "last-modified": "Tue, 20 Sep 2011 02:08:20 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80183dd68badcd1:720\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "17673"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B4%603g-13ac678e4f2-0x104"
+        },
+        {
+          "set-cookie": "nonsession=CgADLAAFQlSPuMQDKACBZ+x5mYzY3OGU0YzgxM2EwYTVlNmM4ZDZjODQ2ZmZmOGYzYjlPrxuR;Domain=.raptor.ebaydesc.com;Expires=Sun, 03-Nov-2013 13:32:22 GMT;Path=/ "
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:03:20 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "54313"
+        },
+        {
+          "cache-control": "max-age=31401067"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 00:03:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:03:52 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "20701"
+        },
+        {
+          "cache-control": "max-age=31401093"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 00:03:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9ve*t%28747%60e%7E%3A-13ac678e523-0x15c"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "3577"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "set-cookie": "HT=1351949521580%0211529%04287876%06261345%0311528%04286823%06260443%0311527%04286801%06203908%011351949527269%02981%04-1%060%03980%04-1%060%03979%04-1%060%03688%04-1%060%03255%04-1%060%011351949541760%0211575%04-1%060%031527%04-1%060%03829%04-1%060%03912%04-1%060%03827%04-1%060%03876%04-1%060%03825%04-1%060%03433%04-1%060%031651%04-1%060%031650%04-1%060; Domain=main.ebayrtm.com; Path=/rtm"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 21:23:48 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "5138"
+        },
+        {
+          "cache-control": "max-age=31132229"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 21:22:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2007 21:44:39 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "3179"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 20:03:15 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "etag": "\"03d21f40ffc91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:23 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "7004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:47:00 GMT"
+        },
+        {
+          "last-modified": "Fri, 27 Aug 2010 00:22:54 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        },
+        {
+          "etag": "\"80af29e9fc8dcc1:8e4\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 04:43:31 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80fb69e73664c31:6fe\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "141"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "last-modified": "Mon, 25 Jul 2005 20:31:43 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "64"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:59 GMT"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "etag": "\"03d21f40ffc91:5b1\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "expires": "Sun, 18 Nov 2012 22:28:04 GMT"
+        },
+        {
+          "last-modified": "Tue, 25 Sep 2012 05:16:18 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "7623"
+        },
+        {
+          "etag": "\"0c688b6514cb1:586\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Fri, 19 Oct 2012 22:52:32 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "949"
+        },
+        {
+          "cache-control": "max-age=30273610"
+        },
+        {
+          "expires": "Sat, 19 Oct 2013 22:52:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:22 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Tue, 19 Jun 2012 05:08:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1069"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "max-age=19670318"
+        },
+        {
+          "expires": "Wed, 19 Jun 2013 05:31:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 03:14:23 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "6931"
+        },
+        {
+          "cache-control": "max-age=30721319"
+        },
+        {
+          "expires": "Fri, 25 Oct 2013 03:14:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlog": "uh%60jk%3D9vj*ts67.21336g2-13ac678eef8"
+        },
+        {
+          "x-ebay-request-id": "13ac678e-ef80-a5ac-0760-c260ff104b3e!ajax.all.get!10.90.192.118!ebay.com[]"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:24 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:25 GMT"
+        },
+        {
+          "expires": "Sun, 18 Nov 2012 22:28:04 GMT"
+        },
+        {
+          "last-modified": "Thu, 04 Oct 2012 18:56:36 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "9521"
+        },
+        {
+          "etag": "\"0c688b6514cb1:586\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%283ab%3D-13ac678ef91-0x19c"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/json"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:25 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:30 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "90235"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:30 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~`s,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7E%60s-13ac678cb27-0xb7"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:31 GMT"
+        },
+        {
+          "expires": "Thu, 27 Sep 2012 23:15:40 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:32 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "80050"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:31 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~go,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ego-13ac6790aa0-0xb6"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:32 GMT"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 04:43:31 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:32 GMT"
+        },
+        {
+          "expires": "Fri, 14 Dec 2012 13:33:03 GMT"
+        },
+        {
+          "last-modified": "Wed, 02 May 2012 23:09:29 GMT"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1544"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%28c1eg-13ac67910d1-0x179"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:32 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 29 May 2012 21:33:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4908"
+        },
+        {
+          "cache-control": "max-age=8305824"
+        },
+        {
+          "expires": "Thu, 07 Feb 2013 16:42:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:33 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:36 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "91130"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:36 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~go,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ego-13ac6790aa0-0xb6"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:37 GMT"
+        },
+        {
+          "expires": "Thu, 27 Sep 2012 23:15:40 GMT"
+        },
+        {
+          "last-modified": "Fri, 21 Jan 2011 20:52:52 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:37 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "80060"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:37 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:38 GMT"
+        },
+        {
+          "expires": "Fri, 26 Oct 2012 04:43:31 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Oct 2005 21:29:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "366"
+        },
+        {
+          "etag": "\"0aa782badb9cb1:682\""
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1290"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "private, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:39 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cteonnt-length": "4588"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9un%7F4g66%60%283d30-13ac67928dc-0x197"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:39 GMT"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "set-cookie": "npii=btguid/c67883f113a0a56964e646c6ffaa1ac152765078^cguid/c67885c613a0a0a9f6568b16ff5917ee52765078^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:40 GMT; Path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:39 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "91165"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:39 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc"
+        },
+        {
+          "rlogid": "t6ulcpjqcj9%3Fuk%601d72f%2B12%60b-13ac678e09e-0xc0"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9un%7F4g65%60%28555f-13ac6792d15-0x18d"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:41 GMT"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "set-cookie": "npii=bcguid/c67885c613a0a0a9f6568b16ff5917ee52765079^tguid/c67883f113a0a56964e646c6ffaa1ac152765079^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:41 GMT; Path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:42 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://www.ebay.com/fashion/health-beauty"
+        },
+        {
+          "rlogid": "p4pmiw%60jtb9%3Fv%7F.wcc%60dh72%3C-13ac6793402"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:42 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:43 GMT; Path=/"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-length": "12792"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "v .r+616d2tu,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fv%7F.r%2B616d2tu-13ac6791ff9-0xbc"
+        },
+        {
+          "rlogid": "p4u%60tsjfgkpfiuf%3F%3Ctq%28qq.d%605g%6053-13ac679336d"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:47:45 GMT"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 18:43:18 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "2469"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 16:22:27 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5850"
+        },
+        {
+          "cache-control": "max-age=31509956"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 06:18:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5679"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "public, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cteonnt-length": "4588"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 15:54:54 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6322"
+        },
+        {
+          "cache-control": "max-age=31522197"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 09:42:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g07n-13aac9b9c70-0x176"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 22:29:19 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "250"
+        },
+        {
+          "cache-control": "max-age=31102053"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 13:00:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 26 Dec 2011 17:33:25 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5900"
+        },
+        {
+          "cache-control": "max-age=31504816"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 04:52:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 15:32:58 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3953"
+        },
+        {
+          "cache-control": "max-age=31511815"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 06:49:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 17:37:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4418"
+        },
+        {
+          "cache-control": "max-age=29623692"
+        },
+        {
+          "expires": "Sat, 12 Oct 2013 10:20:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Sep 2010 09:07:24 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10098"
+        },
+        {
+          "cache-control": "private, max-age=31536000"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:32:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "last-modified": "Tue, 07 Aug 2012 21:01:25 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"804039cedf74cd1:603\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "113266"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 07 Aug 2012 05:29:55 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7341"
+        },
+        {
+          "cache-control": "max-age=19386157"
+        },
+        {
+          "expires": "Sat, 15 Jun 2013 22:35:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 21:57:15 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7462"
+        },
+        {
+          "cache-control": "max-age=31508534"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 05:54:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 02:39:26 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "10090"
+        },
+        {
+          "cache-control": "max-age=31501318"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 03:54:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 19:32:45 GMT"
+        },
+        {
+          "content-type": "text/css;charset=UTF-8"
+        },
+        {
+          "content-length": "6377"
+        },
+        {
+          "cache-control": "max-age=30002402"
+        },
+        {
+          "expires": "Wed, 16 Oct 2013 19:32:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 29 May 2012 19:40:07 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4488"
+        },
+        {
+          "cache-control": "max-age=7260395"
+        },
+        {
+          "expires": "Sat, 26 Jan 2013 14:19:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 23:29:38 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4889"
+        },
+        {
+          "cache-control": "max-age=19908420"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 23:39:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 09 Oct 2012 14:02:17 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3638"
+        },
+        {
+          "cache-control": "max-age=28507880"
+        },
+        {
+          "expires": "Sun, 29 Sep 2013 12:24:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 18:02:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5356"
+        },
+        {
+          "cache-control": "max-age=29198995"
+        },
+        {
+          "expires": "Mon, 07 Oct 2013 12:22:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 12 Jul 2012 01:56:06 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4607"
+        },
+        {
+          "cache-control": "max-age=20432905"
+        },
+        {
+          "expires": "Fri, 28 Jun 2013 01:21:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 23 Jul 2012 16:18:08 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5128"
+        },
+        {
+          "cache-control": "max-age=23738740"
+        },
+        {
+          "expires": "Mon, 05 Aug 2013 07:38:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 16:44:35 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7892"
+        },
+        {
+          "cache-control": "max-age=31534799"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:12:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 03:33:23 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4234"
+        },
+        {
+          "cache-control": "max-age=29726488"
+        },
+        {
+          "expires": "Sun, 13 Oct 2013 14:54:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 20 Aug 2012 20:26:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3021"
+        },
+        {
+          "cache-control": "max-age=26204352"
+        },
+        {
+          "expires": "Mon, 02 Sep 2013 20:31:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 15:22:25 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4919"
+        },
+        {
+          "cache-control": "max-age=30719689"
+        },
+        {
+          "expires": "Fri, 25 Oct 2013 02:47:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 22 Jul 2012 18:13:25 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4788"
+        },
+        {
+          "cache-control": "max-age=20831615"
+        },
+        {
+          "expires": "Tue, 02 Jul 2013 16:06:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 20:15:28 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3987"
+        },
+        {
+          "cache-control": "max-age=17873930"
+        },
+        {
+          "expires": "Wed, 29 May 2013 10:31:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 16 Aug 2012 14:53:01 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4623"
+        },
+        {
+          "cache-control": "max-age=20477655"
+        },
+        {
+          "expires": "Fri, 28 Jun 2013 13:46:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 27 Jul 2012 17:58:05 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4821"
+        },
+        {
+          "cache-control": "max-age=20499738"
+        },
+        {
+          "expires": "Fri, 28 Jun 2013 19:55:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 05:37:24 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5080"
+        },
+        {
+          "cache-control": "max-age=19887245"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 17:46:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:02:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "18863"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "max-age=40850"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:53:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 13:24:40 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "10030"
+        },
+        {
+          "cache-control": "max-age=31521522"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 09:31:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 16 Jul 2012 07:04:19 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6320"
+        },
+        {
+          "cache-control": "max-age=23373247"
+        },
+        {
+          "expires": "Thu, 01 Aug 2013 02:06:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "access-control-allow-origin": "*"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g3%7E1-13a3ef29997-0x16d"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 05:17:21 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "60127"
+        },
+        {
+          "cache-control": "max-age=29262216"
+        },
+        {
+          "expires": "Tue, 08 Oct 2013 05:56:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Tue, 10 Jul 2012 21:28:46 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5983"
+        },
+        {
+          "cache-control": "max-age=23738926"
+        },
+        {
+          "expires": "Mon, 05 Aug 2013 07:41:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 14:51:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "11895"
+        },
+        {
+          "cache-control": "max-age=31510005"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 06:19:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 08:46:05 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7674"
+        },
+        {
+          "cache-control": "max-age=31245727"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 04:54:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Wed, 08 Aug 2012 18:20:46 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "12744"
+        },
+        {
+          "cache-control": "max-age=26388803"
+        },
+        {
+          "expires": "Wed, 04 Sep 2013 23:46:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 19:38:43 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5852"
+        },
+        {
+          "cache-control": "max-age=27384452"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 12:20:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Tue, 22 Nov 2011 18:32:07 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6016"
+        },
+        {
+          "cache-control": "max-age=31505442"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 05:03:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 23 Sep 2012 20:27:09 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8741"
+        },
+        {
+          "cache-control": "max-age=28128091"
+        },
+        {
+          "expires": "Wed, 25 Sep 2013 02:54:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 18:53:28 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5727"
+        },
+        {
+          "cache-control": "max-age=31502723"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 04:18:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 19:32:46 GMT"
+        },
+        {
+          "content-type": "application/x-javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "54418"
+        },
+        {
+          "cache-control": "max-age=30002439"
+        },
+        {
+          "expires": "Wed, 16 Oct 2013 19:33:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 19:02:53 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "2288"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "expires": "Sun, 25 Nov 2012 23:46:56 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Aug 2011 00:39:15 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "cache-control": "max-age=3888000"
+        },
+        {
+          "content-length": "5743"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 15 Jul 2012 05:26:27 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6174"
+        },
+        {
+          "cache-control": "max-age=20606181"
+        },
+        {
+          "expires": "Sun, 30 Jun 2013 01:29:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 20:13:40 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8182"
+        },
+        {
+          "cache-control": "max-age=30802674"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 01:50:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g065-13911ec26be-0x16d"
+        },
+        {
+          "last-modified": "Wed, 08 Aug 2012 21:42:19 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "58636"
+        },
+        {
+          "cache-control": "max-age=24211902"
+        },
+        {
+          "expires": "Sat, 10 Aug 2013 19:04:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 03 Oct 2012 22:05:50 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"804039cedf74cd1:603\""
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "content-length": "63909"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 15:58:50 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13008"
+        },
+        {
+          "cache-control": "max-age=31535919"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:31:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4n%60rujfudlwc%3D9vt*ts67.4e6f0e0-13ac6793f33-0x19b"
+        },
+        {
+          "cache-control": "private, no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:45 GMT"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "set-cookie": "npii=btguid/c67883f113a0a56964e646c6ffaa1ac15276507d^cguid/c67885c613a0a0a9f6568b16ff5917ee5276507d^; Domain=.ebay.com; Expires=Sun, 03-Nov-2013 13:32:45 GMT; Path=/"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa ADMa DEVa PSDo PSAa OUR SAMo IND UNI COM NAV INT STA DEM PRE\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "rlogid": "p4pphdlwc%3D9u%7E*t%28750g3%7Fo-13a40772552-0x169"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 05:19:14 GMT"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "115864"
+        },
+        {
+          "cache-control": "max-age=29287759"
+        },
+        {
+          "expires": "Tue, 08 Oct 2013 13:02:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "2703"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Wed, 28 Mar 2012 22:30:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:44 GMT"
+        },
+        {
+          "expires": "Tue, 30 Oct 2012 19:27:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lucky9=1959890; Domain=.ebay.com; Expires=Thu, 02-Nov-2017 13:32:58 GMT; Path=/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "content-length": "80064"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:32:58 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 23:04:12 GMT"
+        },
+        {
+          "transaction": "uk.r+607b~k|,RcmdId FindingProductv4,RlogId p4pmiw%60jtb9%3Fuk.r%2B607b%7Ek%7C-13ac6796fd6-0xc1"
+        },
+        {
+          "rlogid": "p4u%60tsjfgkpfiuf%3F%3Ctq%28qq.d%605g%6053-13ac679336d"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_26.json b/jetty-http2/http2-hpack/src/test/resources/data/story_26.json
new file mode 100644
index 0000000..143ced2
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_26.json
@@ -0,0 +1,4439 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "IVe/SwucJuBsLtVHWJw2PMdOTOxuEWUir5igQNThkTg="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=17216869"
+        },
+        {
+          "expires": "Tue, 21 May 2013 19:18:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Tue, 24 Apr 2012 22:13:35 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "95tUymdadFLd8Dpml8VnOoUG7KhisOwk74Kd/aIGfU0="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "123"
+        },
+        {
+          "cache-control": "public, max-age=16394910"
+        },
+        {
+          "expires": "Sun, 12 May 2013 06:59:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:37:35 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "Qc0GcUiwi3io8aSRIdXaahYr6KKhphvV6NlN8vo/bD4="
+        },
+        {
+          "content-length": "14684"
+        },
+        {
+          "cache-control": "public, max-age=31067635"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:44:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:23 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "7exUqkoZxtfLseR1zLxJlXnpYK6MOognZuCKx7drdRo="
+        },
+        {
+          "content-length": "14438"
+        },
+        {
+          "cache-control": "public, max-age=24926560"
+        },
+        {
+          "expires": "Mon, 19 Aug 2013 00:53:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 17:08:56 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "eRvyJLXIvW3Vu9d+m439v+LGKqXiLSKmz7w9/xMAUpc="
+        },
+        {
+          "content-length": "17475"
+        },
+        {
+          "cache-control": "public, max-age=31124427"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 18:31:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 22:55:27 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "14hoEcywNNMBIVUS5B7AD7RDGiDvJ4BGeOVgJbBDzf0="
+        },
+        {
+          "content-length": "44191"
+        },
+        {
+          "cache-control": "public, max-age=31067635"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:44:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 18:34:48 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "41/HuGcFNMmys4cvGKlBeylojdVDP4+VBIf1giu3eNQ="
+        },
+        {
+          "content-length": "754"
+        },
+        {
+          "cache-control": "public, max-age=29985162"
+        },
+        {
+          "expires": "Wed, 16 Oct 2013 14:03:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 16:05:53 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "oKQwv0JLYost+zqlv8x+C7MEL7zRBbeMomoc54M5RZY="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2349"
+        },
+        {
+          "cache-control": "public, max-age=31067361"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:40:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "2626"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:08:50 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "zh8tRHKFtERIZ+K/eGiM1utm1H66OnOj1qwPAN7Ck9A="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31068570"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:00:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Fri, 28 Sep 2012 15:01:14 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "pricqIchHztHxKAQSidQiwGmRf62vAL6I7Oi0r/Ki08="
+        },
+        {
+          "content-length": "8036"
+        },
+        {
+          "cache-control": "public, max-age=31066940"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:42:19 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "Kur2FUUQjAQ0yPQJC9fvK56/+LWZHvyQF6Ce2Fuaf2k="
+        },
+        {
+          "content-length": "36302"
+        },
+        {
+          "cache-control": "public, max-age=31068470"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:58:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:51 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "wk2MWysJhw3Et7CRGMA1sE9HWuyzy8oCvtT2V7iPXeg="
+        },
+        {
+          "content-length": "8230"
+        },
+        {
+          "cache-control": "public, max-age=25639699"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 06:59:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:38:44 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "GMzzyj0B89LYf1zKH9hqxZekz5mYTmsuxwLugWyc2Gg="
+        },
+        {
+          "content-length": "4878"
+        },
+        {
+          "cache-control": "public, max-age=31068529"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:59:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:37:48 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:37:48 GMT"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-transfer-encoding": "binary"
+        },
+        {
+          "content-length": "1814"
+        },
+        {
+          "cache-control": "max-age=575215, public, no-transform, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:53 GMT"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":53,\"r\":26,\"q\":0,\"a\":25}"
+        },
+        {
+          "x-fb-server": "10.74.89.23"
+        },
+        {
+          "x-fb-debug": "7iLjsQVXsunUKXe3NlV2ytaBGzQ0VHCkMX/J6rEuB6Y="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 15:06:53 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "ur+THlFHeLotsmDlQWYPw2GRELyvg28JmE0JYVt56uo="
+        },
+        {
+          "content-length": "1155"
+        },
+        {
+          "cache-control": "public, max-age=31067714"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:46:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 31 Aug 2012 22:13:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "6/fKHkRtBpT4oqBg33tFHk2pO6SDZlUG11Uq4/AlUIE="
+        },
+        {
+          "content-length": "516"
+        },
+        {
+          "cache-control": "public, max-age=26316304"
+        },
+        {
+          "expires": "Wed, 04 Sep 2013 02:55:58 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "232"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Sat, 21 Apr 2012 07:03:57 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "XtTsONeGHGs/1vRRv8cvNY1ciB3XqlrvnTq2GZXvnqM="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=30419619"
+        },
+        {
+          "expires": "Mon, 21 Oct 2013 14:44:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Fri, 07 Sep 2012 15:18:40 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "E2JBYTapyXFjxTTVqkrekTVKDp1lDQQT/7YxcxfNU2U="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "400"
+        },
+        {
+          "cache-control": "public, max-age=31066933"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:41:45 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "iPbLdjapQzRoatbOUDrN+exDj8EPHJAcsZ48pVtprtA="
+        },
+        {
+          "content-length": "35766"
+        },
+        {
+          "cache-control": "public, max-age=31068980"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:34:50 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "0ci0R5R2ivIVCRrwtG507Eej+LTK8dUL8dIiZp70+dU="
+        },
+        {
+          "content-length": "10902"
+        },
+        {
+          "cache-control": "public, max-age=31066965"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:38:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "P2Bq0ebVXjtf8GyQp1HHux8NxlftUMXZuY8XF+yaOVo="
+        },
+        {
+          "content-length": "4676"
+        },
+        {
+          "cache-control": "public, max-age=31088728"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 08:36:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:37:10 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "yHzV/c0w3ZyInkRbLCDrA0t5adSMyAG4prBOk+i+t6Y="
+        },
+        {
+          "content-length": "20791"
+        },
+        {
+          "cache-control": "public, max-age=31067654"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:45:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "11113"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:34:47 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "u363OvKFmnm717JBUXA5ePB8Ts0ppRI7+eEJwOOep6w="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31066988"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:34:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:57 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "Yty+Te4OzfswtmjzbJmJZaybyM0hxXiRU2NtHEbDuPE="
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "public, max-age=25753573"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:37:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:24 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "yKFyrxwqBiumMPfWvv4morUUsmz9djZtSdmCoQMnchs="
+        },
+        {
+          "content-length": "571"
+        },
+        {
+          "cache-control": "public, max-age=25753811"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:41:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "HbryxnP7HNa7kdTChA6BppSjLQw0gz9ZzESCqEH3/9k="
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "public, max-age=25753770"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:40:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Tue, 28 Aug 2012 01:20:00 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "edgqdu1lFmUW32Et2hHoiAsp9kFIch8QDiciO71cQ4w="
+        },
+        {
+          "content-length": "12817"
+        },
+        {
+          "cache-control": "public, max-age=26458041"
+        },
+        {
+          "expires": "Thu, 05 Sep 2013 18:18:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:09:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "rXXtxI3fPgNHe6wKIDRBR0xjttUNeG+BDQM8QfKQa+A="
+        },
+        {
+          "content-length": "11688"
+        },
+        {
+          "cache-control": "public, max-age=31068990"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "35165"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:06:47 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "fUJ2Nc9qJdBC1AnYFA5Vs1f7ozv+i/PTKO+Vep0A0HQ="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31068521"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:59:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:00 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "s9ZmJKnYGlEjIGo8xQzxlhVM4nilGHgcv1fhK1Z7F1w="
+        },
+        {
+          "content-length": "1028"
+        },
+        {
+          "cache-control": "public, max-age=31191849"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 13:15:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:08 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "hMQvA7xhuAspt5fOxedr0fWzQZNLkyizVtlmspzgVG8="
+        },
+        {
+          "content-length": "47844"
+        },
+        {
+          "cache-control": "public, max-age=31068990"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:17:24 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "1EkJKYLfWucaDVhZCEVAAo57HpAH7rvF4r9IwDXM2B8="
+        },
+        {
+          "content-length": "42391"
+        },
+        {
+          "cache-control": "public, max-age=31143832"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 23:54:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "13181"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:10:32 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "dO6OKUf38jDdtAnTrM28wZTBz9Y5hU/0EJdd1CkWGDs="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31068989"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:03:57 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "IlZ4dyc3v7fqrfiamqJbFeFTWRkUvEUs2L8KLXNa+5o="
+        },
+        {
+          "content-length": "23736"
+        },
+        {
+          "cache-control": "public, max-age=31478360"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 20:50:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:35:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "REVz0k4Gud7bedzv9KSTG2i1KOporb0T14mWht95MIE="
+        },
+        {
+          "content-length": "12969"
+        },
+        {
+          "cache-control": "public, max-age=31394885"
+        },
+        {
+          "expires": "Fri, 01 Nov 2013 21:39:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:06:44 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "VKvuYL/9rqvjXh7mr8LjSJmcgQLZ/a+Ztqj2aUsPacc="
+        },
+        {
+          "content-length": "8457"
+        },
+        {
+          "cache-control": "public, max-age=31088728"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 08:36:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":26,\"r\":18,\"q\":0,\"a\":30}"
+        },
+        {
+          "x-fb-server": "10.164.86.49"
+        },
+        {
+          "x-fb-debug": "egJridVr0Ohgw3QbFe66p8hTV/ZDa+ldtrrj55f1Dwg="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":15,\"r\":74,\"q\":0,\"a\":21}"
+        },
+        {
+          "x-fb-server": "10.164.212.85"
+        },
+        {
+          "x-fb-debug": "7JVbUHGoJcLzIbHgkJPv0DSBycKYYPPorUc0i6OdRw8="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":33,\"r\":14,\"q\":0,\"a\":27}"
+        },
+        {
+          "x-fb-server": "10.164.203.85"
+        },
+        {
+          "x-fb-debug": "SHFiC3r5rPZSoyQ6AT4o7Lrz58o2i0cRMRoLoKKAVLc="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "10334"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}"
+        },
+        {
+          "x-fb-server": "10.164.121.55"
+        },
+        {
+          "x-fb-debug": "B8TQ25HLrpUM+2nuhej+798G7ib2rXsLxKDRmmd6364="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "79019"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:05 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "q1YlNQFhUrIi0HF88gF/s47itTMC0ALVS2i6Xo/eSFQ="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=17216856"
+        },
+        {
+          "expires": "Tue, 21 May 2013 19:18:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "OOKrpYeJ1K2euVWUg0h3X4OLDU+bPXAhHe2ZbKmaIIo="
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "cache-control": "public, max-age=17216855"
+        },
+        {
+          "expires": "Tue, 21 May 2013 19:18:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:42:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "BWYgCEbzeWyERD5oPP51t1mG+xnS0km1r6TZrds9BdY="
+        },
+        {
+          "content-length": "55530"
+        },
+        {
+          "cache-control": "public, max-age=31068989"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}"
+        },
+        {
+          "x-fb-server": "10.164.121.55"
+        },
+        {
+          "x-fb-debug": "6DDnMStngO3Ec4qHVJLnouT/OjWIKWOh3p7X19lwA2E="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "67"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "x-fb-debug": "DY+dO6Fs6HOjJLzXfO2vzcoACugopwtj+ZfSFe3+0Io="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 01:19:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "U3t5ojZAXSlz/rftvVXMdi+dQaAlCxv95u4nFdmaOpU="
+        },
+        {
+          "content-length": "6332"
+        },
+        {
+          "cache-control": "public, max-age=29865483"
+        },
+        {
+          "expires": "Tue, 15 Oct 2013 04:49:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:19 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "WkN9kzT0IbJnmPVAe/JpiO1KA3sDm5JiLNu+peaU22E="
+        },
+        {
+          "content-length": "1025"
+        },
+        {
+          "cache-control": "public, max-age=17216854"
+        },
+        {
+          "expires": "Tue, 21 May 2013 19:18:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "7905"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:38:51 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "flUDwRXAcKGlCZV+B6xp1kix2zMM2jCaLr8GXWfOS9o="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31191685"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 13:12:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "960"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 07 Jun 2012 20:17:10 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "s2bSrOgSOrnc1I2Y+hCmZNjO4JKRAsJvvEShk7xvQh0="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=25753518"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:36:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 13:05:49 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "dSqFMj3BQam7KrjoHsDUySNYx2e/ZA4jk+iLwQD5q+M="
+        },
+        {
+          "content-length": "1421"
+        },
+        {
+          "cache-control": "public, max-age=25753545"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:36:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "3977"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:41:38 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "if1LyEGCEK6E/tHFIYqTdcReGf2YlH/8CNcvt0MSb5c="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31162173"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 05:00:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:03 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "0MQqsPt7SaQdEz9msJEk0wieC0zyyvfgvjy4gscfRm4="
+        },
+        {
+          "content-length": "316"
+        },
+        {
+          "cache-control": "public, max-age=25628126"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6779"
+        },
+        {
+          "last-modified": "Wed, 09 May 2012 22:55:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7899"
+        },
+        {
+          "last-modified": "Mon, 14 May 2012 09:15:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8961"
+        },
+        {
+          "last-modified": "Fri, 10 Aug 2012 23:04:25 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7270"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 17:02:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "10284"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 13:43:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6932"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 16:53:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "19404"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 21:38:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":23,\"r\":24,\"q\":0,\"a\":31}"
+        },
+        {
+          "x-fb-server": "10.164.204.89"
+        },
+        {
+          "x-fb-debug": "mhzgPOTS+rD7XyjD1gp3zWldoiZpmeeyK0sWCXxCmL8="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":13,\"r\":137,\"q\":0,\"a\":23}"
+        },
+        {
+          "x-fb-server": "10.164.167.53"
+        },
+        {
+          "x-fb-debug": "uWC6Yw5Jjt8tp6GMW/0c7q4sQiyN+cfsFumyrajMSLE="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":20,\"r\":43,\"q\":0,\"a\":30}"
+        },
+        {
+          "x-fb-server": "10.165.52.67"
+        },
+        {
+          "x-fb-debug": "K6O9zzGnsjkFUcjVnvogKEp8WyYKDD5/1SRA3JOqTz8="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "10334"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}"
+        },
+        {
+          "x-fb-server": "10.164.10.79"
+        },
+        {
+          "x-fb-debug": "gU+KRCRWrUp+aETSVFA2+QqzJ57Mry5y8i9NZISRzV4="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "79019"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        },
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}"
+        },
+        {
+          "x-fb-server": "10.164.10.79"
+        },
+        {
+          "x-fb-debug": "2KYdrNd+vAjbaW2+l9lZ0c9qQnQQuLC0uV+aDWEfnEs="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "67"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "x-fb-debug": "ltZY31wZe0x9jjXZ+/GQMCIZ6L+UzLcVFaj4Ye8cEag="
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "32220"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 15:37:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "105703"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 15:38:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "36768"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 01:55:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "119574"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 09:41:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "659"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "yE8mx2kOMcI8Q4MtoKCXYAXv7xSMQBGufoB0y/qkYEs="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=16309260"
+        },
+        {
+          "expires": "Sat, 11 May 2013 07:12:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6966"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 16:26:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4501"
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 11:36:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "37432"
+        },
+        {
+          "last-modified": "Mon, 04 Jun 2012 08:35:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7198"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 16:45:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "13454"
+        },
+        {
+          "last-modified": "Thu, 31 May 2012 01:48:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "access-control-allow-origin": "http://www.facebook.com"
+        },
+        {
+          "access-control-allow-credentials": "true"
+        },
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "19537"
+        },
+        {
+          "last-modified": "Tue, 19 Jun 2012 08:51:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5842"
+        },
+        {
+          "last-modified": "Mon, 14 May 2012 22:03:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6973"
+        },
+        {
+          "last-modified": "Tue, 22 May 2012 23:26:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7263"
+        },
+        {
+          "last-modified": "Mon, 11 Jun 2012 21:11:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6222"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 02:10:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8005"
+        },
+        {
+          "last-modified": "Fri, 13 Jul 2012 02:50:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7949"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:25:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5850"
+        },
+        {
+          "last-modified": "Wed, 23 May 2012 13:04:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4860"
+        },
+        {
+          "last-modified": "Fri, 18 May 2012 06:59:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "36615"
+        },
+        {
+          "last-modified": "Fri, 08 Jun 2012 09:18:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "26180"
+        },
+        {
+          "last-modified": "Fri, 01 Jun 2012 12:58:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8551"
+        },
+        {
+          "last-modified": "Wed, 16 May 2012 00:19:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7021"
+        },
+        {
+          "last-modified": "Fri, 18 May 2012 08:58:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8126"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 10:31:00 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "21780"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 20:43:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "16109"
+        },
+        {
+          "last-modified": "Fri, 08 Jun 2012 21:45:00 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5248"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 17:19:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7600"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 00:02:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8148"
+        },
+        {
+          "last-modified": "Tue, 04 Sep 2012 05:25:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "23688"
+        },
+        {
+          "last-modified": "Tue, 05 Jun 2012 16:58:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "32579"
+        },
+        {
+          "last-modified": "Fri, 15 Jun 2012 23:21:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "36154"
+        },
+        {
+          "last-modified": "Tue, 15 May 2012 16:53:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8261"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 16:15:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "34603"
+        },
+        {
+          "last-modified": "Tue, 05 Jun 2012 19:33:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "19320"
+        },
+        {
+          "last-modified": "Fri, 20 Jul 2012 22:33:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:59:56 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "cEr4CpqyPlutZEM5egM7EW1V/FoNLas8puqhILOyn6g="
+        },
+        {
+          "content-length": "1589"
+        },
+        {
+          "cache-control": "public, max-age=31191410"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 13:08:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:34 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "SjbWzWIhc5uDeUgKzkah4oVawEfOfsqgn79tJvLiODA="
+        },
+        {
+          "content-length": "124"
+        },
+        {
+          "cache-control": "public, max-age=25632795"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 05:04:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "8BYYADIiLWZPRqrmghOTJnnu5b75InjLJYums29XQC4="
+        },
+        {
+          "content-length": "178"
+        },
+        {
+          "cache-control": "public, max-age=25638838"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 06:45:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 26 Oct 2012 21:42:07 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "rg/3x10ePyW5+Yv14okaeMgQpdIDitUpRdeQlHd62wU="
+        },
+        {
+          "content-length": "3403"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "public, max-age=31099667"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 11:39:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:11:34 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "+G0d7Y1/nAK76h5l1ygZcgFyqkHdYYjzu9bN8TThTW0="
+        },
+        {
+          "content-length": "3794"
+        },
+        {
+          "cache-control": "public, max-age=31090886"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 09:12:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Thu, 27 Sep 2012 22:19:28 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "Zx9+0hICgorbmj40+TVQqx/6DWk0JFijw5sOouOK4x8="
+        },
+        {
+          "content-length": "4316"
+        },
+        {
+          "cache-control": "public, max-age=31191442"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 13:08:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "y9gp03qLmGwdrjrggsFyxKUnduRuH6ZkhHy3J217wnA="
+        },
+        {
+          "content-length": "82"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "public, max-age=25628121"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:15 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "y31IzOtXz6QEqDb4Yh8nL9E7Jz3QdrtFTVTfJpFI67s="
+        },
+        {
+          "content-length": "281"
+        },
+        {
+          "cache-control": "public, max-age=25628127"
+        },
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:48 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "cdKo7nf6SbFgEUsu8p8ZpYkyd14IkSsYwu8pEpjIPW8="
+        },
+        {
+          "content-length": "18581"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "public, max-age=31068960"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:28:22 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "Mcoj0fymAm3BWRvLoE9uVgrJkXk8Wldn9hUKly6PE60="
+        },
+        {
+          "content-length": "686"
+        },
+        {
+          "cache-control": "public, max-age=31067324"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 02:40:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "70824"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:35:10 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "U6CnJQe7lFM5/wvYBRcEyvixo284qs3dxFI4vIJ3Sfo="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=31117935"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 16:43:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "6953"
+        },
+        {
+          "content-type": "application/x-shockwave-flash"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=260332"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 13:10:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "6953"
+        },
+        {
+          "content-type": "application/x-shockwave-flash"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=260331"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 13:10:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:21 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 17:45:29 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-fb-debug": "casrvtlqM38DGgUK+sC64wYFWqXchCM2wnMjgM8VC98="
+        },
+        {
+          "content-length": "15685"
+        },
+        {
+          "cache-control": "public, max-age=31299110"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 19:03:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cnection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "1591"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "last-modified": "Thu, 20 Sep 2012 01:12:35 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "E9XqLqcAPtaMWK+vlxTTyhNPMewUq9nSCKax+m9KMwk="
+        },
+        {
+          "x-cnection": "close"
+        },
+        {
+          "cache-control": "public, max-age=28776235"
+        },
+        {
+          "expires": "Wed, 02 Oct 2013 14:15:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:51:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_27.json b/jetty-http2/http2-hpack/src/test/resources/data/story_27.json
new file mode 100644
index 0000000..0a0077d
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_27.json
@@ -0,0 +1,9890 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:12 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:12 GMT; path=/; domain=.flickr.com"
+        },
+        {
+          "location": "http://www.flickr.com/"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "x-served-by": "www199.flickr.mud.yahoo.com"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "20"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:13 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:05:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www199.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "no-store, no-cache, must-revalidate, max-age=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r16.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:15 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 09:50:22 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www25.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "age": "273053"
+        },
+        {
+          "via": "HTTP/1.1 r42.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 04:23:38 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "21830"
+        },
+        {
+          "x-served-by": "www145.flickr.mud.yahoo.com"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "age": "206257"
+        },
+        {
+          "via": "HTTP/1.1 r46.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r9.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:15 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www187.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r44.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:15 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:16 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 355 dc10_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:17 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "327"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:28:23 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://p3p.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV\""
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:00:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding,User-Agent"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=3600"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        },
+        {
+          "age": "773"
+        },
+        {
+          "content-length": "111260"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "ATS/3.2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:16 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:19 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www18.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r48.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "fldetectedlang=en-us; expires=Wed, 02-Jan-2013 13:41:19 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5002"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:30:08 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "45842"
+        },
+        {
+          "x-cache": "HIT from photocache510.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache510.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache510.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2849"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:51:39 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "88063"
+        },
+        {
+          "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3533"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Thu, 27 Oct 2022 22:31:31 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "609449"
+        },
+        {
+          "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8165"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 03 Jul 2022 07:34:11 UTC"
+        },
+        {
+          "last-modified": "Tue, 10 Nov 2009 20:15:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "1332"
+        },
+        {
+          "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "16040"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:51:39 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:32 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "104768"
+        },
+        {
+          "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "16818"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:51:39 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "104768"
+        },
+        {
+          "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "258838"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:14:20 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "3930"
+        },
+        {
+          "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "15513"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:47:34 UTC"
+        },
+        {
+          "last-modified": "Mon, 06 Jun 2011 11:22:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "9645"
+        },
+        {
+          "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:20 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 380 dc11_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:21 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:21 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7878"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Wed, 20 Jul 2022 12:23:18 UTC"
+        },
+        {
+          "last-modified": "Mon, 23 Jun 2008 19:15:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "41746"
+        },
+        {
+          "x-cache": "HIT from photocache114.flickr.mud.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache114.flickr.mud.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache114.flickr.mud.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:21 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:21 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3339"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sat, 01 Oct 2022 14:49:54 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Oct 2012 03:50:32 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "79702"
+        },
+        {
+          "x-cache": "HIT from photocache902.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache902.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache902.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:21 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www145.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/javascript; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r02.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "fldetectedlang=en-us; expires=Wed, 02-Jan-2013 13:41:19 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3403"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:01:02 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "146624"
+        },
+        {
+          "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3018"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:06 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "498650"
+        },
+        {
+          "x-cache": "HIT from photocache509.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache509.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache509.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3493"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:01:02 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "184716"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "19066"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:06 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "498650"
+        },
+        {
+          "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "14587"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:06 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:44:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "498650"
+        },
+        {
+          "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "16541"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:51:39 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:55 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "64145"
+        },
+        {
+          "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "17669"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:06 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "498070"
+        },
+        {
+          "x-cache": "HIT from photocache536.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache536.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache536.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "17009"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:06 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "498070"
+        },
+        {
+          "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "110090"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:50:49 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "104763"
+        },
+        {
+          "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:22 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "121145"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:14:22 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "104763"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:23 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www105.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r08.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:23 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:24 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 328 dc26_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:25 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:24 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5372"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 24 Jul 2022 05:03:05 UTC"
+        },
+        {
+          "last-modified": "Sat, 10 Jul 2010 18:58:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "113797"
+        },
+        {
+          "x-cache": "HIT from photocache417.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache417.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache417.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:24 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:25 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "101072"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:13:50 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "399124"
+        },
+        {
+          "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:25 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www135.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "via": "HTTP/1.1 r34.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:25 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:26 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 358 dc28_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:26 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:26 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "131822"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:13:19 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "399125"
+        },
+        {
+          "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www198.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "via": "HTTP/1.1 r34.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:27 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:28 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 366 dc36_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:29 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:29 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:29 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "137767"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 09:13:04 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "959688"
+        },
+        {
+          "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Fri, 06 Jul 2012 19:15:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www24.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "35102"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:30 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "9755"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 23:11:18 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "783768"
+        },
+        {
+          "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "8018"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 23:11:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "783767"
+        },
+        {
+          "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5509"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 23:11:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "849721"
+        },
+        {
+          "x-cache": "HIT from photocache517.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache517.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache517.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "24244"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 23:11:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "832233"
+        },
+        {
+          "x-cache": "HIT from photocache503.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache503.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache503.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "15699"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:49:46 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "184724"
+        },
+        {
+          "x-cache": "HIT from photocache535.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache535.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache535.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26051"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:41 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 19:06:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "783767"
+        },
+        {
+          "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13263"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:08 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "216108"
+        },
+        {
+          "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "19324"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 03 Jul 2022 22:23:27 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301732"
+        },
+        {
+          "x-cache": "HIT from photocache539.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache539.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache539.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "21573"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:42 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "14644"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "20730"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:42 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:44:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301890"
+        },
+        {
+          "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "32916"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:08 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "251785"
+        },
+        {
+          "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26574"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:27:42 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:55 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "832232"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "27759"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:23 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301883"
+        },
+        {
+          "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "11409"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:10 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "832232"
+        },
+        {
+          "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26453"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 24 Jul 2022 04:56:22 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "3058"
+        },
+        {
+          "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "23128"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:23 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301877"
+        },
+        {
+          "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "28275"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:23 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301881"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:30 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "26267"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:23 UTC"
+        },
+        {
+          "last-modified": "Wed, 15 Sep 2010 19:43:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301876"
+        },
+        {
+          "x-cache": "HIT from photocache514.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache514.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache514.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:31 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 369 dc23_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:32 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:31 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:31 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:31 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Wed, 31 Oct 2012 09:31:12 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www96.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "max-age=1209600"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/vnd.microsoft.icon"
+        },
+        {
+          "age": "274220"
+        },
+        {
+          "via": "HTTP/1.1 r15.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cHs f ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:30 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:33 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www1.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r12.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:33 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "19144"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301872"
+        },
+        {
+          "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "24110"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "840419"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "32406"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 18:43:07 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "166451"
+        },
+        {
+          "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "20059"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "382867"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "23332"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:41:55 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "68360"
+        },
+        {
+          "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "18543"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:24:48 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "458533"
+        },
+        {
+          "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "15399"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 30 Oct 2022 01:48:16 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "424858"
+        },
+        {
+          "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "29793"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Tue, 16 Aug 2022 22:34:17 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 22:00:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "840419"
+        },
+        {
+          "x-cache": "HIT from photocache401.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache401.flickr.ac4.yahoo.com:81"
+        },
+        {
+          "via": "1.1 photocache401.flickr.ac4.yahoo.com:81 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13571"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:16:36 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "783188"
+        },
+        {
+          "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "18149"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 12 Jun 2022 23:12:34 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "953364"
+        },
+        {
+          "x-cache": "HIT from photocache414.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache414.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache414.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "15403"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "388250"
+        },
+        {
+          "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "14796"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "320180"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "18710"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "840419"
+        },
+        {
+          "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "32555"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 19 Jun 2022 15:01:08 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 22:00:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "58741"
+        },
+        {
+          "x-cache": "HIT from photocache412.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache412.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache412.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13726"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:10 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "840419"
+        },
+        {
+          "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "27660"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 22:06:36 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "320180"
+        },
+        {
+          "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "19545"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:38:09 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "840419"
+        },
+        {
+          "x-cache": "HIT from photocache517.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache517.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache517.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "30518"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 16:28:03 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "49685"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:34 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 310 dc33_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:35 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:35 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:38 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 342 dc32_ne1"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:39 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "site tracked"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:39 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www31.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:39 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:40 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:41 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 352 dc19_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:42 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "imp=a$le#1351950101610_669834368_ap2101_int|; Domain=.teracent.net; Expires=Thu, 02-May-2013 13:41:41 GMT; Path=/tase"
+        },
+        {
+          "p3p": "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "expires": "Sat, 6 May 1995 12:00:00 GMT"
+        },
+        {
+          "cache-control": "post-check=0, pre-check=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:41 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:41 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www56.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:44 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2830"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:50:16 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "4009"
+        },
+        {
+          "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4884"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:44:25 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "159147"
+        },
+        {
+          "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3513"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:49:35 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:18 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "4010"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6899"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:49:08 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328198"
+        },
+        {
+          "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4695"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Thu, 03 Nov 2022 23:49:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "MISS from photocache514.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "MISS from photocache514.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache514.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2596"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:55:46 UTC"
+        },
+        {
+          "last-modified": "Mon, 04 Oct 2010 23:11:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431512"
+        },
+        {
+          "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3516"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 17:53:36 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "302049"
+        },
+        {
+          "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4922"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "36944"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3158"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:46:15 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328157"
+        },
+        {
+          "x-cache": "HIT from photocache512.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache512.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache512.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4541"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Thu, 16 Sep 2010 17:19:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "302053"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4145"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 07:51:21 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:40:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328231"
+        },
+        {
+          "x-cache": "HIT from photocache508.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache508.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache508.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3419"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:06:37 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "650868"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5035"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:41:31 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "3999"
+        },
+        {
+          "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:44 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 305 dc9_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:46 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "45"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5313"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Thu, 01 Sep 2022 04:55:06 UTC"
+        },
+        {
+          "last-modified": "Fri, 31 Aug 2012 18:28:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "959613"
+        },
+        {
+          "x-cache": "HIT from photocache906.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache906.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache906.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4675"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Wed, 07 Sep 2022 05:56:52 UTC"
+        },
+        {
+          "last-modified": "Thu, 06 Sep 2012 18:42:55 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "338945"
+        },
+        {
+          "x-cache": "HIT from photocache907.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache907.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache907.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7282"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 28 Aug 2022 09:31:01 UTC"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 22:28:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "73654"
+        },
+        {
+          "x-cache": "HIT from photocache924.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache924.flickr.bf1.yahoo.com:85"
+        },
+        {
+          "via": "1.1 photocache924.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4242"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Thu, 01 Sep 2022 04:55:06 UTC"
+        },
+        {
+          "last-modified": "Fri, 31 Aug 2012 18:28:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "959613"
+        },
+        {
+          "x-cache": "HIT from photocache926.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache926.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache926.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4561"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 17 Jul 2022 03:19:16 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "4005"
+        },
+        {
+          "x-cache": "HIT from photocache203.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache203.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache203.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6350"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 17 Jul 2022 04:55:35 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 16:18:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431728"
+        },
+        {
+          "x-cache": "HIT from photocache204.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache204.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache204.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3341"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 17 Jul 2022 18:09:37 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328215"
+        },
+        {
+          "x-cache": "HIT from photocache205.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache205.flickr.bf1.yahoo.com:85"
+        },
+        {
+          "via": "1.1 photocache205.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7005"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 18 Jul 2022 01:41:12 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "4064"
+        },
+        {
+          "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:85"
+        },
+        {
+          "via": "1.1 photocache202.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4068"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 18 Jul 2022 03:45:04 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "438025"
+        },
+        {
+          "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache202.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7960"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 18 Jul 2022 03:44:32 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:41:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328207"
+        },
+        {
+          "x-cache": "HIT from photocache205.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache205.flickr.bf1.yahoo.com:85"
+        },
+        {
+          "via": "1.1 photocache205.flickr.bf1.yahoo.com:85 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:45 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:46 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4395"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 18 Jul 2022 03:45:05 UTC"
+        },
+        {
+          "last-modified": "Mon, 01 Nov 2010 05:40:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2328241"
+        },
+        {
+          "x-cache": "HIT from photocache202.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache202.flickr.bf1.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache202.flickr.bf1.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:48 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www30.flickr.bf1.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "via": "HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:48 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3706"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "608527"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4610"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 16:47:58 UTC"
+        },
+        {
+          "last-modified": "Wed, 04 Aug 2010 23:21:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "598783"
+        },
+        {
+          "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2551"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "801137"
+        },
+        {
+          "x-cache": "HIT from photocache529.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache529.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache529.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2822"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:43:25 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache504.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache504.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache504.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "151390"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4463"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:56:37 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "252496"
+        },
+        {
+          "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1441"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:25 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "496025"
+        },
+        {
+          "x-cache": "HIT from photocache501.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache501.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache501.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3780"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sat, 22 Oct 2022 00:35:44 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "988214"
+        },
+        {
+          "x-cache": "HIT from photocache312.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache312.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache312.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5215"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 24 Oct 2022 02:15:29 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431732"
+        },
+        {
+          "x-cache": "HIT from photocache324.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache324.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache324.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2610"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "872080"
+        },
+        {
+          "x-cache": "HIT from photocache520.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache520.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache520.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4241"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 08:00:12 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "2356"
+        },
+        {
+          "x-cache": "HIT from photocache513.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache513.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache513.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4461"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:10:07 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301869"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4292"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 13:51:59 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "258540"
+        },
+        {
+          "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3353"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache518.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache518.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache518.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "496025"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4008"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:42:08 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "435217"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4081"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:43:52 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "435217"
+        },
+        {
+          "x-cache": "HIT from photocache521.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache521.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache521.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3996"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 15:30:11 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:46:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "872288"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2178"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:42:08 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431529"
+        },
+        {
+          "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3292"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:39:41 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431732"
+        },
+        {
+          "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3415"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89675"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3963"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 15:19:56 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "89675"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3036"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Wed, 04 Aug 2010 23:21:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "245531"
+        },
+        {
+          "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1843"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431517"
+        },
+        {
+          "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6971"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301877"
+        },
+        {
+          "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3968"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431731"
+        },
+        {
+          "x-cache": "HIT from photocache527.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache527.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache527.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:49 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:50 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 326 dc12_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:51 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:50 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:50 GMT"
+        },
+        {
+          "server": "YTS/1.20.13"
+        },
+        {
+          "x-rightmedia-hostname": "raptor0740.rm.bf1.yahoo.com"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "location": "http://ad.yieldmanager.com/pixel?id=365081&t=2"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, max-age=0"
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:41:50 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:50 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4726"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 17:54:01 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:36 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "211089"
+        },
+        {
+          "x-cache": "HIT from photocache519.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache519.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache519.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4433"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 04 Jul 2022 00:08:57 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431736"
+        },
+        {
+          "x-cache": "HIT from photocache539.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache539.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache539.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2677"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431735"
+        },
+        {
+          "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3081"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "164867"
+        },
+        {
+          "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3457"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "435221"
+        },
+        {
+          "x-cache": "HIT from photocache526.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache526.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache526.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4433"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "424621"
+        },
+        {
+          "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "6486"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:46:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431736"
+        },
+        {
+          "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4899"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Wed, 04 Aug 2010 23:21:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "598778"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3981"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sat, 15 Oct 2022 23:23:06 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:46:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431687"
+        },
+        {
+          "x-cache": "HIT from photocache311.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache311.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache311.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7338"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sun, 12 Jun 2022 22:06:49 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 22:00:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "608533"
+        },
+        {
+          "x-cache": "HIT from photocache415.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache415.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache415.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5640"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:48:36 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "988205"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4609"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "871819"
+        },
+        {
+          "x-cache": "HIT from photocache530.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache530.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache530.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3776"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:39:41 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431533"
+        },
+        {
+          "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4551"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:35:21 UTC"
+        },
+        {
+          "last-modified": "Tue, 17 Aug 2010 18:40:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "415587"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4452"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:41:31 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "36952"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2023"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:45:55 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache533.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache533.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache533.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "682487"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:51 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www144.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "via": "HTTP/1.1 r29.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:51 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4675"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:44:19 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89679"
+        },
+        {
+          "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3139"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:09:56 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:00 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89670"
+        },
+        {
+          "x-cache": "HIT from photocache531.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache531.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache531.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3167"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431533"
+        },
+        {
+          "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4227"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:25 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89679"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2768"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 11:43:02 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "206489"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4375"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "988235"
+        },
+        {
+          "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3506"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 18:52:47 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:36 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431534"
+        },
+        {
+          "x-cache": "HIT from photocache507.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache507.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache507.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3522"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 21:59:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "988233"
+        },
+        {
+          "x-cache": "HIT from photocache515.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache515.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache515.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:53 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 307 dc1_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:55 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "45"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "server": "YTS/1.20.13"
+        },
+        {
+          "x-rightmedia-hostname": "raptor0291.rm.bf1.yahoo.com"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, max-age=0"
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "server": "YTS/1.20.13"
+        },
+        {
+          "x-rightmedia-hostname": "raptor0921.rm.bf1.yahoo.com"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, max-age=0"
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:54 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "location": "http://ad.yieldmanager.com/imp?Z=1x1&s=768714&T=3&_salt=2374354217&B=12&m=2&u=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Fnasacommons%2Ftags%2Fnationalaeronauticsandspaceadministration%2Fpage3%2F&r=0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:55 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "last-modified": "Tue, 06 Mar 2012 23:48:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "x-served-by": "www13.flickr.mud.yahoo.com"
+        },
+        {
+          "x-flickr-static": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "via": "HTTP/1.1 r18.ycpi.mud.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ]), HTTP/1.1 r02.ycpi.mia.yahoo.net (YahooTrafficServer/1.20.20 [cMsSf ])"
+        },
+        {
+          "server": "YTS/1.20.20"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-length": "6640"
+        },
+        {
+          "expires": "Mon, 28 Jul 2014 23:30:00 GMT"
+        },
+        {
+          "set-cookie": "localization=en-us%3Bus%3Bus; expires=Sat, 01-Nov-2014 13:41:55 GMT; path=/; domain=.flickr.com"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5525"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:39:41 UTC"
+        },
+        {
+          "last-modified": "Wed, 04 Aug 2010 23:21:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "435224"
+        },
+        {
+          "x-cache": "HIT from photocache503.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache503.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache503.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4651"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:21:30 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "166264"
+        },
+        {
+          "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4344"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:43:52 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301880"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4372"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431536"
+        },
+        {
+          "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4446"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431689"
+        },
+        {
+          "x-cache": "HIT from photocache534.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache534.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache534.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4431"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:46:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "431690"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "13813"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Sat, 03 Sep 2022 23:41:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 17 May 2010 22:00:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "608533"
+        },
+        {
+          "x-cache": "HIT from photocache408.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache408.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache408.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2010"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:43:52 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431537"
+        },
+        {
+          "x-cache": "HIT from photocache535.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache535.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache535.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4596"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:24 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "301900"
+        },
+        {
+          "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4383"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:25 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache540.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache540.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache540.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "89682"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3501"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 08:02:11 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89673"
+        },
+        {
+          "x-cache": "HIT from photocache506.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache506.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache506.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3829"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:11 UTC"
+        },
+        {
+          "last-modified": "Wed, 04 Aug 2010 23:21:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "871646"
+        },
+        {
+          "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3781"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:46:07 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "435223"
+        },
+        {
+          "x-cache": "HIT from photocache502.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache502.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache502.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4186"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 20:41:31 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "363909"
+        },
+        {
+          "x-cache": "HIT from photocache524.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache524.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache524.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3814"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:43:52 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache537.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache537.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache537.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "89682"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2478"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:25 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431536"
+        },
+        {
+          "x-cache": "HIT from photocache511.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache511.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache511.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "7387"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Wed, 31 Mar 2010 17:47:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431739"
+        },
+        {
+          "x-cache": "HIT from photocache523.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache523.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache523.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5870"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:04:10 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "337938"
+        },
+        {
+          "x-cache": "HIT from photocache525.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache525.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache525.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "5202"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:40:12 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:57:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431738"
+        },
+        {
+          "x-cache": "HIT from photocache505.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache505.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache505.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2820"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "431536"
+        },
+        {
+          "x-cache": "HIT from photocache538.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache538.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache538.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3044"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:43:52 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:07:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "x-cache": "HIT from photocache516.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache516.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache516.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        },
+        {
+          "age": "2363"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "4834"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 12:34:28 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:59:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "89682"
+        },
+        {
+          "x-cache": "HIT from photocache522.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache522.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache522.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3365"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:56:07 UTC"
+        },
+        {
+          "last-modified": "Tue, 03 Aug 2010 22:58:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "252421"
+        },
+        {
+          "x-cache": "HIT from photocache528.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache528.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache528.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "3978"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "max-age=315360000,public"
+        },
+        {
+          "expires": "Mon, 30 May 2022 10:39:41 UTC"
+        },
+        {
+          "last-modified": "Mon, 30 Aug 2010 06:49:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "age": "872078"
+        },
+        {
+          "x-cache": "HIT from photocache532.flickr.ac4.yahoo.com"
+        },
+        {
+          "x-cache-lookup": "HIT from photocache532.flickr.ac4.yahoo.com:83"
+        },
+        {
+          "via": "1.1 photocache532.flickr.ac4.yahoo.com:83 (squid/2.7.STABLE9)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:56 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "private, no-store, max-age=0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "set-cookie": "itsessionid10001561398679=aUqazlyMaa|fses10001561398679=; path=/; domain=.analytics.yahoo.com"
+        },
+        {
+          "ts": "0 372 dc33_ne1"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:58 GMT"
+        },
+        {
+          "cache-control": "no-cache, private, must-revalidate"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "tracking-status": "fpc site tracked"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "server": "YTS/1.20.13"
+        },
+        {
+          "x-rightmedia-hostname": "raptor0663.rm.bf1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "location": "http://ad.yieldmanager.com/pixel?id=372009&t=2"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, max-age=0"
+        },
+        {
+          "vary": "*"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:57 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:41:58 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://info.yahoo.com/w3c/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\""
+        },
+        {
+          "cache-control": "no-cache, no-store, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_28.json b/jetty-http2/http2-hpack/src/test/resources/data/story_28.json
new file mode 100644
index 0000000..26c5a59
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_28.json
@@ -0,0 +1,5293 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "location": "http://www.linkedin.com/"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:39 GMT"
+        },
+        {
+          "server": "lighttpd"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "E2zvmRmjhYEFJpx7GePGrg=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:39 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 22:43:31 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4224"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31224822"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 22:47:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1757"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=23972673"
+        },
+        {
+          "expires": "Thu, 08 Aug 2013 00:18:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 17:17:34 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1104"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31119071"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 17:24:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 22:43:30 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4725"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31225090"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 22:51:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 22:43:29 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "18531"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31225288"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 22:55:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 22:43:30 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "81464"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31224801"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 22:47:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "L1e=495eba97; path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "gLtcwO0VwxJQ3EsqHysAAA=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:43 GMT"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 19:08:05 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "361"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31188041"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 12:34:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 19:11:14 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "CCdnnfDTwhJwlNCV9ioAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=31463444"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 17:04:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:44 GMT"
+        },
+        {
+          "content-length": "3489"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Mon, 13 Aug 2012 19:03:38 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1062"
+        },
+        {
+          "cache-control": "max-age=24472323"
+        },
+        {
+          "expires": "Tue, 13 Aug 2013 19:05:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:44 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "14888"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 15:51:19 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 06:13:29 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 18:13:29 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "25215"
+        },
+        {
+          "cache-control": "max-age=43200, public"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168216"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "age": "168216"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03-Nov-2012 13:13:45 GMT"
+        },
+        {
+          "etag": "M0-0eb75f26"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, no-transform, must-revalidate, max-age=604800"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "content-length": "2298"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "set-cookie": "mc=50951889-343da-16f7e-ae952; expires=Mon, 05-May-2014 13:13:45 GMT; path=/; domain=.quantserve.com"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAo PSDo OUR SAMa IND COM NAV\""
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Sat, 17 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "content-length": "1140"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-transform, max-age=1209600"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:45 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "jguBxDxCP8A3strRU6z0Sw=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:49 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "8e0b81c43c423fc037b2dad153acf44b"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "lighttpd"
+        },
+        {
+          "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "jguBxDxCP8A3strRU6z0Sw=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:49 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "8e0b81c43c423fc037b2dad153acf44b"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT"
+        },
+        {
+          "content-length": "1150"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Thu, 16 Aug 2012 01:24:42 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1044"
+        },
+        {
+          "cache-control": "max-age=24721219"
+        },
+        {
+          "expires": "Fri, 16 Aug 2013 16:14:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Wed, 17 Oct 2012 23:09:52 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9168"
+        },
+        {
+          "cache-control": "max-age=30168335"
+        },
+        {
+          "expires": "Fri, 18 Oct 2013 17:19:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:51 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:51 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168222"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:51 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:10:36 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "eAzMxNUMwxJwGtyV9ioAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=31525993"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 10:27:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:51 GMT"
+        },
+        {
+          "content-length": "223"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Sat, 01 Sep 2012 00:58:09 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "CCdnnfDTwhJwlNCV9ioAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=26048872"
+        },
+        {
+          "expires": "Sun, 01 Sep 2013 01:01:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:51 GMT"
+        },
+        {
+          "content-length": "11160"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "AZRbIR9V68fBQlYZzQoS1w=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:54 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "01945b211f55ebc7c1425619cd0a12d7"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT"
+        },
+        {
+          "content-length": "4714"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:54 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:54 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168226"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:54 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "lang=\"v=2&lang=en-us\"; Version=1; Domain=linkedin.com; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "wL1PItpHScLBRl0PVkiLLQ=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:59 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "c0bd4f22da4749c2c1465d0f56488b2d"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Wed, 22 Jun 2011 20:28:00 GMT"
+        },
+        {
+          "content-length": "4714"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:59 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:59 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168230"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:13:59 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "vZHDyRjuiQCkhZBzyxGqrg=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:01 GMT"
+        },
+        {
+          "age": "3"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "6176"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 07:53:23 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4012"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=28752189"
+        },
+        {
+          "expires": "Wed, 02 Oct 2013 07:57:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 17:17:34 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "628"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=3381907"
+        },
+        {
+          "expires": "Wed, 12 Dec 2012 16:39:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-length": "1044"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31490642"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 00:38:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:36:32 GMT"
+        },
+        {
+          "x-li-uuid": "KMg5e7HswhIQwgDTIysAAA=="
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 00:20:08 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17928"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31230754"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 00:26:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 10:10:40 GMT"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11863"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=30574946"
+        },
+        {
+          "expires": "Wed, 23 Oct 2013 10:16:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 17:10:42 GMT"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "77011"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=30513689"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 17:15:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "352"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:05 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "vZHDyRjuiQCkhZBzyxGqrg=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:04 GMT"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "6176"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 09:02:37 GMT"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 09:02:37 GMT"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-transfer-encoding": "binary"
+        },
+        {
+          "content-length": "1186"
+        },
+        {
+          "cache-control": "max-age=503312, public, no-transform, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:05 GMT"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:06 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:06 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168237"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "age": "168237"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:06 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 09:55:42 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:08 GMT"
+        },
+        {
+          "x-fs-uuid": "4062fd4fc89b6346ee2b61950a9840a5"
+        },
+        {
+          "x-li-uuid": "QGL9T8ibY0buK2GVCphApQ=="
+        },
+        {
+          "age": "1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "rDlCGMNjprrsLUOMpHhJIw=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:09 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "352"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:09 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 22 Aug 2012 09:55:42 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:09 GMT"
+        },
+        {
+          "x-fs-uuid": "4062fd4fc89b6346ee2b61950a9840a5"
+        },
+        {
+          "x-li-uuid": "CDPTy/MVwxKQFKu9mysAAA=="
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 17:09:44 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "YP+9O9z6wRIwf5dQLCsAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "64"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=28813847"
+        },
+        {
+          "expires": "Thu, 03 Oct 2013 01:04:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 19:11:14 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-li-uuid": "iA7sd9nTwhIQefs/LCsAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=31463319"
+        },
+        {
+          "expires": "Sat, 02 Nov 2013 17:02:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:09 GMT"
+        },
+        {
+          "content-length": "603"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1156"
+        },
+        {
+          "last-modified": "Fri, 18 Apr 2008 18:03:54 GMT"
+        },
+        {
+          "etag": "1208541834000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=5196477"
+        },
+        {
+          "expires": "Wed, 02 Jan 2013 16:42:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3476"
+        },
+        {
+          "last-modified": "Thu, 01 Sep 2011 13:46:08 GMT"
+        },
+        {
+          "etag": "1314884768000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=29243668"
+        },
+        {
+          "expires": "Tue, 08 Oct 2013 00:28:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1465"
+        },
+        {
+          "last-modified": "Wed, 15 Dec 2010 19:56:09 GMT"
+        },
+        {
+          "etag": "1292442969000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=5723024"
+        },
+        {
+          "expires": "Tue, 08 Jan 2013 18:57:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1705"
+        },
+        {
+          "last-modified": "Wed, 13 May 2009 06:47:06 GMT"
+        },
+        {
+          "etag": "1242197226000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=28717727"
+        },
+        {
+          "expires": "Tue, 01 Oct 2013 22:22:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1748"
+        },
+        {
+          "last-modified": "Mon, 13 Feb 2012 04:16:54 GMT"
+        },
+        {
+          "etag": "1329106614000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=29613032"
+        },
+        {
+          "expires": "Sat, 12 Oct 2013 07:04:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2115"
+        },
+        {
+          "last-modified": "Mon, 06 Jun 2011 11:28:28 GMT"
+        },
+        {
+          "etag": "1307359708000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=29255048"
+        },
+        {
+          "expires": "Tue, 08 Oct 2013 03:38:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2065"
+        },
+        {
+          "last-modified": "Fri, 15 Aug 2008 06:35:34 GMT"
+        },
+        {
+          "etag": "1218782134000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "cache-control": "max-age=23989474"
+        },
+        {
+          "expires": "Thu, 08 Aug 2013 04:58:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-cdn": "AKAM"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1777"
+        },
+        {
+          "last-modified": "Sun, 06 Apr 2008 16:44:40 GMT"
+        },
+        {
+          "etag": "1207500280000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=24015458"
+        },
+        {
+          "expires": "Thu, 08 Aug 2013 12:11:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2536"
+        },
+        {
+          "last-modified": "Sun, 17 Apr 2011 11:26:00 GMT"
+        },
+        {
+          "etag": "1303039560000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=30996570"
+        },
+        {
+          "expires": "Mon, 28 Oct 2013 07:23:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "1445"
+        },
+        {
+          "last-modified": "Sun, 14 Dec 2008 19:47:28 GMT"
+        },
+        {
+          "etag": "1229284048000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31023826"
+        },
+        {
+          "expires": "Mon, 28 Oct 2013 14:57:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "11785"
+        },
+        {
+          "last-modified": "Tue, 21 Feb 2012 04:44:27 GMT"
+        },
+        {
+          "etag": "1329799467000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=29267475"
+        },
+        {
+          "expires": "Tue, 08 Oct 2013 07:05:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:11 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:11 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168242"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "age": "168242"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:11 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "1013"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:44:36 GMT"
+        },
+        {
+          "etag": "1351921476485"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31508935"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 05:43:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:11 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-li-uuid": "uBgHimv9whIwouPuKysAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 09 Aug 2012 02:40:28 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:12 GMT"
+        },
+        {
+          "x-fs-uuid": "b73d9dcff4c8d40067468ef689e05a93"
+        },
+        {
+          "x-li-uuid": "tz2dz/TI1ABnRo72ieBakw=="
+        },
+        {
+          "age": "1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "6507"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "+8Oyp3i1cl6p243WV3LM6g=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:13 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "537"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:13 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "2469"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:13 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "last-modified": "Tue, 08 May 2012 20:09:07 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "321"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "81845"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Tue, 21 Feb 2012 01:03:49 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:03:29 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:03:29 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "24156"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "61845"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:10:35 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=31525781"
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 10:23:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:13 GMT"
+        },
+        {
+          "content-length": "94"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"5f7cc9080cad02333445367dae64546d:1351006466\""
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 15:34:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=3600"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "content-length": "1028"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"eb63c14544dcd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "2955"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 16:25:49 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 16:25:49 GMT"
+        },
+        {
+          "etag": "46977404F0473696BBDC518B1845C60E809A3249"
+        },
+        {
+          "cache-control": "max-age=356494,public,no-transform,must-revalidate"
+        },
+        {
+          "x-ocsp-reponder-id": "t8edcaocsp6"
+        },
+        {
+          "content-length": "471"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"65786c291a4603aa5150a1884452838d:1271351254\""
+        },
+        {
+          "last-modified": "Thu, 15 Apr 2010 17:07:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=2144448000"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"4cdd47b7bd15f75838435f1207ac1414:1351006993\""
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 15:43:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=315360000"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "content-length": "12232"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "set-cookie": "cckz=1mcwy3r; Domain=media6degrees.com; Expires=Thu, 02-May-2013 13:14:15 GMT; Path=/"
+        },
+        {
+          "location": "http://action.media6degrees.com/orbserv/nsjs?ncv=33&ns=299&pcv=39&nc=1&pixId=13086&cckz=true"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:14 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:15 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 23:10:45 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:15 GMT"
+        },
+        {
+          "x-fs-uuid": "1034b0b6c77d1f91819a2d929764b582"
+        },
+        {
+          "x-li-uuid": "EDSwtsd9H5GBmi2Sl2S1gg=="
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "6507"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "iPSByYTV24172TMFAcPcSg=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:15 GMT"
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "539"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "set-cookie": "cckz=1mcwy3s; Domain=media6degrees.com; Expires=Thu, 02-May-2013 13:14:16 GMT; Path=/"
+        },
+        {
+          "location": "http://action.media6degrees.com/orbserv/nsjs?ncv=33&ns=299&pcv=39&nc=1&pixId=13086&cckz=true"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "set-cookie": "JSESSIONID=CE33DFE7D94779C13B04C4D9B43D7792; Path=/orbserv; HttpOnly"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-length": "5"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:15 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "841"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "u=8|0BAgYJ9UoGCfVKAAAAAAAAQEAAQIhdawAARg9fRc3AAAAAAT9PvgAAAAAAu9ZfgAAAAAO_VtUCBMBAAuBLQA; Version=1; Domain=.agkn.com; Max-Age=63072000; Expires=Mon, 03-Nov-2014 13:14:16 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "image/gif;charset=ISO-8859-1"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:15 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 23:10:45 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "x-fs-uuid": "1034b0b6c77d1f91819a2d929764b582"
+        },
+        {
+          "x-li-uuid": "EDSwtsd9H5GBmi2Sl2S1gg=="
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "6507"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "2036"
+        },
+        {
+          "last-modified": "Thu, 29 Nov 2007 19:09:10 GMT"
+        },
+        {
+          "etag": "1196363350000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31005797"
+        },
+        {
+          "expires": "Mon, 28 Oct 2013 09:57:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-li-uuid": "uBgHimv9whIwouPuKysAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "access-control-allow-origin": "http://www.linkedin.com"
+        },
+        {
+          "last-modified": "Sat, 15 Sep 2012 06:22:35 GMT"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=27345738"
+        },
+        {
+          "expires": "Mon, 16 Sep 2013 01:16:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "content-length": "146"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "last-modified": "Tue, 03 Jul 2012 21:15:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 03:30:07 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:30:07 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "19787"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "35049"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"eb63c14544dcd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "2955"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"84332e7556647543d5f87647f37a8a6d:1346087966\""
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 17:19:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=600"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "content-length": "741"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168247"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "age": "168247"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"f13746374fa151b24abd8bf99a396878:1347294343\""
+        },
+        {
+          "last-modified": "Mon, 10 Sep 2012 16:25:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=2144448000"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "content-length": "1028"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"4d5ead3cfaa1fd96263197170ccaed07:1347294382\""
+        },
+        {
+          "last-modified": "Mon, 10 Sep 2012 16:26:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1507"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "max-age=2144448000"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:16 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sun, 05 Aug 2012 15:35:43 GMT"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:18 GMT"
+        },
+        {
+          "x-fs-uuid": "e4dcbadff47540485aebb5d079a66252"
+        },
+        {
+          "x-li-uuid": "5Ny63/R1QEha67XQeaZiUg=="
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "6507"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "sl=\"delete me\"; Version=1; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-li-uuid": "qwi+h66wCYWzSNcKexV4yw=="
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:18 GMT"
+        },
+        {
+          "age": "1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "x-fs-uuid": "bd91c3c918ee8900a4859073cb11aaae"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1672258277\""
+        },
+        {
+          "last-modified": "Fri, 27 Nov 2009 06:27:21 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "538"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "CP=\"COM NAV INT STA NID OUR IND NOI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "set-cookie": "JSESSIONID=AA69DF8838B33636B86F3AD5917D28DD; Path=/orbserv; HttpOnly"
+        },
+        {
+          "content-type": "text/html;charset=ISO-8859-1"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-length": "5"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "859"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "X-LI-IDC=C1"
+        },
+        {
+          "p3p": "CP=\"CAO DSP COR CUR ADMi DEVi TAIi PSAi PSDi IVAi IVDi CONi OUR DELi SAMi UNRi PUBi OTRi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT POL PRE\""
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sun, 05 Aug 2012 15:35:43 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "x-fs-uuid": "e4dcbadff47540485aebb5d079a66252"
+        },
+        {
+          "x-li-uuid": "aGvE/vUVwxKwMlIRJCsAAA=="
+        },
+        {
+          "age": "0"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-length": "6507"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "u=8|0BAgYJ9UoGCfVKwAAAAABAQEAAQQhdawAARg9fRc3AAAAAAT9PvgAAAAAAu5WuAAAAAAO_VtUCBMBAAuBLQA; Version=1; Domain=.agkn.com; Max-Age=63072000; Expires=Mon, 03-Nov-2014 13:14:19 GMT; Path=/"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "expires": "Sat, 01 Jan 2000 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "image/gif;charset=ISO-8859-1"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:18 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-length": "3183"
+        },
+        {
+          "last-modified": "Tue, 04 Mar 2008 16:53:17 GMT"
+        },
+        {
+          "etag": "1204649597000"
+        },
+        {
+          "server": "Jetty(6.1.26)"
+        },
+        {
+          "x-cdn": "AKAM"
+        },
+        {
+          "cache-control": "max-age=31199347"
+        },
+        {
+          "expires": "Wed, 30 Oct 2013 15:43:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-li-uuid": "uBgHimv9whIwouPuKysAAA=="
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Mon, 18 Jun 2012 13:12:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"eb63c14544dcd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "2955"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 04 Aug 1978 12:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "server": "QS"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "age": "168250"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Thu, 01 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Wed, 19 Apr 2000 11:43:00 GMT"
+        },
+        {
+          "last-modified": "Wed, 21 Jan 2004 19:51:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
+        },
+        {
+          "age": "168250"
+        },
+        {
+          "server": "GFE/2.0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:14:19 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_29.json b/jetty-http2/http2-hpack/src/test/resources/data/story_29.json
new file mode 100644
index 0000000..01bdbbf
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_29.json
@@ -0,0 +1,13780 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "301"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "location": "http://www.msn.com/"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:27 GMT"
+        },
+        {
+          "content-length": "142"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\""
+        },
+        {
+          "set-cookie": "SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20121103; expires=Mon, 03-Nov-2014 13:29:29 GMT; domain=.msn.com; path=/"
+        },
+        {
+          "errorcodecount": "[0:0]"
+        },
+        {
+          "s": "CO3SCH010020101"
+        },
+        {
+          "edge-control": "no-store"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:28 GMT"
+        },
+        {
+          "content-length": "41648"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=43200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"808cfaf3c1ac81:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "age": "7374"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2007 15:02:13 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 23:26:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=86400,public"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"078def13c1fcd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "age": "33322"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 21:31:28 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:14:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"083df89b6bac81:0\""
+        },
+        {
+          "server": "BLUMPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "1162"
+        },
+        {
+          "age": "9388284"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Tue, 20 May 2008 20:17:34 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:38:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=86400,public"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"078def13c1fcd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "age": "33322"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 20 Apr 2012 21:31:28 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:14:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"096b38d19cc1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "417"
+        },
+        {
+          "age": "11654605"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Tue, 03 May 2011 20:32:28 GMT"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 16:06:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"99789f9faea8cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "2712"
+        },
+        {
+          "age": "378940"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 19:20:21 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 04:13:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"d6db97976eb9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "3262"
+        },
+        {
+          "age": "37907"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:54:50 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 02:57:42 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"6c2a9d5170b1cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "4648"
+        },
+        {
+          "age": "23683"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 22:47:02 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:54:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0922651f38cb1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "4286"
+        },
+        {
+          "age": "9388299"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Tue, 10 Aug 2010 00:03:00 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:37:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"f9f8904b5ab9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4352"
+        },
+        {
+          "age": "46151"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:29:32 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 00:40:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8437263c89b8cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "6131"
+        },
+        {
+          "age": "23313"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 23:33:02 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:00:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"54a642c148b9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "5522"
+        },
+        {
+          "age": "23304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:23:59 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:01:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"f5d7f6f68b8cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "4048"
+        },
+        {
+          "age": "23326"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 19:38:15 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:00:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"789825b3b68cc1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "7075"
+        },
+        {
+          "age": "304691"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Aug 2011 18:27:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 00:51:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"6a4618d83cb9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "11544"
+        },
+        {
+          "age": "59087"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 20:58:43 GMT"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 21:04:42 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"188d971c36b9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "3753"
+        },
+        {
+          "age": "23326"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 20:10:32 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:00:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80a9243afa8cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "2135"
+        },
+        {
+          "age": "64967"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 19:24:57 GMT"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 19:26:42 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"da259a60afb9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "6786"
+        },
+        {
+          "age": "9961"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 10:38:35 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:43:28 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"3a2bfd7658b9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "6859"
+        },
+        {
+          "age": "47464"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:16:26 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 00:18:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"feefae84ab9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "7066"
+        },
+        {
+          "age": "23304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:39:23 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:01:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"4b1b97dcc0b9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "14928"
+        },
+        {
+          "age": "2676"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 12:43:44 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 12:44:53 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80f314cf17b7cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "23864"
+        },
+        {
+          "age": "290866"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 03:28:35 GMT"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 04:41:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"9c71d229a3b9cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "7497"
+        },
+        {
+          "age": "14681"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 09:11:09 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 09:24:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=300"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=43200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"91588811bb8bcd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "2420"
+        },
+        {
+          "age": "41017"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Wed, 05 Sep 2012 23:06:23 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:05:53 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0e49dbec5aecb1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "4082"
+        },
+        {
+          "age": "8615761"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 07 Jan 2011 23:51:04 GMT"
+        },
+        {
+          "expires": "Fri, 26 Jul 2013 20:13:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"ac1668bfc52ca1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "657"
+        },
+        {
+          "age": "159348"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Thu, 22 Oct 2009 09:46:35 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 17:13:42 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"803ab9aa463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "24630"
+        },
+        {
+          "age": "9388297"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:19:05 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:37:53 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"02bfb6a29b7cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "65670"
+        },
+        {
+          "age": "285810"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 05:34:38 GMT"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 06:06:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80d88a9463acd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "age": "8077925"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:19:03 GMT"
+        },
+        {
+          "expires": "Fri, 02 Aug 2013 01:37:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8097d798463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "48"
+        },
+        {
+          "age": "9389765"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:35 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:13:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"5bc3dfd117b7cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "6234"
+        },
+        {
+          "age": "290867"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 03:28:39 GMT"
+        },
+        {
+          "expires": "Thu, 31 Oct 2013 04:41:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"801e6b9c463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "1117"
+        },
+        {
+          "age": "8614139"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:41 GMT"
+        },
+        {
+          "expires": "Fri, 26 Jul 2013 20:40:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"077efa8463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "age": "11574965"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:19:02 GMT"
+        },
+        {
+          "expires": "Sat, 22 Jun 2013 14:13:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8097d798463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "1142"
+        },
+        {
+          "age": "9388300"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:35 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:37:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8086f4a5463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "172"
+        },
+        {
+          "age": "9388300"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:57 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:37:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8016f7a74e67cc1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "421"
+        },
+        {
+          "age": "9389765"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Tue, 30 Aug 2011 19:54:41 GMT"
+        },
+        {
+          "expires": "Wed, 17 Jul 2013 21:13:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"9a7af237eb5cd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "5436"
+        },
+        {
+          "age": "462287"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 02:35:10 GMT"
+        },
+        {
+          "expires": "Tue, 29 Oct 2013 05:04:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "content-length": "1640"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "3989"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10263730-T100595690-C40000000000114208"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\""
+        },
+        {
+          "set-cookie": "SRCHD=MS=2546729&D=2546729&AF=NOFORM; expires=Mon, 03-Nov-2014 13:29:30 GMT; domain=.msn.com; path=/"
+        },
+        {
+          "errorcodecount": "[0:0]"
+        },
+        {
+          "s": "CO3SCH010133009"
+        },
+        {
+          "edge-control": "no-store"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "content-length": "2197"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://c.atdmt.com/c.gif?udc=true&di=340&pi=7317&ps=95101&lng=en-us&tp=http%3A%2F%2Fwww.msn.com%2Fdefaultwpe3w.aspx&rid=e32241cc231e4226b91543c154dd3b7e&rnd=1351949370023&rf=&scr=1366x768&RedC=c.msn.com&MXFR=3D632B5B5356602B36252F56575660EB"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "MUID=3D632B5B5356602B36252F56575660EB&TUID=1; domain=.msn.com; expires=Mon, 03-Nov-2014 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-location": "http://spe.atdmt.com/images/pixel.gif"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:29 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/3642305/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "GFE/2.0"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0287ded7fb9cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "1811"
+        },
+        {
+          "age": "1765"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:58:56 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:30:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80722a7c098cc1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "9346"
+        },
+        {
+          "age": "1170"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Tue, 01 Nov 2011 18:04:09 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0af38a5c098cc1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "20808"
+        },
+        {
+          "age": "1411"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Tue, 01 Nov 2011 18:04:06 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:35:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"8091e4ec7fb9cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "1142"
+        },
+        {
+          "age": "1226"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:58:55 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://c.msn.com/c.gif?udc=true&di=340&pi=7317&ps=95101&lng=en-us&tp=http%3A%2F%2Fwww.msn.com%2Fdefaultwpe3w.aspx&rid=e32241cc231e4226b91543c154dd3b7e&rnd=1351949370023&rf=&scr=1366x768&MUID=39C1843BD7CB679E06238036D4CB670B&cb=1cdb9c7414258b0"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "SRM_M=39C1843BD7CB679E06238036D4CB670B; domain=c.atdmt.com; expires=Mon, 03-Nov-2014 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"299a82bdeb9cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-length": "20046"
+        },
+        {
+          "age": "1074"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 15:28:42 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:36 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Fri, 17 Aug 2012 14:27:55 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 19:34:58 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 19:34:58 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "64473"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 07:00:23 GMT"
+        },
+        {
+          "server": "Jetty(6.1.22)"
+        },
+        {
+          "p3p": "policyref=\"/w3c/policy.xml\", CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-powered-by": "Mirror Image Internet"
+        },
+        {
+          "via": "1.1 bfi061004 (MII-APC/2.2)"
+        },
+        {
+          "x-mii-cache-hit": "1"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "keep-alive": "timeout=2"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0e2349e463acd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "93"
+        },
+        {
+          "age": "8077926"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:31 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:44 GMT"
+        },
+        {
+          "expires": "Fri, 02 Aug 2013 01:37:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "set-cookie": "pudm_AAAA=MLuxc4uHAF5HEldAttN+mTMH5l3UFcGfjYAvMSjMMwDWP3TDUWl1; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:29:31 GMT; Path=/"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "x-proc-data": "pd3-bgas02-0"
+        },
+        {
+          "content-type": "application/javascript;charset=ISO-8859-1"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "p3p": "CP=\"NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND\""
+        },
+        {
+          "set-cookie": "SRCHD=SM=1&MS=2546729&D=2546729&AF=NOFORM; expires=Mon, 03-Nov-2014 13:29:31 GMT; domain=.msn.com; path=/"
+        },
+        {
+          "errorcodecount": "[0:0]"
+        },
+        {
+          "s": "CO3SCH010120128"
+        },
+        {
+          "edge-control": "no-store"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:30 GMT"
+        },
+        {
+          "content-length": "1672"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0a420aa463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "387"
+        },
+        {
+          "age": "11654712"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:31 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:19:04 GMT"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 16:04:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"05ba19a463acd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "4842"
+        },
+        {
+          "age": "11654572"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:38 GMT"
+        },
+        {
+          "expires": "Fri, 21 Jun 2013 16:06:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80b325a7463acd1:0\""
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "1105"
+        },
+        {
+          "age": "8614141"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "last-modified": "Fri, 25 May 2012 07:18:59 GMT"
+        },
+        {
+          "expires": "Fri, 26 Jul 2013 20:40:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "content-length": "562"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "884"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10669318-T100595843-C108000000000115722"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "3114"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-radid": "P10603404-T100595756-C48000000000113484"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:31 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1323"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:31 GMT"
+        },
+        {
+          "content-length": "1336"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "3147"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10720545-T100595939-C52000000000120598"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "406"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-radid": "P3782944-T100582739-C521263"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:31 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "325"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0bd514f14ac31:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "content-length": "85"
+        },
+        {
+          "age": "12894277"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "last-modified": "Tue, 15 Jul 2003 16:49:38 GMT"
+        },
+        {
+          "expires": "Fri, 07 Jun 2013 07:44:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=31535999"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "2710"
+        },
+        {
+          "age": "3659370"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "expires": "Sun, 22 Sep 2013 05:00:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=31508189"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "9220"
+        },
+        {
+          "age": "3659358"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "expires": "Sat, 21 Sep 2013 21:16:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=31338077"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "3607"
+        },
+        {
+          "age": "3400121"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "expires": "Sun, 22 Sep 2013 22:02:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 09:35:33 GMT"
+        },
+        {
+          "etag": "\"1411999884f419ea8219bf9b531a9c66\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/javascript; charset=utf-8"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3260"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "etag": "\"377d257f2d2e294916143c069141c1c5:1328738114\""
+        },
+        {
+          "last-modified": "Wed, 08 Feb 2012 21:55:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:10:52 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "status": "200 OK"
+        },
+        {
+          "content-type": "application/javascript;charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "889"
+        },
+        {
+          "server": "tfe"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, post-check=0, pre-check=0"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-transaction": "49df427f743e57d8"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "expires": "Tue, 31 Mar 1981 05:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate, pre-check=0, post-check=0"
+        },
+        {
+          "set-cookie": "guest_id=v1%3A135194937257731566; Expires=Mon, 3-Nov-2014 13:29:32 GMT; Path=/; Domain=.twitter.com"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "65"
+        },
+        {
+          "server": "tfe"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 09:48:13 GMT"
+        },
+        {
+          "etag": "\"b036a791811effc968bfcb43fa6d6910\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7242"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "p3p": "CP=\"CAO DSP LAW CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "cache-control": "public, max-age=1800"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:34 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 16:28:26 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 16:28:26 GMT"
+        },
+        {
+          "etag": "412224A3234E88A2760468333271010BB1C6D1AA"
+        },
+        {
+          "cache-control": "max-age=355731,public,no-transform,must-revalidate"
+        },
+        {
+          "x-ocsp-reponder-id": "t8edcaocsp4"
+        },
+        {
+          "content-length": "471"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-transfer-encoding": "Binary"
+        },
+        {
+          "content-length": "1938"
+        },
+        {
+          "connection": "Close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:34 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 16:28:26 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 16:28:26 GMT"
+        },
+        {
+          "etag": "412224A3234E88A2760468333271010BB1C6D1AA"
+        },
+        {
+          "cache-control": "max-age=355731,public,no-transform,must-revalidate"
+        },
+        {
+          "x-ocsp-reponder-id": "t8edcaocsp4"
+        },
+        {
+          "content-length": "471"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "content-length": "28018"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 06:48:54 GMT"
+        },
+        {
+          "server": "Jetty(6.1.22)"
+        },
+        {
+          "p3p": "policyref=\"/w3c/policy.xml\", CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-powered-by": "Mirror Image Internet"
+        },
+        {
+          "via": "1.1 bfi061001 (MII-APC/2.2)"
+        },
+        {
+          "x-mii-cache-hit": "1"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "keep-alive": "timeout=2"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"80ebcf5152b0cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "6717"
+        },
+        {
+          "age": "1026619"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:39:47 GMT"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 16:19:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0195ab552b0cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "8659"
+        },
+        {
+          "age": "1026617"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:42:34 GMT"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 16:19:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"707a74ac52b0cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "9389"
+        },
+        {
+          "age": "1026617"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:42:19 GMT"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 16:19:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"f0edab8b52b0cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "3749"
+        },
+        {
+          "age": "1026645"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:41:24 GMT"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 16:18:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "content-length": "4286"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"951751d2bdb7cd1:0\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "773"
+        },
+        {
+          "age": "416777"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 17:43:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431989"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "4747"
+        },
+        {
+          "age": "69970"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 18:03:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=423916"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "45125"
+        },
+        {
+          "age": "4791"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 09:55:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public,max-age=31536000"
+        },
+        {
+          "content-length": "42060"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"1ac2aef461a9cc1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "p3p": "CP=\"ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI\""
+        },
+        {
+          "vtag": "279606632500000000"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "age": "3987586"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        },
+        {
+          "last-modified": "Tue, 22 Nov 2011 21:59:06 GMT"
+        },
+        {
+          "expires": "Wed, 18 Sep 2013 09:49:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG7]PCxrx)0s]#%2L_'x%SEV/hnJip4FQV_eKj?9kb10I3SSI79ox)!lG@t]; path=/; expires=Fri, 01-Feb-2013 13:29:36 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        },
+        {
+          "content-length": "615"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:35 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "381"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 04:51:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG7]PCxrx)0s]#%2L_'x%SEV/hnJip4FQV_eKj?9kb10I3SSI79ox)!lG@t]; path=/; expires=Fri, 01-Feb-2013 13:29:36 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089389.300024620"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:36 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "2290"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "40789"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 21:57:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "20802"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 06:30:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431968"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "4319"
+        },
+        {
+          "age": "1707"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 13:00:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431760"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "5321"
+        },
+        {
+          "age": "14923"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 09:16:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431996"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4605"
+        },
+        {
+          "age": "46358"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 00:36:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431925"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4097"
+        },
+        {
+          "age": "64344"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:35:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=432000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4692"
+        },
+        {
+          "age": "32851"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 04:22:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431754"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "2555"
+        },
+        {
+          "age": "14924"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 09:16:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431758"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4026"
+        },
+        {
+          "age": "54890"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 22:10:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431997"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "4589"
+        },
+        {
+          "age": "403007"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 21:32:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "3476"
+        },
+        {
+          "age": "82129"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:40:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431839"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "5927"
+        },
+        {
+          "age": "53455"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 22:36:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431993"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "4900"
+        },
+        {
+          "age": "83837"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:12:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431997"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4420"
+        },
+        {
+          "age": "88061"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:01:53 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/octet-stream"
+        },
+        {
+          "content-length": "2209"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 19:27:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431982"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "5496"
+        },
+        {
+          "age": "63170"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:56:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "3450"
+        },
+        {
+          "age": "89554"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 12:36:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "2271"
+        },
+        {
+          "age": "92961"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 11:40:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431991"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4009"
+        },
+        {
+          "age": "86314"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:30:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431989"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "3779"
+        },
+        {
+          "age": "86708"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:24:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431976"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "3115"
+        },
+        {
+          "age": "69186"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 18:16:07 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "4867"
+        },
+        {
+          "age": "80624"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:05:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431993"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "5187"
+        },
+        {
+          "age": "140253"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 22:31:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431966"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "5244"
+        },
+        {
+          "age": "140817"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 22:22:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431931"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "3807"
+        },
+        {
+          "age": "303973"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 01:02:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431977"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "4135"
+        },
+        {
+          "age": "143835"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 21:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431943"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "5096"
+        },
+        {
+          "age": "64149"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:39:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431988"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "3801"
+        },
+        {
+          "age": "125275"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 02:41:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431990"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "4499"
+        },
+        {
+          "age": "144182"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 21:26:25 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:37 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "23449"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0feb9575b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "5942"
+        },
+        {
+          "age": "717045"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:33:48 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:18:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"0f9f3446b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "8528"
+        },
+        {
+          "age": "717044"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:40:26 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:18:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"968a7a9552b0cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "8149"
+        },
+        {
+          "age": "1026651"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 12:41:40 GMT"
+        },
+        {
+          "expires": "Tue, 22 Oct 2013 16:18:51 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "4286"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"951751d2bdb7cd1:0\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=24"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********532"
+        },
+        {
+          "rendertime": "11/2/2012 8:14:13 AM"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "34971"
+        },
+        {
+          "age": "39"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:42 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 15:14:13 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:44:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG3x=Cxrx)0s]#%2L_'x%SEV/hnKu94FQV_eKj?9kb10I3SSI7:0wHz@)G?)i4ZhK; path=/; expires=Fri, 01-Feb-2013 13:29:43 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "content-length": "514"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=7775467"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********532"
+        },
+        {
+          "rendertime": "11/2/2012 8:14:13 AM"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "27220"
+        },
+        {
+          "age": "226499"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:25:52 GMT"
+        },
+        {
+          "expires": "Tue, 29 Jan 2013 22:25:51 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-length": "1465"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "age": "77450"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Thu, 06 Sep 2012 03:42:16 GMT"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 15:58:54 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089440.299934848"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "514"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "3936"
+        },
+        {
+          "age": "1664"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 11:56:42 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:35:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "4646"
+        },
+        {
+          "age": "1653"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:42:24 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 17:14:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "14780"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 04:45:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "41165"
+        },
+        {
+          "age": "1664"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:52:34 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:31:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "location": "http://m.adnxs.com/msftcookiehandler?t=1&c=MUID%3d39C1843BD7CB679E06238036D4CB670B"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "content-length": "13"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "sess=1; path=/; expires=Sun, 04-Nov-2012 13:29:43 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "content-length": "43"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "7206"
+        },
+        {
+          "age": "1871"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 19:21:20 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:46:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "2833"
+        },
+        {
+          "age": "4319"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 01:22:37 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:57:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "4141"
+        },
+        {
+          "age": "1871"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 09:14:16 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:47:24 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=600"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:43 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********529"
+        },
+        {
+          "rendertime": "11/3/2012 6:29:43 AM"
+        },
+        {
+          "x-rendertime": "0.017 secs"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "content-length": "6790"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "7264"
+        },
+        {
+          "age": "4321"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:45:33 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:47:42 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=7776000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********532"
+        },
+        {
+          "rendertime": "11/2/2012 8:14:13 AM"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "3083"
+        },
+        {
+          "age": "227101"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:24:43 GMT"
+        },
+        {
+          "expires": "Tue, 29 Jan 2013 22:24:43 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=7775989"
+        },
+        {
+          "content-type": "text/css; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********532"
+        },
+        {
+          "rendertime": "11/2/2012 8:14:13 AM"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "631"
+        },
+        {
+          "age": "227144"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:23:50 GMT"
+        },
+        {
+          "expires": "Tue, 29 Jan 2013 22:23:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "5366"
+        },
+        {
+          "age": "2169"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 23:46:05 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:23:35 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=7775981"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "5125"
+        },
+        {
+          "age": "227144"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:23:41 GMT"
+        },
+        {
+          "expires": "Tue, 29 Jan 2013 22:23:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "38544"
+        },
+        {
+          "age": "1664"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:46:18 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:32:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, max-age=7775962"
+        },
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "68447"
+        },
+        {
+          "age": "227086"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 22:24:21 GMT"
+        },
+        {
+          "expires": "Tue, 29 Jan 2013 22:24:20 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********525"
+        },
+        {
+          "rendertime": "11/3/2012 6:29:44 AM"
+        },
+        {
+          "x-rendertime": "0.003 secs"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:43 GMT"
+        },
+        {
+          "content-length": "1238"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "machine": "SN1********509"
+        },
+        {
+          "rendertime": "11/3/2012 6:29:44 AM"
+        },
+        {
+          "set-cookie": "zip=c:cz; domain=msn.com; expires=Sat, 10-Nov-2012 14:29:44 GMT; path=/"
+        },
+        {
+          "x-rendertime": "0.067 secs"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:44 GMT"
+        },
+        {
+          "content-length": "138"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:46 GMT"
+        },
+        {
+          "content-length": "25630"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"951751d2bdb7cd1:0\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=422586"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "818"
+        },
+        {
+          "age": "321488"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 17:34:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "1996"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG68%Cxrx)0s]#%2L_'x%SEV/hnJPh4FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1Ra^uI$+VZ; path=/; expires=Fri, 01-Feb-2013 13:29:47 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-length": "1463"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "ntcoent-length": "42"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "6:29:42 AM"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "trackingid": "3bd68bdc-1e91-410e-bd92-a85913c08914"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "54"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "must-revalidate"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 13:29:48 GMT"
+        },
+        {
+          "set-cookie": "fc=rqbE3Poup4Ofv8GxDEGHJ0T2mPet6qErhzJbX2aX0FVY8uK-xitYHevMNKV5qRPTQHHOFrDBExLyIrZ-jLRD_r3wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:48 GMT; Path=/"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:47 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:48 GMT"
+        },
+        {
+          "content-length": "4142"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "cache-control": "private, max-age=0, no-cache, no-store, must-revalidate, proxy-revalidate"
+        },
+        {
+          "expires": "Sat, 1 Jan 2000 01:01:00 GMT"
+        },
+        {
+          "last-modified": "Sat, 1 Jan 2000 01:01:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "AdifyServer"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "45"
+        },
+        {
+          "set-cookie": "s=1,2*50951c4c*3Q4liHxMwG*rZye1ewDYpnkdvSJkze6tOMY_w==*; path=/; expires=Mon, 03-Nov-2014 13:29:48 GMT; domain=afy11.net;"
+        },
+        {
+          "p3p": "policyref=\"http://ad.afy11.net/privacy.xml\", CP=\" NOI DSP NID ADMa DEVa PSAa PSDa OUR OTRa IND COM NAV STA OTC\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "sess=1; path=/; expires=Sun, 04-Nov-2012 13:29:49 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "location": "http://r.turn.com/r/bd?ddc=1&pid=54&cver=1&uid=3755642153863499992"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "text/html; charset=ISO-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "GlassFish v3"
+        },
+        {
+          "p3p": "policyref=\"/bh/w3c/p3p.xml\", CP=\"NOI DSP COR NID CURa DEVa PSAa OUR BUS COM NAV INT\""
+        },
+        {
+          "set-cookie": "pb_rtb_ev=2-535461.3194305635051091579.0.0.1351949514647; Domain=.contextweb.com; Expires=Sun, 03-Nov-2013 13:31:54 GMT; Path=/"
+        },
+        {
+          "cw-server": "lga-app602"
+        },
+        {
+          "cache-control": "private, max-age=0, no-cache, no-store"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "content-type": "image/gif;charset=ISO-8859-1"
+        },
+        {
+          "content-language": "en-US"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:31:54 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "cache-control": "post-check=0, pre-check=0"
+        },
+        {
+          "content-location": "partner.html"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "location": "http://cdn.spotxchange.com/media/thumbs/pixel/pixel.gif"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR IND UNI COM NAV ADMa\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8e-fips-rhel5"
+        },
+        {
+          "set-cookie": "partner-0=eNptzM0KgkAUQOF1vUvgzzCF0MJwkpGuF3WyGXcpBKOZLYLJ%2B%2FRJtGx7OHyc7fxVdOBsU4lSxifZiCQyaiJ8vAh7EaLNnNGZ1471rMOaGp3dmvTomUpuO5ocWmkxBA4q5nKsWZfeZ6PLZxswi8GwdAigh3dOwFB9Tf%2Bfeb0UP2fgcvlRFQTJOQA6u1wJh0r4OQ3L4%2B3XH6c7OqM%3D; expires=Sun, 03-Mar-2013 13:29:49 GMT; path=/; domain=.spotxchange.com"
+        },
+        {
+          "tcn": "choice"
+        },
+        {
+          "vary": "negotiate"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "location": "http://r.turn.com/r/cms/id/0/ddc/1/pid/18/uid/?google_gid=CAESEITR3tLElIgxNs25jzV8Md0&google_cver=1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "server": "Cookie Matcher"
+        },
+        {
+          "content-length": "300"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "cache-control": "public, max-age=30, proxy-revalidate"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "CP=\"CUR ADM OUR NOR STA NID\""
+        },
+        {
+          "set-cookie": "i=cbdc52da-b3d4-4f79-bc70-3121d006fdfa; expires=Mon, 03-Nov-2014 13:29:49 GMT; path=/; domain=.openx.net"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "server": "Apache/2.2.3 (CentOS)"
+        },
+        {
+          "x-powered-by": "PHP/5.3.3"
+        },
+        {
+          "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "set-cookie": "put_1185=3194305635051091579; expires=Wed, 02-Jan-2013 13:29:49 GMT; path=/; domain=.rubiconproject.com"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "keep-alive": "timeout=30, max=9907"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "server": "Apache/2.2.22 (Ubuntu)"
+        },
+        {
+          "x-powered-by": "PHP/5.3.10-1ubuntu3.4"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "private, max-age=0, no-cache, max-age=86400, must-revalidate"
+        },
+        {
+          "p3p": "CP=\"CUR ADM OUR NOR STA NID\""
+        },
+        {
+          "set-cookie": "ljtrtb=eJyrVjJUslIyNrQ0MTYwNTM2NTA1NLA0NDW3VKoFAE9vBcg%3D; expires=Sun, 03-Nov-2013 13:29:49 GMT; path=/; domain=.lijit.com"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:48 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:49 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "adaptv/1.0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "set-cookie": "rtbData0=\"key=turn:value=3194305635051091579:expiresAt=Sat+Nov+10+05%3A29%3A49+PST+2012:32-Compatible=true\";Path=/;Domain=.adap.tv;Expires=Mon, 03-Nov-2014 13:29:49 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "W/\"21947-1351808321000\""
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:18:41 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "21947"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:49 GMT"
+        },
+        {
+          "server": "Apache/2.2.4 (Unix) DAV/2 mod_ssl/2.2.4 OpenSSL/0.9.7a mod_fastcgi/2.4.2"
+        },
+        {
+          "set-cookie": "PUBRETARGET=82_1446557389; domain=pubmatic.com; expires=Tue, 03-Nov-2015 13:29:49 GMT; path=/"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR LAW CUR ADMo DEVo TAIo PSAo PSDo IVAo IVDo HISo OTPo OUR SAMo BUS UNI COM NAV INT DEM CNT STA PRE LOC\""
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 26 May 2011 15:59:36 UTC"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "max-age=182357"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "set-cookie": "CMDD=;domain=casalemedia.com;path=/;expires=Sun, 04 Nov 2012 13:29:50 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "p3p": "policyref=\"http://tag.admeld.com/w3c/p3p.xml\", CP=\"PSAo PSDo OUR SAM OTR BUS DSP ALL COR\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "none"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://files.adbrite.com/w3c/p3p.xml\",CP=\"NOI PSA PSD OUR IND UNI NAV DEM STA OTC\""
+        },
+        {
+          "server": "XPEHb/1.2"
+        },
+        {
+          "set-cookie": "rb2=CiQKBjc0MjY5Nxjxxt_6vwEiEzMxOTQzMDU2MzUwNTEwOTE1NzkQAQ; path=/; domain=.adbrite.com; expires=Fri, 01-Feb-2013 13:29:50 GMT"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "none"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:50 GMT"
+        },
+        {
+          "expires": "Mon, 26 Jul 1997 05:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://files.adbrite.com/w3c/p3p.xml\",CP=\"NOI PSA PSD OUR IND UNI NAV DEM STA OTC\""
+        },
+        {
+          "server": "XPEHb/1.2"
+        },
+        {
+          "set-cookie": "rb2=CiUKBzExMTM4NzQY78bf-r8BIhMzMTk0MzA1NjM1MDUxMDkxNTc5EAE; path=/; domain=.adbrite.com; expires=Fri, 01-Feb-2013 13:29:50 GMT"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:51 GMT"
+        },
+        {
+          "content-length": "24328"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"951751d2bdb7cd1:0\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"809c1885b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "7723"
+        },
+        {
+          "age": "717364"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:35:09 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:13:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"08343346b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "11495"
+        },
+        {
+          "age": "717363"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:39:58 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:13:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001003"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:51 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"4bbce916b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "10962"
+        },
+        {
+          "age": "717363"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:38:33 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:13:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"cf3edfd75b2cd1:0\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "2004"
+        },
+        {
+          "age": "717364"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 16:37:22 GMT"
+        },
+        {
+          "expires": "Sat, 26 Oct 2013 06:13:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "content-length": "955"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=309678"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "26369"
+        },
+        {
+          "age": "62302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 10:12:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:51 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430622"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "45394"
+        },
+        {
+          "age": "62302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG5+^Cxrx)0s]#%2L_'x%SEV/hnK]14FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1k^WD2#$i1)erK!!*m?S=+svq; path=/; expires=Fri, 01-Feb-2013 13:29:52 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "content-length": "1391"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "must-revalidate"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "set-cookie": "fc=PwF5GJAr9THO6EaVkyk6nl6s2gAVQMeB09yelt5Ns41Y8uK-xitYHevMNKV5qRPT6cGxTnB2KJjyGGqZV9P7973wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:52 GMT; Path=/"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "p3p": "CP=\"NOI CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\""
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "set-cookie": "p=1-dPmPP55J4f0S;Path=/;Domain=.rfihub.com"
+        },
+        {
+          "location": "http://ib.adnxs.com/pxj?bidder=18&seg=378601&action=setuids('672725195243299649','');&redir="
+        },
+        {
+          "content-length": "0"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG7DHCxrx)0s]#%2L_'x%SEV/hnK)x4FQV_eKj?9AMF4:V)4hY/82QjU'-Rw1k^WD2#$i1)erM67KPze!'cEZmBiRY; path=/; expires=Fri, 01-Feb-2013 13:29:52 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:52 GMT"
+        },
+        {
+          "content-length": "4142"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        },
+        {
+          "location": "http://dpm.demdex.net/ibs:dpid=375&dpuuid=3194305635051091579"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        },
+        {
+          "location": "http://tags.bluekai.com/site/4499?id=3194305635051091579"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat,  03 Nov 2012 13:29:53 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "server": "AAWebServer"
+        },
+        {
+          "p3p": "policyref=\"http://www.adadvisor.net/w3c/p3p.xml\",CP=\"NOI NID\""
+        },
+        {
+          "content-length": "21"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "set-cookie": "ab=0001%3ATeN7H043oXvJ0Gd0I9Rzik4yxpbxTv3S; Domain=.adadvisor.net; Expires=Sat,  03 Nov 2013 13:29:53 GMT; Path=/"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\""
+        },
+        {
+          "dcs": "la-dcs-3-1.internal.demdex.com 1.9.12"
+        },
+        {
+          "set-cookie": "demdex=24048888904140259620062165691276314735;Path=/;Domain=.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 2009 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "location": "http://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=375&dpuuid=3194305635051091579"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "server": "Jetty(7.2.2.v20101205)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\""
+        },
+        {
+          "dcs": "la-dcs-6-3.internal.demdex.com 1.9.12"
+        },
+        {
+          "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 2009 00:00:00 GMT"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "sts": "OK"
+        },
+        {
+          "content-length": "308"
+        },
+        {
+          "server": "Jetty(7.2.2.v20101205)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/"
+        },
+        {
+          "location": "http://segment-pixel.invitemedia.com/set_partner_uid?partnerID=402&sscs_active=1&partnerUID=3194305635051091579"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:53 GMT; Path=/"
+        },
+        {
+          "location": "http://dpm.demdex.net/ibs:dpid=470&dpuuid=3194305635051091579"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\""
+        },
+        {
+          "dcs": "la-dcs-6-4.internal.demdex.com 1.9.12"
+        },
+        {
+          "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 2009 00:00:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "sts": "OK"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "server": "Jetty(7.2.2.v20101205)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        },
+        {
+          "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "location": "http://cm.g.doubleclick.net/pixel?google_nid=invitemedia&google_cm&google_hm=ZGdnc8YbR_itxPPM3K8lNw=="
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "server": "Jetty(7.3.1.v20110307)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "location": "http://g-pixel.invitemedia.com/gmatcher?google_gid=CAESEIZ7yBsa025UuJ5EUDIscrc&google_cver=1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "server": "Cookie Matcher"
+        },
+        {
+          "content-length": "293"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "server": "Jetty(7.3.1.v20110307)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3512552298351731296; Domain=.audienceiq.com; Expires=Thu, 02-May-2013 13:29:54 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3819163497929337273; Domain=.audienceiq.com; Expires=Thu, 02-May-2013 13:29:54 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "server": "Apache/2.2.3 (CentOS)"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CUR ADMo DEVo PSAo PSDo OUR SAMo BUS UNI NAV\", policyref=\"http://tags.bluekai.com/w3c/p3p.xml\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store"
+        },
+        {
+          "set-cookie": "bkdc=wdc; expires=Mon, 03-Dec-2012 13:29:54 GMT; path=/; domain=.bluekai.com"
+        },
+        {
+          "bk-server": "f325"
+        },
+        {
+          "content-length": "62"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430617"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "49975"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:27 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=402248"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "54206"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 11:55:38 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=404329"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "34129"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 12:30:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "30171"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=424287"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "32018"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 18:02:58 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=427425"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "24185"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 18:55:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=272174"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "33943"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 23:47:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=325871"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "52353"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 14:42:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430158"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "29736"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:40:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430924"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "16459"
+        },
+        {
+          "age": "62304"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:53:34 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=392023"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "16888"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 09:05:14 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "39134"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430616"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "18663"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:27 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430616"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "22545"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:27 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=309680"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "48746"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 10:12:51 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=307453"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "32656"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 09:35:44 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431902"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "4473"
+        },
+        {
+          "age": "16748"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 08:49:08 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=429492"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "5239"
+        },
+        {
+          "age": "22750"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 06:28:56 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426970"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "4784"
+        },
+        {
+          "age": "22751"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 05:46:53 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431944"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "3843"
+        },
+        {
+          "age": "50495"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 23:27:23 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431143"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "4058"
+        },
+        {
+          "age": "50541"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 23:13:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431761"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "3291"
+        },
+        {
+          "age": "84703"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:54:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430621"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "34459"
+        },
+        {
+          "age": "62302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:48:33 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "1996"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001006"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG4S]cvjr/?0P(*AuB-u**g1:XIFC`Ei'/AQwFYO^vhHR3SSI7:0ssX1ka!s@?zYs*/7]T1O`l^oQUpqMxHLk'kk[7/>IRq; path=/; expires=Fri, 01-Feb-2013 13:29:56 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:56 GMT"
+        },
+        {
+          "content-length": "1447"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "must-revalidate"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 13:29:56 GMT"
+        },
+        {
+          "set-cookie": "fc=2flUeaaDSas8xOI0IwXvS5DprXaL8T8Iioo9PyFO3fRY8uK-xitYHevMNKV5qRPT3ar07KU0y6i_uQzRwZVJBr3wc-cQ7FRKnITKYzO3zYV52dhK4dSErN9-EcLOAtq0; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:56 GMT; Path=/"
+        },
+        {
+          "content-type": "text/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001002"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=337125"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "47409"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 17:50:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html;charset=UTF-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "private, no-cache, no-store, must-revalidate"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:56 GMT"
+        },
+        {
+          "content-length": "4142"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=430158"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "40464"
+        },
+        {
+          "age": "62303"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:54 GMT"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 19:40:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "p3p": "CP=\"NON DSP COR CURa PSA PSD OUR BUS NAV STA\""
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:55 GMT"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "vary": "Accept-Encoding"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:56 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:57 GMT"
+        },
+        {
+          "content-length": "1162"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2685"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10661134-T100558395-C70000000000110100"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:57 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:56 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:57 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-length": "2346"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:57 GMT"
+        },
+        {
+          "location": "http://s0.2mdn.net/viewad/3642305/1-1x1.gif"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "DCLK-AdSvr"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "last-modified": "Tue, 08 May 2012 20:09:07 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 14:30:09 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "321"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "82788"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 20:12:56 GMT"
+        },
+        {
+          "date": "Fri, 02 Nov 2012 20:51:00 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 20:51:00 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "16399"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "age": "59938"
+        },
+        {
+          "cache-control": "public, max-age=86400"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:58 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "953"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "1996"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001006"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:58 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG2<rcvjr/?0P(*AuB-u**g1:XIB_LEi'/AQwFYO^vhHR3SSI7:0ssX1dkoAOc['^!Xu%1Q*<TAN0EGDS>RnOx8gy:7tmWz0W/8y; path=/; expires=Fri, 01-Feb-2013 13:29:59 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "539"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:58 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001003"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089440.299934848"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:58 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "508"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3194305635051091579; Domain=.turn.com; Expires=Thu, 02-May-2013 13:29:59 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:58 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:00 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:00 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG6kGcvjr/?0P(*AuB-u**g1:XIDv6Ei'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:x)IOr/*M`m)sza^*g0Y08QVgH; path=/; expires=Fri, 01-Feb-2013 13:30:00 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:00 GMT"
+        },
+        {
+          "content-length": "536"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089389.300024911"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:29:59 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "2292"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:00 GMT"
+        },
+        {
+          "set-cookie": "io_frequency=;Path=/;Domain=invitemedia.com;Expires=Thu, 01-Jan-1970 00:00:01 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"OTI DSP COR ADMo TAIo PSAo PSDo CONo OUR SAMo OTRo STP UNI PUR COM NAV INT DEM STA PRE LOC\""
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "server": "Jetty(7.3.1.v20110307)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:00 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001006"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001004"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG10Qcvjr/?0P(*AuB-u**g1:XICjmEi'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:8=1cxYEkOC%bAiN80044UhHvz!%M]c5$rYZ; path=/; expires=Fri, 01-Feb-2013 13:30:02 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-length": "555"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "mt2/2.6.2.2465 Sep 24 2012 22:21:34 ewr-pixel-x1 pid 0x7b39 31545"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "set-cookie": "uuid=50951c5a-a617-32b8-be76-b1fea84d696f; domain=.mathtag.com; path=/; expires=Sun, 03-Nov-2013 13:30:02 GMT"
+        },
+        {
+          "location": "http://sync.mathtag.com/sync/img?mt_exid=13&mt_exuid=3755642153863499992&mm_bnc"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300088980.299949017.299886085"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "2684"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "33683"
+        },
+        {
+          "allow": "GET"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 04:46:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "server": "mt2/2.6.2.2465 Sep 24 2012 22:21:34 ewr-pixel-x6 pid 0x3dc6 15814"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID CURa ADMa DEVa PSAa PSDa OUR BUS COM INT OTC PUR STA\""
+        },
+        {
+          "set-cookie": "mt_mop=13:1351949402|10002:1351949402; domain=.mathtag.com; path=/; expires=Mon, 03-Dec-2012 13:30:02 GMT"
+        },
+        {
+          "location": "http://tags.bluekai.com/site/2948?id=50951c5a-a617-32b8-be76-b1fea84d696f"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "server": "Apache/2.2.3 (CentOS)"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR CUR ADMo DEVo PSAo PSDo OUR SAMo BUS UNI NAV\", policyref=\"http://tags.bluekai.com/w3c/p3p.xml\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "set-cookie": "bkdc=wdc; expires=Mon, 03-Dec-2012 13:30:02 GMT; path=/; domain=.bluekai.com"
+        },
+        {
+          "bk-server": "ed3c"
+        },
+        {
+          "content-length": "62"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001003"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:03 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001001"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:02 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:03 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "1996"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:03 GMT"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "954"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG5`$cvjr/?0P(*AuB-u**g1:XIF)WEi'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:8=1cxY3czU+5<.*N0EGE.[oe!wqakQLnSHY42'_N; path=/; expires=Fri, 01-Feb-2013 13:30:03 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:03 GMT"
+        },
+        {
+          "content-length": "534"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089440.299934848"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:03 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "509"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI NID CURa ADMa DEVa PSAa PSDa OUR SAMa BUS PUR COM NAV INT\""
+        },
+        {
+          "dcs": "la-dcs-4-2.internal.demdex.com 1.9.12"
+        },
+        {
+          "set-cookie": "dpm=24048888904140259620062165691276314735;Path=/;Domain=.dpm.demdex.net;Expires=Thu, 03-Nov-2022 23:37:33 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 2009 00:00:00 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "no-cache,no-store,must-revalidate,max-age=0,proxy-revalidate,no-transform,private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "sts": "OK"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "server": "Jetty(7.2.2.v20101205)"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "server": "Microsoft-IIS/8.0"
+        },
+        {
+          "x-aspnetmvc-version": "4.0"
+        },
+        {
+          "x-ua-compatible": "IE=Edge;chrome=1"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-frame-options": "SAMEORIGIN"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:04 GMT"
+        },
+        {
+          "content-length": "26996"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 23:16:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"951751d2bdb7cd1:0\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "private, no-cache, proxy-revalidate, no-store"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "last-modified": "Thu, 20 Oct 2011 10:27:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"04baaef128fcc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "set-cookie": "ANONCHK=0; domain=c.msn.com; expires=Tue, 06-Nov-2012 13:29:30 GMT; path=/;"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001005"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:04 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, must-revalidate"
+        },
+        {
+          "content-type": "text/html; Charset=utf-8"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 19:29:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"01c35bc2fa3cd1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "content-length": "954"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "2008"
+        },
+        {
+          "expires": "Fri, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "x-radid": "P10723443-T100550693-C29000000000082620"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426988"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "27953"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 23:46:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=416068"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "42814"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 20:44:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache, no-store, must-revalidate"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "last-modified": "Mon, 18 Jul 2011 19:03:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "etag": "\"a29327667d45cc1:0\""
+        },
+        {
+          "server": "Microsoft-IIS/7.5"
+        },
+        {
+          "s": "VIEMSNVM001002"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "content-length": "42"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store, no-cache, private"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Sat, 15 Nov 2008 16:00:00 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.adnxs.com/w3c/policy/p3p.xml\", CP=\"NOI DSP COR ADM PSAo PSDo OURo SAMo UNRo OTRo BUS COM NAV DEM STA PRE\""
+        },
+        {
+          "x-xss-protection": "0"
+        },
+        {
+          "set-cookie": "anj=Kfu=8fG3H<cvjr/?0P(*AuB-u**g1:XIC8]Ei'/AQwFYO^vhHR3SSI7:0ssX1dl0I/A@=2rt>+)p4?5?fIu<PZksk:^@W+Nwgwmo%ACvi+5<.*N0Iu+9Y'W#w3TL$v$Kfc5PKO+; path=/; expires=Fri, 01-Feb-2013 13:30:05 GMT; domain=.adnxs.com; HttpOnly"
+        },
+        {
+          "content-type": "text/html; charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "content-length": "607"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "server": "Jetty(6.1.22)"
+        },
+        {
+          "set-cookie": "wfivefivec=8293faeb-8917-4006-95bc-2d52d4cd2f6d;Path=/;Domain=.w55c.net;Expires=Mon, 03-Nov-14 13:30:06 GMT"
+        },
+        {
+          "p3p": "policyref=\"https://cts.w55c.net/ct/p3p_policy_ref.xml\", CP=\"UNI PUR COM INT STA OTC STP OUR CUR TAIo COR DSP NOI\""
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "x-powered-by": "Mirror Image Internet"
+        },
+        {
+          "content-length": "42"
+        },
+        {
+          "via": "1.1 ttn061005 (MII-APC/2.2)"
+        },
+        {
+          "keep-alive": "timeout=2"
+        },
+        {
+          "connection": "Keep-Alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-store"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "0"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-msadid": "300089440.299934848"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-length": "511"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/json; charset=utf-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:05 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Mon, 01 Jan 1990 00:00:00 GMT"
+        },
+        {
+          "cache-control": "private, no-cache, no-cache=Set-Cookie, no-store, proxy-revalidate"
+        },
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=418020"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "41311"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 21:17:13 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426681"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "47495"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 23:41:34 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431985"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA08"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA08"
+        },
+        {
+          "content-length": "26998"
+        },
+        {
+          "age": "385360"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:27:11 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431851"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA06"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA06"
+        },
+        {
+          "content-length": "27541"
+        },
+        {
+          "age": "327876"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 18:23:01 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431570"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "40200"
+        },
+        {
+          "age": "303592"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 01:03:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426988"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "31967"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 23:46:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431525"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "45843"
+        },
+        {
+          "age": "303592"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 01:02:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=431595"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA07"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA07"
+        },
+        {
+          "content-length": "41590"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 01:03:28 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "public, must-revalidate, proxy-revalidate, max-age=426365"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "server": "CO1MPPSTCA05"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "p3p": "CP=\"BUS CUR CONo FIN IVDo ONL OUR PHY SAMo TELo\""
+        },
+        {
+          "s": "CO1MPPSTCA05"
+        },
+        {
+          "content-length": "46706"
+        },
+        {
+          "age": "303593"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:30:06 GMT"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 23:36:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_30.json b/jetty-http2/http2-hpack/src/test/resources/data/story_30.json
new file mode 100644
index 0000000..6ecb39d
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_30.json
@@ -0,0 +1,28257 @@
+{
+  "context": "response",
+  "cases": [
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:05 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "location": "http://www.nytimes.com/"
+        },
+        {
+          "content-length": "207"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=iso-8859-1"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:05 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:05 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 23:33:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1054"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=242"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:43:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "915"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=75412"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:35:58 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "563"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=75368"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:35:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 13:17:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "5433"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=71334"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:28:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2012 23:33:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11190"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=255"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:43:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:01:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "414"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=124"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 00:30:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1460"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=141"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "593"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=75423"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:36:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 00:30:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14014"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=181"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:42:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 13:32:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2864"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=71377"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:28:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 15:09:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1204"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=41140"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:04:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 14 Sep 2011 21:26:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1330"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=249513"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 10:57:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 28 Jun 2012 19:00:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1261"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=249513"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 10:57:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Mar 2012 17:13:25 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "33140"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=121"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:49:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "75"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348760"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:31:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "769"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=63729"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:21:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 24 Oct 2012 22:07:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2335"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=501801"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 09:02:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 05 Jun 2012 14:20:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5065"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=139006"
+        },
+        {
+          "expires": "Mon, 05 Nov 2012 04:15:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:30:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9619"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=449914"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 18:37:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:09:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9453"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=463322"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 22:21:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:05 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "RMID=007f010022166047bee9002b; Expires=Sun, 03 Nov 2013 13:39:05 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "set-cookie": "adxcs=-; path=/; domain=.nytimes.com"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "cteonnt-length": "174626"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 20:52:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "10651"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=548063"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 21:53:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 00:08:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9713"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=481042"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 03:16:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 21:58:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13397"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=50108"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:34:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 14:25:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10596"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=43276"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:40:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 21:58:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "857"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=50108"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:34:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:20:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "23526"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=60"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:26:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9473"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=551938"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 22:58:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5048"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=63748"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:21:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:49:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3428"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348719"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:31:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:24:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9374"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=550656"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 22:36:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 01:15:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9656"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=561534"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 01:38:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:27:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "10211"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=564327"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 02:24:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:03:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9722"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568295"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:30:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:51:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9372"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=555580"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 23:58:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 17:14:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "22786"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=559540"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 01:04:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 01:28:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9942"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=564328"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 02:24:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:54:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9364"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568578"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:35:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:09:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9404"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=578228"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:16:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:38:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10217"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=478523"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 02:34:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 01:19:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9052"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568307"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:30:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:00:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9379"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=553121"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 23:17:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:02:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9989"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=538058"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 19:06:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:36:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "10950"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=531474"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 17:17:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 16:22:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11381"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=529651"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 16:46:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 18:00:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10322"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=534703"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 18:10:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 17:11:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "22643"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=537513"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 18:57:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:59:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8617"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=459081"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 21:10:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:29:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10164"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=539911"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 19:37:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 05:22:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9476"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=488920"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 05:27:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:29:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9077"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=551868"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 22:56:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 17:43:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10600"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=540450"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 19:46:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 20:32:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9896"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=547139"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 21:38:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 15:09:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "572"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=41141"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:04:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Tue, 28 Apr 2009 18:18:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "404"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=41148"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:04:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 Sep 2012 11:12:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2845"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=63810"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:22:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 13 Sep 2012 16:49:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3246"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=64066"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:26:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:45:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "18527"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=51883"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "402"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=61804"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 06:49:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1108"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=33319"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:54:25 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:50:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "3113"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=250845"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:19:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "132"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=82000"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:25:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "130"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=44124"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:54:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 12:22:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2027"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=141"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5636"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39613"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:57:18 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9333"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592839"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:04:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "12380"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=574165"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:08:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:51:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "14526"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=574163"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:08:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 09:37:18 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "27338"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592839"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:21:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "17678"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=574163"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:08:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "15086"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "cache-control": "private, max-age=47723"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:54:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14119"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=38721"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:24:27 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 22:23:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15038"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=77030"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 11:02:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15051"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39616"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:52:36 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9914"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=574165"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:08:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:26:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "13388"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=574135"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:08:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:54:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=45924"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:24:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:06 GMT"
+        },
+        {
+          "content-length": "73046"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39601"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:15 GMT"
+        },
+        {
+          "content-length": "1713"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:26:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1246"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=45118"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:11:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9877"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39601"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:15 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "328"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=63772"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:22:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=0F8E3E619FFB422270FEEB659AA60437&e=i.1354338000&t=i.10&v=i.0&l=l.25.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.0.0.0.0&pr=l.4.1.0.0.0&vp=i.0&gf=l.10.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:16 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "114"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "424"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=81965"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:25:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "504"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=81965"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:25:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 25 Mar 2011 19:37:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "68"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=1088067"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 03:53:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 25 Mar 2011 19:37:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "3422"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=279280"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:13:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "368"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=82007"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:26:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39602"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "content-length": "8728"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:48:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7020"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39602"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:49:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "193"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349609"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 15:30:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "193"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349609"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 27 Feb 2010 03:33:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "192"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349609"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:49:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "192"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349609"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:50:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "35113"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:48:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "29467"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:51:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "16823"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "550"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=82007"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:26:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:52:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "16912"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:49:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "25024"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:49:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "24454"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:50:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "30450"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:51:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "19300"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=592829"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 10:19:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 12:34:42 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10032"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=536866"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 18:47:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:00:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9307"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=566721"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:04:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:58:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9354"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573743"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 05:01:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 08 Jun 2012 19:24:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "49"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349611"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "4654"
+        },
+        {
+          "set-cookie": "PRpc=|HwqgHD3W:1|HrYwHDG0:1|HrYvHDG1:2|#;domain=ads.pointroll.com; path=/; expires=Mon, 03-Nov-2014 13:39:17 GMT;"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "186"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=72083"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:40:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=45062"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:10:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=80765"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:05:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=45140"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:11:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "cache-control": "max-age=1200"
+        },
+        {
+          "etag": "\"4c3fb0afe8567a750ed2a0ea49e6944fba16bf00\""
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-served-by": "apiservices-a004.krxd.net"
+        },
+        {
+          "x-request-backend": "controltag"
+        },
+        {
+          "x-config-age": "400"
+        },
+        {
+          "x-cache-hits": "103"
+        },
+        {
+          "x-age": "377"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "content-length": "26341"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "64"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=49385"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:22:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 05 Oct 2012 17:38:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2153"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=35030"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 23:23:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "159"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "5623"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=82032"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:26:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:16 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Tue, 01 Mar 2011 22:54:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2078"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=279283"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:14:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "593"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=279282"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:14:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1062"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=279282"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:14:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "830"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=279285"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:14:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 14 Nov 2011 19:12:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1230"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=310332"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 03:51:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=49385"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:22:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "319"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=279282"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 19:14:00 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:18 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "content-length": "65"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1968"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39604"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs37lVrcF5/ZLq6rynLbPIrYKIQNSvBay5eXmklcaqTTiLoOeuQVXo/ErioUh8fUwMfecUglqHQguFB4PZbqjfC/R139oOkeO9km0JPhPmAlXHZdbK2WUEIbFJNiFPRmQDogdoIloef2Ff8AdiQTdLWj97qwBkClC8B/JlbaEoMNL360/5sp2oAT08Y; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:18 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas02-12"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39604"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-length": "11292"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "x-amz-id-2": "DlMsa95OAPS0ALn9DdiKGfdHovCM2TvJb0VQCd4x9FF44D35U9YbOWNnUKKYQL89"
+        },
+        {
+          "x-amz-request-id": "8987CB21B2CF98CC"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:20 GMT"
+        },
+        {
+          "cache-control": "max-age=10"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:35:29 GMT"
+        },
+        {
+          "etag": "\"8254326a395317db7b197564fa83e476\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": ""
+        },
+        {
+          "content-length": "92155"
+        },
+        {
+          "server": "AmazonS3"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39603"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "content-length": "645"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6174"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=39603"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 00:39:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "location": "/dcsa5pgfq10000c9zuysqk0lm_6i8y/dcs.gif?dcsredirect=126&dcstlh=0&dcstlv=0&dcsdat=1351949959619&dcssip=www.nytimes.com&dcsuri=/&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.vt_f_tlv=0&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=The%20New%20York%20Times%20-%20Breaking%20News,%20World%20News%20%26%20Multimedia&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/&WT.z_fbc=&WT.cg_n=Homepage&WT.z_rcgn=Homepage&WT.z_gpt=Homepage&WT.z_nyts=&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.rv=0&WT.mc_ev=&WT.vt_f_tlh=0&WT.vt_f_d=1&WT.vt_f_s=1&WT.vt_f_a=1&WT.vt_f=1"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAIcelVCHHpVQAQAAAHhHAACHHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAIcelVCHHpVQAQAAAHhHAACHHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:19 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 21:22:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "430"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=45030"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:09:49 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1103"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=82037"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:26:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1766"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=45133"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:11:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:19 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"15850e53f035443e5db6f28f75a9c1ac:1351623427\""
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 18:57:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=1200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "content-length": "17391"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "public, max-age=600"
+        },
+        {
+          "content-type": "text/javascript;charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:18 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:31:16 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BD8)"
+        },
+        {
+          "status": "200 OK"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "9879"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:22 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:39:22 GMT"
+        },
+        {
+          "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BF1)"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "35"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"f523ab9a498518867f12ca24f39ed087:1310577714\""
+        },
+        {
+          "last-modified": "Wed, 13 Jul 2011 17:10:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "cache-control": "max-age=1200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:21 GMT"
+        },
+        {
+          "content-length": "14202"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:24 GMT"
+        },
+        {
+          "etag": "\"894881535586350a54ec0f6e94779ee35c2169bd\""
+        },
+        {
+          "x-age": "0"
+        },
+        {
+          "x-cache": "MISS"
+        },
+        {
+          "x-cache-hits": "0"
+        },
+        {
+          "x-kuid": "IAJ5Qqdp"
+        },
+        {
+          "x-request-backend": "user_data"
+        },
+        {
+          "x-served-by": "apiservices-a002.krxd.net"
+        },
+        {
+          "content-length": "100"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:24 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:24 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=250 t=1351949964465812"
+        },
+        {
+          "x-served-by": "beacon-a002.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:25 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "public, max-age=604800"
+        },
+        {
+          "content-type": "text/css;charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:21 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 10:41:53 GMT"
+        },
+        {
+          "server": "ECS (lhr/4B9B)"
+        },
+        {
+          "status": "200 OK"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "54615"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "131"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=63879"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:24:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:28 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "130"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=41854"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:17:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:28 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAABAAAAmLwAAJEelVCHHpVQAQAAAHhHAACRHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:29 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "content-type": "text/plain"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "location": "http://www.nytimes.com/glogin?URI=http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&OQ=hpQ26_rQ3D0&OP=36bee93bQ2FQ27NgQ3FQ27zwQ3FQ27nnnQ27vQ3FoJQ27!N)ujNNQ3FQ2FQ27Q2FQ60Q22Q2FQ27Q22Q22Q27Q60Q20Q27TuQ27gSzzuwJEQ24zCQ240NoCQ3FQ3FS!0gNCuNz0!Q24Q3FQ240Cz0nQ24Q3FSj0jSgNjQ3FQ3AvQ3FoJ"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "302"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "set-cookie": "NYT-S=0MdTeGr8L1EDLDXrmvxADeHzL3eTxUhvw7deFz9JchiAIUFL2BEX5FWcV.Ynx4rkFI; expires=Mon, 03-Dec-2012 13:39:29 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "location": "http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html?hp&_r=0"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "495"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72064"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:40:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "539"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=30984"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:15:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "777"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70943"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "172"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=55043"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:56:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7026"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67908"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:31:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "set-cookie": "NYT-S=0MdTeGr8L1EDLDXrmvxADeHzL3eTxUhvw7deFz9JchiAIUFL2BEX5FWcV.Ynx4rkFI; expires=Mon, 03-Dec-2012 13:39:29 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "location": "http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html?hp&_r=0"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MTlTX5YhqzXfDXrmvxADeHBiKThPzJplXdeFz9JchiAJK89nlVaR7bsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "cteonnt-length": "61027"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3093"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71366"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:28:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5636"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71943"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:38:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2481"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70868"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:20:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 15 Oct 2012 20:38:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1241"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67395"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:22:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR PSAo PSDo OUR BUS OTC\""
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "x-aspnet-version": "2.0.50727"
+        },
+        {
+          "content-length": "1"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-type": "text/plain; charset=utf-8"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:11:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "568"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72065"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:40:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1307"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67397"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:22:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:48:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "47727"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=66869"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:13:58 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Sep 2012 20:20:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2093"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70944"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "693"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67422"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:23:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2045"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71899"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:37:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1052"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71981"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:39:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:11:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2466"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72115"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:41:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "885"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70944"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 10 Sep 2012 21:02:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3686"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67060"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:17:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "636"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72224"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:43:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "850"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70987"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:22:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1057"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70895"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:47:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1577"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70868"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:20:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "546"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71763"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:35:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MTlTX5YhqzXfDXrmvxADeHBiKThPzJplXdeFz9JchiAJK89nlVaR7bsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1911"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71744"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:35:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "648"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=66989"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:15:58 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MWfXncvqFxdbDXrmvxADeHBiKThPzJplXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "956"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=66847"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:13:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif"
+        },
+        {
+          "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\""
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 25 Mar 2011 19:37:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1110"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=251474"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "525"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70973"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:22:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=66881"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1766"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=63849"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:23:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "864"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72341"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:45:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5039"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=66914"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 22:21:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "561"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70935"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 26 Apr 2012 15:13:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8381"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=351783"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:22:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 04 Nov 2010 16:47:55 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1896"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=51812"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Sep 2012 18:13:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5551"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=71858"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:37:07 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 01:19:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15650"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571282"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:20:51 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 22:23:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "22905"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=51812"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1713"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70944"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 11 Sep 2009 17:35:00 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "69"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=72168"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:42:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 30 May 2012 16:54:32 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13402"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=18685"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 18:50:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8728"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67350"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:21:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "656"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67439"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:23:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5248"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70974"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:22:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1103"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70946"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "YvVdaXFdQYBoLiHhS/Pvn3QQnQ4PguJp3trhCHZSnIIo5NT7S98Tdyovty62vHSG"
+        },
+        {
+          "x-amz-request-id": "CD0C61042E9125AE"
+        },
+        {
+          "date": "Thu, 05 Jul 2012 20:17:51 GMT"
+        },
+        {
+          "cache-control": "max-age=600000"
+        },
+        {
+          "last-modified": "Wed, 28 Sep 2011 20:00:18 GMT"
+        },
+        {
+          "etag": "\"df3e567d6f16d040326c7a0ea29a4f41\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "64616"
+        },
+        {
+          "x-amz-cf-id": "oorNbpV0j8hpPM9RfynFxe0GrjwY7QWan8Mzs8SdZ-6uuC5_pgLgZA=="
+        },
+        {
+          "via": "1.0 2cfcdac9b945cce88c21cc3f30d884cd.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "126"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67490"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:24:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=8F26281382200A491A2301632AB3A6B8&e=i.1354338000&t=i.10&v=i.1&l=l.25.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.1.0.0.0&pr=l.4.2.0.0.0&vp=i.0&gf=l.10.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:29 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 16 Oct 2012 21:00:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5399"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=66914"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1401"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71732"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:35:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 02 Mar 2011 21:46:12 GMT"
+        },
+        {
+          "etag": "\"195-49d86d768f100\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-host": "b103 D=2883"
+        },
+        {
+          "keep-alive": "timeout=120, max=990"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "age": "93     "
+        },
+        {
+          "content-length": "405"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3831"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71853"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:37:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:26:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1246"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70966"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:22:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "37497"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=72227"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:43:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9877"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70946"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "424"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71023"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "268"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67682"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:27:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "873"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70936"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:11:33 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "368"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71023"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3481"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71854"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:37:03 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "550"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70868"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:20:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=51842"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "content-length": "9458"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2328"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=51833"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2619"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=51842"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "129"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=51812"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:03:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "35"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=42508"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:27:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "68"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=69239"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:53:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=71028"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1147"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=66888"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:29 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 01 Mar 2011 22:54:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2078"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=251463"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "593"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=251463"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1062"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=251463"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "830"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=251463"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "46"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=65132"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:45:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 03 Mar 2011 19:32:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "319"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=251463"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:30:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 25 Mar 2011 19:37:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "68"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=1148040"
+        },
+        {
+          "expires": "Fri, 16 Nov 2012 20:33:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "89"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "99"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "522"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "5623"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 22:51:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5799"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=351376"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:15:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 10:59:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9147"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=336431"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 11:06:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 17:13:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9389"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=445021"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 17:16:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 11 Oct 2012 22:48:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5801"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=349648"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:46:58 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 04:10:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9726"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=402546"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 05:28:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:47:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8968"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568247"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:30:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "2160"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "384"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=66991"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:16:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3710"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71770"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:35:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1435"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=72025"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:39:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "193"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=66872"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11292"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67441"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:23:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1968"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=70895"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:05 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:30 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "645"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67389"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:22:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6174"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=63855"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:23:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1008"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 20:14:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "nncoection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "451"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "location": "/dcsypfq3j00000gsclwfljaeo_6i3w/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351949970618&dcssip=www.nytimes.com&dcsuri=/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&dcsqry=%3Fhp%26_r=0&dcsref=http://www.nytimes.com/&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=Pennsylvania%20Omitted%20Poison%20Data%20in%20Water%20Report%20-%20NYTimes.com&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html&WT.z_cad=1&WT.z_fbc=0&WT.cg_n=U.S.&WT.z_rcgn=U.S.&WT.z_gpt=Article&WT.z_gpst=News&WT.cre=The%20New%20York%20Times&WT.z_nyts=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.z_hdl=Pennsylvania%20Omitted%20Poison%20Data%20in%20Water%20Report&WT.z_aid=nyta-100000001882561&WT.z_pud=20121102&WT.z_put=Archive&WT.z.gsg=Archive&WT.z_gat=1987-Present&WT.z_pua=free&WT.z_clmst=JON%20HURDLE&WT.z_puv=Normal&WT.z_pudr=1%20Day&WT.z_pyr=2012&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351949969&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f="
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAACAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQAQAAAHhHAACSHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs3719rcF5/JLq6ryuLbPLJXeyC9jZZv+I7SU4qR++R9DDoNb/ysNCSXuwJ979WKhzt9zeOAxNfu6nTWtMntzlCge0zMN6tn5CjIsSTK5oUfaLnJaYMq4VYwS5vxNRs6EHC1nNdLw29SQ2GQ1OzYMBqy0e3FBBr8pVvZLpT4SSw1y6vIpitypkpC3SUacb3M5M=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:30 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas09-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "684"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAACAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQAQAAAHhHAACSHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:30 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 21:22:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "430"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=67493"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:24:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2791"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=547136"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 21:38:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 21:27:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1103"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=43733"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:48:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1330"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=72392"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:46:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1261"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=72392"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:46:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1687"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=67920"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:31:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=67981"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:32:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 16:21:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1029"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=72522"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:48:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 17 Jul 2012 16:21:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "108"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=70940"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "73"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=67925"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:31:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "max-age=604800, private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1211"
+        },
+        {
+          "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "684"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 20:42:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10779"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=66917"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:14:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 12:45:53 GMT"
+        },
+        {
+          "server": "safe"
+        },
+        {
+          "cache-control": "public, max-age=3600"
+        },
+        {
+          "content-length": "141"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-type": "application/ocsp-response"
+        },
+        {
+          "content-length": "1330"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:30 GMT"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "access-control-allow-origin": "*"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "x-fb-debug": "viBL2OtZRmc+1Eqe26sXit4heGPBgfLwrdCHHhHx73Y="
+        },
+        {
+          "content-length": "1916"
+        },
+        {
+          "cache-control": "public, max-age=25750987"
+        },
+        {
+          "expires": "Wed, 28 Aug 2013 14:42:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:31 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=263 t=1351949971765301"
+        },
+        {
+          "x-served-by": "beacon-a006.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=1800"
+        },
+        {
+          "content-type": "text/javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "etag": "\"ad69b1e55307637e8f511c3651fe4a796330656f\""
+        },
+        {
+          "x-age": "0"
+        },
+        {
+          "x-cache": "MISS"
+        },
+        {
+          "x-cache-hits": "0"
+        },
+        {
+          "x-kuid": "IAJ5QtWI"
+        },
+        {
+          "x-request-backend": "user_data"
+        },
+        {
+          "x-served-by": "apiservices-a002.krxd.net"
+        },
+        {
+          "content-length": "117"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "set-cookie": "NYT-S=0MSC2NhKvY9wzDXrmvxADeHz0Rn194VZRXdeFz9JchiAJYOVLIKocjgsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "684"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-length": "1406"
+        },
+        {
+          "last-modified": "Fri, 03 Aug 2012 23:51:15 GMT"
+        },
+        {
+          "etag": "\"57e-501c63f3\""
+        },
+        {
+          "accept-ranges": "bytes"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 11:36:59 GMT"
+        },
+        {
+          "etag": "\"30-4cd95ab8fecc0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-host": "b205 D=2031"
+        },
+        {
+          "keep-alive": "timeout=120, max=972"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "age": "161    "
+        },
+        {
+          "content-length": "48"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:30:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5873"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=419"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:46:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 15 Jul 2010 17:33:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "583"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=251500"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:31:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2007 19:58:55 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "79"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=251499"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 11:31:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:32 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "etag": "\"d04742eb975012ec5e5aecce3effd7ce:1350417145\""
+        },
+        {
+          "last-modified": "Tue, 25 Sep 2012 18:41:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:31 GMT"
+        },
+        {
+          "content-length": "3167"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:32 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "235"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=50212"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:36:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:12:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "402"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70900"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:20 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1108"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=45394"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 02:16:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "content-type": "image/x-icon"
+        },
+        {
+          "set-cookie": "NYT-S=0MuwkWjSilDpbDXrmvxADeHGJBFC9b9qDRdeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "684"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 19:11:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=86400, private"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-length": "1406"
+        },
+        {
+          "last-modified": "Fri, 03 Aug 2012 23:51:15 GMT"
+        },
+        {
+          "etag": "\"57e-501c63f3\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "ntcoent-length": "142315"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:20:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2017"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64909"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:41:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 21:20:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1687"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=43"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 13:51:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9372"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=519781"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 14:02:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 18:59:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "21158"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=451415"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 19:03:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 02:58:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9420"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=480982"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 03:16:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 24 May 2012 19:30:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1217"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=31"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:11 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 17 May 2012 20:43:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "586"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=57"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 21:20:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17724"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=44"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "586"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=70933"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:24 GMT"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "max-age=604800, private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1211"
+        },
+        {
+          "last-modified": "Wed, 14 Mar 2012 16:16:16 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "593"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=72068"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:40:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "380"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=76028"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:46:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1435"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=67567"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:25:47 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 10:03:09 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6703"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568282"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:31:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 15:35:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10892"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 00:21:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9029"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 16:05:06 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10524"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568298"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:31:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2045"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71054"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "416"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71053"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:05:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "31084"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "402"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=71054"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:23:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 20 May 2011 16:30:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9829"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:14:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "526"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=50213"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:49:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "67"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=217288"
+        },
+        {
+          "expires": "Tue, 06 Nov 2012 02:01:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 21 Apr 2010 19:31:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "507"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=307895"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 03:11:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 21 Apr 2010 19:31:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1578"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=358516"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 17:14:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 03 Mar 2010 22:58:31 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1927"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=601439"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 12:43:39 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:39:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "10726"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568482"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:34:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 23 Oct 2012 05:20:00 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9316"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 28 Dec 2006 14:20:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "183"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349196"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:39:36 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 04:24:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13748"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 10:40:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8817"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Fri, 14 Mar 2008 23:03:40 GMT"
+        },
+        {
+          "etag": "\"19f-4486dae50ab00\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-host": "b203 D=1778"
+        },
+        {
+          "keep-alive": "timeout=120, max=997"
+        },
+        {
+          "content-type": "application/javascript"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "age": "43     "
+        },
+        {
+          "content-length": "415"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=65755B60FD3DAC5F62160A7CED54655D&e=i.1354338000&t=i.10&v=i.1&l=l.25.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.1.0.0.0&pr=l.4.3.0.0.0&vp=i.0&gf=l.10.2802408197.-1.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:40 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "114"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:28:25 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8578"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 29 Oct 2012 18:53:28 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "40163"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 00:59:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "31146"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=582958"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 07:35:38 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 22 Oct 2012 17:24:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "16403"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 27 Oct 2012 18:43:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11670"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=308055"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 03:13:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 28 Apr 2010 14:36:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "987"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=568614"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 28 Apr 2010 14:36:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2533"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=568614"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 16:22:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14479"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568614"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 09 Apr 2012 21:40:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14215"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568614"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 11 Dec 2008 21:32:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "2981"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=568614"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 17:09:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13040"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=43242"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:40:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 28 Apr 2009 18:18:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "441"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=43242"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 01:40:22 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 21:41:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14372"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=54908"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:54:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 01 Apr 2009 23:28:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1305"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=30976"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 22:15:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 20 Mar 2012 16:46:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "16641"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=76250"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:50:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "public, max-age=600"
+        },
+        {
+          "content-type": "text/javascript;charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:40 GMT"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:32:42 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BB6)"
+        },
+        {
+          "status": "200 OK"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "9160"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "64"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=70518"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:14:59 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:15:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2092"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 23 Sep 2011 19:12:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1453"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=47"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:40:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "119"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=65032"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:43:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1261"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=65032"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:43:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=70571"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:15:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:14:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=70936"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:21:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 28 Aug 2012 21:17:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "880"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64971"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4164"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=76141"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:48:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "230"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64971"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2404"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64971"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "5136"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64867"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:40:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "29137"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64954"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5752"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64971"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "723"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=76141"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:48:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "ALT_ID=007f010046a161bb587e0031; Expires=Sun, 03 Nov 2013 13:39:30 GMT; Path=/; Domain=.nytimes.com;"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "586"
+        },
+        {
+          "last-modified": "Thu, 06 Dec 2007 12:15:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "etag": "\"14f8931-69a-4409d16c699c0\""
+        },
+        {
+          "cteonnt-length": "1690"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:50:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "170"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348768"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:32:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:50:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "106"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348768"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:32:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 14 May 2010 14:50:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "3113"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348768"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:32:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2303"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=64971"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "16036"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64972"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 31 Aug 2010 02:21:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "783"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=64970"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Jan 2011 01:28:46 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1930"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT"
+        },
+        {
+          "etag": "\"1506ccd-181-46d1d28b0d7c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cteonnt-length": "385"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "233"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1875"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1313"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64974"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:35 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "956"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=65049"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:43:50 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 24 Apr 2012 15:30:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7711"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 23 Jun 2011 19:37:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8232"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Tue, 28 Feb 2012 20:00:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "8082"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 23 Jun 2011 20:05:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8047"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 16 Mar 2012 15:04:36 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8295"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs37yNvMF5jo9YXjSnP7LCTHV9qwwoXglYNnSgoXY6BgbxUe/dD4KFNMYHqMNEyxe2rbNMTaq4ZLc54Mwg8CSJxvNnh/ajkRBOJfEPCwjrLmcL1OEvcVlVd6ZL/LHB0ixoNHfgWDborMHCUfZtXPvcBFlRNv7qTCM+wn7NY4LUipF+V+epFmBpnIArrjDPO; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:41 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas12-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:16:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8374"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "location": "/dcsaon9rw0000008ifmgqtaeo_2f9c/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351949981735&dcssip=www.nytimes.com&dcsuri=/pages/science/index.html&dcsref=http://www.nytimes.com/2012/11/03/us/pennsylvania-omitted-poison-data-in-water-report.html%3Fhp%26_r=0&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=Science%20News%20-%20The%20New%20York%20Times&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/pages/science/index.html&WT.cg_n=Science&WT.z_rcgn=Science&WT.z_gpt=Section%20Front&WT.z_nyts=0MlRvbBBJvPrbDXrmvxADeHGBFC0o.wGyedeFz9JchiAKuaKkdl/6loIV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351949981&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f="
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACdHpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 08 Sep 2011 15:52:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8274"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:21:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8001"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Mon, 04 Apr 2011 17:44:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "8310"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568612"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 13 Mar 2012 15:48:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8162"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 19:24:18 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8410"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 19:26:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8253"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 30 Mar 2011 20:20:51 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8372"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 19:25:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8030"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT"
+        },
+        {
+          "etag": "\"1506ccd-181-46d1d28b0d7c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cteonnt-length": "385"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "ntcoent-length": "62"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 09 Mar 2012 18:41:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "8093"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:31:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8036"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 14 Mar 2012 19:42:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8124"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:33:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8207"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:36:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8363"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 29 Mar 2011 21:41:44 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8151"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568613"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:36:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAJIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACdHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:41 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 17 Mar 2010 16:56:32 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "20"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private, max-age=64931"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:41:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BF1)"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "35"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "public, max-age=604800"
+        },
+        {
+          "content-type": "text/css;charset=utf-8"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:41 GMT"
+        },
+        {
+          "last-modified": "Sun, 28 Oct 2012 04:22:00 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BB5)"
+        },
+        {
+          "status": "200 OK"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "136727"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:43 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:43 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=245 t=1351949983602996"
+        },
+        {
+          "x-served-by": "beacon-a006.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:43 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 21 Aug 2012 20:06:02 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1780"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=72048"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:40:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "511"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=72077"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:41:02 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 16:29:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "6000"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571763"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:29:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 16:26:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "6454"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571763"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:29:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0Ma.K9EWB.dlLDXrmvxADeHD./oTk5S0O8deFz9JchiAImJkOx2rgxzsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "ntcoent-length": "64765"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 17:02:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8653"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571763"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:29:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "21379"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=71749"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:35:34 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 14:47:21 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15456"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571763"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:29:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 14:29:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "49747"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571763"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:29:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 20:15:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3168"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=72146"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:42:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 14 Jun 2012 20:14:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10547"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=49875"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:31:01 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        },
+        {
+          "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif"
+        },
+        {
+          "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\""
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=39895E64FA29A782E08DBEA5DC0005A0&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.4.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:46 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "ntcoent-length": "50"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-amz-id-2": "YvVdaXFdQYBoLiHhS/Pvn3QQnQ4PguJp3trhCHZSnIIo5NT7S98Tdyovty62vHSG"
+        },
+        {
+          "x-amz-request-id": "CD0C61042E9125AE"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "cache-control": "max-age=600000"
+        },
+        {
+          "last-modified": "Wed, 28 Sep 2011 20:00:18 GMT"
+        },
+        {
+          "etag": "\"df3e567d6f16d040326c7a0ea29a4f41\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "server": "AmazonS3"
+        },
+        {
+          "age": "64633"
+        },
+        {
+          "x-amz-cf-id": "kbjTp1EH_MixUnZ7pqHXKi1pQZ7tCItHqSP2iVMrIwMt36MEvhC5bQ=="
+        },
+        {
+          "via": "1.0 2cfcdac9b945cce88c21cc3f30d884cd.cloudfront.net (CloudFront)"
+        },
+        {
+          "x-cache": "Hit from cloudfront"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "993"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MKyyIqtYtFvnDXrmvxADeHJm9OXN6YxpedeFz9JchiAIrvq48TSAR4YV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "cteonnt-length": "1220"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "767"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "522"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "59"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MrbR7PgLIdPLDXrmvxADeHJm9OXN6YxpedeFz9JchiAIa2oeaXI7u7sV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1071"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:46 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:45 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs3MVVvMC5/TPbCQtB9rewZ4ac3sWtlL/To9pTTnVflQ7/pHvfl9TutghgWq8BWX5hkGMxwV0G2TYPnu7UrqddmXeJqDHsu7UtpznAhQDBIXp76SiJpTi8Xt/SyOHvyVjspIxogIORYGOkXT50L77u7Afv+N5dTX/mGL4zVQJ5xgVd7PhAxSnfU7wMqMA10uXsSVCgB; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:46 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas14-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "67"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=75225"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:33:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAADAAAAmLwAAJEelVCHHpVQ9r0AAKIelVCSHpVQ+r0AAJ0elVCdHpVQAQAAAHhHAACiHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:39:46 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:46 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "421"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MCYDgCh5sLPnDXrmvxADeHJm9OXN6YxpedeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "611"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "677"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1270"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=65537"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:52:04 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 01 Oct 2012 22:20:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "850"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=82550"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 12:35:37 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2007 19:58:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "78"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=343858"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 13:10:45 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 25 Jun 2012 18:51:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "193"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348897"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:47 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=261 t=1351949987674149"
+        },
+        {
+          "x-served-by": "beacon-a002.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:47 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 25 Jun 2012 18:51:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "195"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348898"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:48 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:48 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 17 Nov 2011 21:55:54 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1439"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348897"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 27 Sep 2011 18:42:47 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "120"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348920"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:35:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 17 Nov 2010 22:08:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "79"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=348893"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 17 Nov 2010 22:08:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "444"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348893"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "314"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=69564"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:59:13 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:49 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "x-amz-id-2": "ceFRS1NFRp8F1PuWGjAzR4CMD8nHMNrIGG1K803RtQWtRwA6ZZIyFDi3hvyD0rEU"
+        },
+        {
+          "x-amz-request-id": "1F4B6B1CFD329F7B"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:50 GMT"
+        },
+        {
+          "last-modified": "Mon, 20 Aug 2012 08:07:13 GMT"
+        },
+        {
+          "etag": "\"327b3e51a98ec9a7794030292d94bfdd\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "content-length": "2329"
+        },
+        {
+          "server": "AmazonS3"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 11 Nov 2011 21:24:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "992"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=348902"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:34:52 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:50 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MPfF5c8nIM93DXrmvxADeHz.PZL72gaixdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 20:18:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4913"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=75470"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:37:42 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 25 Oct 2012 15:40:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9921"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=62694"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:04:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "59"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MVMayrSvblfnDXrmvxADeHz.PZL72gaixdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "45"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:38:56 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MrRmN0I2VxMLDXrmvxADeHx2AlW/TY.ZkdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:52 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=484D5CE2EC7396EB483BD34967CEFAEA&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.5.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:52 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1064"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 20:48:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "cache-control": "public, max-age=0"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "175"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 09:47:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "cache-control": "public, max-age=0"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "846"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M3MAhi1As7rzDXrmvxADeHIS37KQvQCBqdeFz9JchiAI32QSUxrnkuIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:53 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1015"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs38VNrMF5/o7ZYjynLbLK61Fp4LCE4qYA8/Pkh6qaTfl607NSARhRSu/Fzrhux2ZemT7dtNzdkLuaRJQuxoxMjsTLW4MWkvPvMQEm63fgskbXcOyhmIGhAp8smwaMCPqeCAzEoxoL8g46HoNIA8DP6t0XbPL6ADv/liREWAhRB2zl4cdzIiQpdChU6FSzIgUundpLxZgo=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:53 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas07-3"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:53 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "674"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:54 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:54 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=261 t=1351949994087668"
+        },
+        {
+          "x-served-by": "beacon-a006.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:54 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:55 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MsUPd65dnaE7DXrmvxADeHIS37KQvQCBqdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 19 Sep 2012 14:55:07 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9556"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=18600"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 18:49:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=BB78456D636A55DD29717BF2DF3A713D&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.6.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:39:57 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "674"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1086"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "522"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "982"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "last-modified": "Thu, 12 Apr 2012 20:48:26 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "cache-control": "public, max-age=0"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "175"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs38VVrcF5/ZLq6rynLbPIrDNNqLmAVAjAcmlywO48hlDb+EIf12DpSuoFj6R+qKjtBkmg2hwh475ZyhKkLcXnOHD8snyDB8tqBczw0L+1ELClDEhhnAWZEtcBDLaM8gpIzDffofr8PXgb4mdcdsGQEwxlXd7J5w1a+LaHURhUo7KSjHyswVRH8QuXMXjpbXabRMAqNp3YYzXPS12ub; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:39:57 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas11-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "421"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MQAEyqJ3kflHDXrmvxADeHFvzcPY0HhncdeFz9JchiAIul1FwAbE3OsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "611"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:39:57 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:58 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "674"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:58 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "last-modified": "Mon, 27 Aug 2012 09:47:24 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:39:57 GMT"
+        },
+        {
+          "cache-control": "public, max-age=0"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "server": "sffe"
+        },
+        {
+          "content-length": "846"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:58 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:58 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:39:58 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=258 t=1351949998446073"
+        },
+        {
+          "x-served-by": "beacon-a006.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:39:58 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:00 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MzziEIMyxqcHDXrmvxADeHFvzcPY0HhncdeFz9JchiALEJMkToPY7aYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "1625"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "ntcoent-length": "59049"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "59"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MMbUZRWJFzCHDXrmvxADeHKjc4hKLrMXGdeFz9JchiALVSSvxGfo9IYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=A04BB1C6D05156CDD246EFA62A7CC3A3&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.7.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:03 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1065"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "vary": "Host"
+        },
+        {
+          "cteonnt-length": "1240"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "777"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "522"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1013"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs37lNrMF5/o7ZYjynLbLK6rQEBceRsik1IRXIEfZYJjiQapJzwsXeZjT0U5HMKHV3mXKvvaQ4FLg4p3hY87Lr+QiD9QLBuC5Vhn49p+QQ/emsZO26pJ7Jdh6OeXLf4hds9p5K2fB19Ja95VikymGQrDgRB3gOb5zehMs2tUQJAktvEjgSgsPeIBsEg8ddP/NbMOovVC1aBKj+1; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:03 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd3-bgas14-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:40:03 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:03 GMT"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "674"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1628"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:04 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=274 t=1351950004445628"
+        },
+        {
+          "x-served-by": "beacon-a006.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:48:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3699"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=79"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:23 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:04 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:05 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1628"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M0SovqlRxK8PDXrmvxADeHKjc4hKLrMXGdeFz9JchiAI7clrZeQfNdsV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:14 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1397"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=55146"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:59:15 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "ntcoent-length": "135910"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1628"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MZmF2WzRIAizDXrmvxADeHI4U72bYMorSdeFz9JchiALVSSvxGfo9IYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "vary": "Host"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Sep 2012 20:00:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1566"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=202"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:43:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:21:37 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "9333"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=564467"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 02:27:56 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 17:00:35 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8948"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=530746"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 17:05:55 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1276"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=64897"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:41:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Mon, 17 Sep 2012 20:00:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "19737"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=202"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:43:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "248"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64919"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "921"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=20124"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 19:15:33 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:10:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10427"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=571269"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:21:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "59"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0Ma.K9EWB.dlLDXrmvxADeHI4U72bYMorSdeFz9JchiALJvjis/thrUYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:54:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "33089"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573548"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:13:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "8950"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=559591"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 01:06:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:18:13 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "431"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/css"
+        },
+        {
+          "cache-control": "private, max-age=64941"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:30 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Mar 2012 17:13:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "52128"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=97"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:41:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 06:54:58 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10027"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=580777"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:59:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 03:35:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9303"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573129"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:52:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 00:50:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10045"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=559835"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 01:10:44 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:02:10 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "10110"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=552339"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 23:05:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:40:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9118"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=568308"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 03:31:57 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 02 Oct 2007 16:06:30 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "3308"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=573548"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 22:25:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14634"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:22:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14341"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:50:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "16624"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=361320"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 18:02:09 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=918B6703052398FA5C152AAC782FA51F&e=i.1354338000&t=i.10&v=i.2&l=l.25.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.2.0.0.0&pr=l.4.8.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.-1.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:09 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "114"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 30 Oct 2012 22:51:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15006"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 20:07:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "51622"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=369068"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 20:11:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 02:55:22 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "19143"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=394445"
+        },
+        {
+          "expires": "Thu, 08 Nov 2012 03:14:14 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 23:23:53 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "9474"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=553714"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 23:28:43 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:48:38 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8030"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573439"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:57:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 20 Jun 2012 14:59:39 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "10115"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 20 Aug 2009 21:16:01 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2105"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=351563"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:19:32 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 04:00:27 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "35977"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Tue, 27 Apr 2010 17:46:57 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "1787"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=349039"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:37:28 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 14 Oct 2011 20:04:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "8189"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573550"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 17 Jun 2011 13:57:26 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2824"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573550"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 15 Nov 2011 19:33:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11967"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573550"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 10 Jun 2011 13:57:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2404"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573152"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:52:41 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 02 Jun 2011 21:47:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17489"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=352377"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:33:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Tue, 31 Jul 2012 15:09:43 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "7708"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573550"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 23 Mar 2007 20:45:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "4035"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573550"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:19 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 03 Jun 2010 13:02:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1660"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=352377"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 15:33:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 21 Jun 2012 18:52:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "11884"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=75841"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:44:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 31 Oct 2012 21:41:52 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "17667"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=50037"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 03:34:06 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 05 Jul 2012 20:15:36 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2092"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT"
+        },
+        {
+          "etag": "\"1506ccd-181-46d1d28b0d7c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cteonnt-length": "385"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "233"
+        },
+        {
+          "ntcoent-length": "62"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 13 Jan 2011 15:17:04 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1870"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=86400"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Wed, 24 Jun 2009 19:31:51 GMT"
+        },
+        {
+          "etag": "\"1506ccd-181-46d1d28b0d7c0\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cteonnt-length": "385"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "74"
+        },
+        {
+          "ntcoent-length": "62"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1866"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=604800"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 13:40:10 GMT"
+        },
+        {
+          "last-modified": "Tue, 31 Jul 2012 23:02:57 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BF1)"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "35"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Thu, 15 Dec 2011 19:05:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=52304"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 04:11:53 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:09 GMT"
+        },
+        {
+          "content-length": "42039"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:14:45 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "66"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=71036"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 09:24:08 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "247"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64954"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:46 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:05 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2289"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64924"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 04 Aug 2012 21:19:03 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "2443"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=64924"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 07:42:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "vary": "Cookie"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:38:24 +0000"
+        },
+        {
+          "cache-control": "max-age=132, must-revalidate"
+        },
+        {
+          "keep-alive": "timeout=60, max=940"
+        },
+        {
+          "connection": "Keep-Alive"
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "188"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=349116"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:38:48 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "106"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=349122"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:38:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 18 Mar 2009 18:50:08 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "131"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=349122"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:38:54 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 09 Sep 2009 16:10:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "351"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=349157"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:39:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Wed, 09 Sep 2009 16:10:20 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "224"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "cache-control": "private, max-age=349157"
+        },
+        {
+          "expires": "Wed, 07 Nov 2012 14:39:29 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "872"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs38FVrcF5/ZLq6rynLbPIrzBMgf6gCZEFYbnEyqJwHBZC0garfrvMOIs+B939ykqVLVck4XSTGQIMvPdVthDcyttnh/a+rfKsxItpUfG2D5pA4KGuH2gGpHenDN3B0M6eEi6BWcidf0I+ZlqmL9bIpDHIKu64kT0YghPKjDoejnlzus5jQeqqP4igBfBMSRX3hgEHkgrccVaMsrutxL45k8Cggfg==; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:12 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd4-bgas03-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:08:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "18011"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "location": "/dcsj5tb4n100000sl76culaeo_4f3w/dcs.gif?dcsredirect=112&dcstlh=0&dcstlv=0&dcsdat=1351950012922&dcssip=www.nytimes.com&dcsuri=/pages/nyregion/index.html&dcsref=http://www.nytimes.com/2012/11/04/education/edlife/a-new-kind-of-tutoring-aims-to-make-students-smarter.html%3Fpagewanted=4%26ref=science&WT.co_f=130.129.68.73-2680109824.30259656&WT.vt_sid=130.129.68.73-2680109824.30259656.1351949959620&WT.tz=-4&WT.bh=9&WT.ul=en-US&WT.cd=24&WT.sr=1366x768&WT.jo=Yes&WT.ti=New%20York%20Region%20News%20-%20The%20New%20York%20Times&WT.js=Yes&WT.jv=1.7&WT.ct=unknown&WT.bs=994x649&WT.fi=No&WT.tv=1.0.7&WT.dl=0&WT.es=www.nytimes.com/pages/nyregion/index.html&WT.cg_n=N.Y./Region&WT.z_rcgn=N.Y./Region&WT.z_gpt=Section%20Front&WT.z_nyts=0Ma.K9EWB.dlLDXrmvxADeHI4U72bYMorSdeFz9JchiALJvjis/thrUYV.Ynx4rkFI&WT.z_nytd=&WT.z_rmid=007f010022166047bee9002b&WT.z_ref=nytimes.com&WT.rv=0&WT.mc_ev=&WT.vt_f_tlv=&WT.vt_f_tlh=1351950010&WT.vt_f_d=&WT.vt_f_s=&WT.vt_f_a=&WT.vt_f="
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AALwelVC8HpVQAQAAAHhHAAC8HpVQhx6VUAAAAAA-; path=/; expires=Thu, 10-Dec-2015 10:27:34 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:06:34 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "25015"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 03:06:11 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "25206"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=573549"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 04:59:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "304"
+        },
+        {
+          "x-amz-id-2": "d90CCR9lSoaaNwupUMIdb/ey0mevoBrnI3ZRtI8HHFRBEUtsLjtNMBWb2X6DprZz"
+        },
+        {
+          "x-amz-request-id": "D6FC61A73C17CF70"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:14 GMT"
+        },
+        {
+          "cache-control": "max-age=10"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 13:35:29 GMT"
+        },
+        {
+          "etag": "\"8254326a395317db7b197564fa83e476\""
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-type": ""
+        },
+        {
+          "content-length": "92155"
+        },
+        {
+          "server": "AmazonS3"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AAL0elVC8HpVQAQAAAHhHAAC9HpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:40:13 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 07:39:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=300"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:45:12 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:12 GMT"
+        },
+        {
+          "content-length": "4073"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/png"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"fb5af56cb67780c01fb3516e7c3f74e3\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Wed, 04 Apr 2012 20:38:25 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BA4)"
+        },
+        {
+          "x-amz-id-2": "cBUUBPPZMto6skduFezdQ+9bNRCuwVjOvgFgohhb4PfZdlrYG33n3GM2BJ25YTtq"
+        },
+        {
+          "x-amz-request-id": "6758CF2C16F8B0C0"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "1662"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"0940a52ad7b3435f775918b80b088f27\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Thu, 30 Sep 2010 12:29:59 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BCC)"
+        },
+        {
+          "x-amz-id-2": "jDnDMjao+nUL4vfffUU3TFPTyN1KxJt9Dy6uCIra3CbwdS9wgqVrVK02Lhf++2Kk"
+        },
+        {
+          "x-amz-request-id": "296BB691837A53B5"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "980"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"7e3ff7f7848a81a63b6e2e0bfb394799\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Sun, 12 Jun 2011 15:43:21 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BA1)"
+        },
+        {
+          "x-amz-id-2": "QHLqCpOps7vUVMXN1QzHCNBpV3eM2RaV2CNFSW7QQ5BQSiaY2U04JVbdV76t6uPA"
+        },
+        {
+          "x-amz-request-id": "4E56272125A99862"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "2607"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"3ff974032fd77223fd059c6d234ebb43\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Tue, 14 Jun 2011 16:57:49 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BDF)"
+        },
+        {
+          "x-amz-id-2": "q0tabYbFY5+80zmAw4/5X92+LUMhsasmJRWZU8wZxF7S+TYVyMgxcBM47nT2KV2t"
+        },
+        {
+          "x-amz-request-id": "5C17C42AD2E36B99"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "3219"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"ac105110a13a3d24f2b5d502fb0db4e8\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Tue, 16 Jun 2009 22:22:00 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BAD)"
+        },
+        {
+          "x-amz-id-2": "AlVWqZvxNaFzFrxq+Lo/jRl878iwJzLMeSmnDalUQWo33DvFg3BUtTZnEF+yRJ5W"
+        },
+        {
+          "x-amz-request-id": "F6C83DE008C7DEFA"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "1673"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "cache-control": "max-age=31536000"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "etag": "\"6c157f6f56910c50a03faa81d54546bd\""
+        },
+        {
+          "expires": "Sun, 03 Nov 2013 13:40:13 GMT"
+        },
+        {
+          "last-modified": "Tue, 06 Sep 2011 20:24:40 GMT"
+        },
+        {
+          "server": "ECS (lhr/4BAC)"
+        },
+        {
+          "x-amz-id-2": "KFCqXFOHRJbWl2rZ7FfvRitLrhcAZnqUIfhUqkDIDZOQB0cgxkSjAlC9Qh0pOvZ3"
+        },
+        {
+          "x-amz-request-id": "8BF259D47606A786"
+        },
+        {
+          "x-cache": "HIT"
+        },
+        {
+          "content-length": "2437"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:13 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:13 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=271 t=1351950013983899"
+        },
+        {
+          "x-served-by": "beacon-a002.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:14 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:52:17 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15613"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=564661"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 02:31:18 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Tue, 03 Apr 2012 15:22:24 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "1955"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=299"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:45:16 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 02:54:40 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "14642"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:54:59 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "15613"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=547394"
+        },
+        {
+          "expires": "Fri, 09 Nov 2012 21:43:31 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MA4.kVz1KQmzDXrmvxADeHK.rUS.yFrOJdeFz9JchiALJvjis/thrUYV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "216"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/1.0.0"
+        },
+        {
+          "set-cookie": "nyt-m=8FF27B7C7E22BE437F4E72563691B5C2&e=i.1354338000&t=i.10&v=i.3&l=l.25.2802408197.2634689326.1254883451.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1.-1&n=i.2&g=i.0&er=i.1351949956&vr=l.4.3.0.0.0&pr=l.4.9.0.0.0&vp=i.0&gf=l.10.2802408197.2634689326.1254883451.-1.-1.-1.-1.-1.-1.-1; expires=Thu, 02-Nov-2017 13:40:17 GMT; path=/; domain=.nytimes.com"
+        },
+        {
+          "content-length": "113"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "cache-control": "max-age=0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:01 GMT"
+        },
+        {
+          "p3p": "CP=\"IDC DSP COR DEVa TAIa OUR BUS UNI\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "server": "nginx/0.7.59"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "303"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:16 GMT"
+        },
+        {
+          "location": "http://d1aivi5dp2wry5.cloudfront.net/pixel.gif"
+        },
+        {
+          "p3p": "CP=\"NOI PSAo OUR IND COM NAV STA\""
+        },
+        {
+          "server": "Microsoft-IIS/7.0"
+        },
+        {
+          "x-aspnet-version": "4.0.30319"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MP9kmlu11B5nDXrmvxADeHK.rUS.yFrOJdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "59"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "45"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "NYT-S=0MP9kmlu11B5nDXrmvxADeHK.rUS.yFrOJdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "ntcoent-length": "50"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:54:29 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "7020"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=76680"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 10:58:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:49:48 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "41440"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:50:15 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "53346"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:48:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "55860"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:49:19 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "46030"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:51:50 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "25431"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:52:12 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "27683"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:50:56 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "71084"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/html; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1966"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 05:51:23 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-length": "34384"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/jpeg"
+        },
+        {
+          "cache-control": "private, max-age=579064"
+        },
+        {
+          "expires": "Sat, 10 Nov 2012 06:31:21 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "1024"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "521"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0M6GemS05ruUDDXrmvxADeHAjAqSvifpeXdeFz9JchiAKfXJAEEJyUmIV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-length": "156"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MMaQ/2qmmFHvDXrmvxADeHAjAqSvifpeXdeFz9JchiAIcUoUNnYFX3YV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cteonnt-length": "45"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "content-length": "59"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "nginx/1.0.10"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "p3p": "policyref=\"http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml\", CP=\"CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
+        },
+        {
+          "content-type": "text/javascript; charset=UTF-8"
+        },
+        {
+          "x-content-type-options": "nosniff"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "cafe"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-length": "979"
+        },
+        {
+          "x-xss-protection": "1; mode=block"
+        },
+        {
+          "x-frame-options": "ALLOWALL"
+        },
+        {
+          "age": "3217"
+        },
+        {
+          "content-disposition": "attachment"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache-Coyote/1.1"
+        },
+        {
+          "p3p": "policyref=\"/w3c/p3p.xml\", CP=\"NOI CURa DEVa TAIa PSAa PSDa IVAa IVDa OUR IND UNI NAV\""
+        },
+        {
+          "cache-control": "max-age=0, no-cache, no-store, private, must-revalidate, s-maxage=0"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "set-cookie": "uid=3582991558377661871; Domain=.p-td.com; Expires=Thu, 02-May-2013 13:40:18 GMT; Path=/"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "keep-alive": "timeout=20"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "p3p": "policyref=\"http://www.imrworldwide.com/w3c/p3p.xml\", CP=\"NOI DSP COR NID PSA ADM OUR IND UNI NAV COM\""
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "set-cookie": "rts_AAAA=MLs3MV9rcF5/e8raSsB8J1a8xoyhfqgGdE1oaHcypJ43DeCuFAmr4KFNP2NyUKmpJDKN5oHAaw4FLg6p/xU87LpGBP1V8Vwc/u8nqIWD9h6mituy2I3ef/nmfXXys59Ro9/kQ77nLnGIV6iKi6h89ib3bNEkAgz8RVtHEqb8hpvCshkDOJUx9+7dGislj1zxURVYlAk37LbXfBKtqErQegJsJj8=; Domain=.revsci.net; Expires=Sun, 03-Nov-2013 13:40:18 GMT; Path=/"
+        },
+        {
+          "x-proc-data": "pd4-bgas09-2"
+        },
+        {
+          "p3p": "policyref=\"http://js.revsci.net/w3c/rsip3p.xml\", CP=\"NON PSA PSD IVA IVD OTP SAM IND UNI PUR COM NAV INT DEM CNT STA PRE OTC HEA\""
+        },
+        {
+          "server": "RSI"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "Thu, 01 Jan 1970 00:00:00 GMT"
+        },
+        {
+          "content-type": "application/javascript;charset=UTF-8"
+        },
+        {
+          "transfer-encoding": "chunked"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "connection": "close"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "Microsoft-IIS/6.0"
+        },
+        {
+          "x-powered-by": "ASP.NET"
+        },
+        {
+          "set-cookie": "ACOOKIE=C8ctADEzMC4xMjkuNjguNzMtMjY4MDEwOTgyNC4zMDI1OTY1NgAAAAAAAAAEAAAAmLwAAJEelVCHHpVQ9r0AALkelVCSHpVQ+r0AAJ0elVCdHpVQ970AAMIelVC8HpVQAQAAAHhHAADCHpVQhx6VUAAAAAA-; path=/; expires=Mon, 03-Nov-2014 13:40:18 GMT"
+        },
+        {
+          "p3p": "CP=\"NOI DSP COR NID ADM DEV PSA OUR IND UNI PUR COM NAV INT STA\""
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "expires": "-1"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "67"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "server": "Sun-ONE-Web-Server/6.1"
+        },
+        {
+          "ntcoent-length": "1068"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/json"
+        },
+        {
+          "cache-control": "private"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "5623"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "x-powered-by": "PHP/5.2.9"
+        },
+        {
+          "content-type": "text/html"
+        },
+        {
+          "set-cookie": "NYT-S=0MMaQ/2qmmFHvDXrmvxADeHAjAqSvifpeXdeFz9JchiAIcUoUNnYFX3YV.Ynx4rkFI; path=/; domain=.nytimes.com"
+        },
+        {
+          "expires": "Thu, 01 Dec 1994 16:00:00 GMT"
+        },
+        {
+          "cache-control": "no-cache"
+        },
+        {
+          "pragma": "no-cache"
+        },
+        {
+          "transfer-encoding": "chunked"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "last-modified": "Fri, 12 Oct 2012 00:14:49 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "content-length": "13551"
+        },
+        {
+          "cneonction": "close"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "cache-control": "private, max-age=68002"
+        },
+        {
+          "expires": "Sun, 04 Nov 2012 08:33:40 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:18 GMT"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "last-modified": "Sat, 03 Nov 2012 07:39:41 GMT"
+        },
+        {
+          "accept-ranges": "bytes"
+        },
+        {
+          "vary": "Accept-Encoding"
+        },
+        {
+          "content-encoding": "gzip"
+        },
+        {
+          "nncoection": "close"
+        },
+        {
+          "content-type": "application/x-javascript"
+        },
+        {
+          "cache-control": "private, max-age=300"
+        },
+        {
+          "expires": "Sat, 03 Nov 2012 13:45:17 GMT"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:17 GMT"
+        },
+        {
+          "content-length": "4073"
+        },
+        {
+          "connection": "keep-alive"
+        },
+        {
+          "cneonction": "close"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "204"
+        },
+        {
+          "cache-control": "private, no-cache, no-store"
+        },
+        {
+          "content-length": "0"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:19 GMT"
+        },
+        {
+          "p3p": "policyref=\"http://cdn.krxd.net/kruxcontent/p3p.xml\", CP=\"NON DSP COR NID OUR DEL SAM OTR UNR COM NAV INT DEM CNT STA PRE LOC OTC\""
+        },
+        {
+          "server": "Apache"
+        },
+        {
+          "set-cookie": "_kuid_=IAJ5QtWI; path=/; expires=Thu, 02-May-13 13:40:19 GMT; domain=.krxd.net"
+        },
+        {
+          "x-request-time": "D=259 t=1351950019348818"
+        },
+        {
+          "x-served-by": "beacon-a002.krxd.net"
+        },
+        {
+          "connection": "keep-alive"
+        }
+      ]
+    },
+    {
+      "headers": [
+        {
+          ":status": "200"
+        },
+        {
+          "server": "nginx/0.7.67"
+        },
+        {
+          "date": "Sat, 03 Nov 2012 13:40:19 GMT"
+        },
+        {
+          "content-type": "image/gif"
+        },
+        {
+          "content-length": "43"
+        },
+        {
+          "connection": "close"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/data/story_31.json b/jetty-http2/http2-hpack/src/test/resources/data/story_31.json
new file mode 100644
index 0000000..62f43e2
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/data/story_31.json
@@ -0,0 +1,4555 @@
+{
+  "cases": [
+    {
+      "seqno": 0, 
+      "headers": [
+        {
+          "content-length": "522"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "expires": "Tue, 21 May 2013 19:18:33 GMT"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "public, max-age=17216869"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "IVe/SwucJuBsLtVHWJw2PMdOTOxuEWUir5igQNThkTg="
+        }
+      ]
+    }, 
+    {
+      "seqno": 1, 
+      "headers": [
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Sun, 12 May 2013 06:59:14 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "content-length": "123"
+        }, 
+        {
+          "last-modified": "Tue, 24 Apr 2012 22:13:35 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=16394910"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "95tUymdadFLd8Dpml8VnOoUG7KhisOwk74Kd/aIGfU0="
+        }
+      ]
+    }, 
+    {
+      "seqno": 2, 
+      "headers": [
+        {
+          "content-length": "14684"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:44:39 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:37:35 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067635"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "Qc0GcUiwi3io8aSRIdXaahYr6KKhphvV6NlN8vo/bD4="
+        }
+      ]
+    }, 
+    {
+      "seqno": 3, 
+      "headers": [
+        {
+          "content-length": "14438"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "expires": "Mon, 19 Aug 2013 00:53:24 GMT"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:23 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "public, max-age=24926560"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "7exUqkoZxtfLseR1zLxJlXnpYK6MOognZuCKx7drdRo="
+        }
+      ]
+    }, 
+    {
+      "seqno": 4, 
+      "headers": [
+        {
+          "content-length": "17475"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 18:31:11 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Mon, 29 Oct 2012 17:08:56 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31124427"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "eRvyJLXIvW3Vu9d+m439v+LGKqXiLSKmz7w9/xMAUpc="
+        }
+      ]
+    }, 
+    {
+      "seqno": 5, 
+      "headers": [
+        {
+          "content-length": "44191"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:44:39 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 22:55:27 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067635"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:44 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "14hoEcywNNMBIVUS5B7AD7RDGiDvJ4BGeOVgJbBDzf0="
+        }
+      ]
+    }, 
+    {
+      "seqno": 6, 
+      "headers": [
+        {
+          "content-length": "754"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 16 Oct 2013 14:03:31 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Fri, 12 Oct 2012 18:34:48 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=29985162"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "41/HuGcFNMmys4cvGKlBeylojdVDP4+VBIf1giu3eNQ="
+        }
+      ]
+    }, 
+    {
+      "seqno": 7, 
+      "headers": [
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:40:10 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "content-length": "2349"
+        }, 
+        {
+          "last-modified": "Thu, 25 Oct 2012 16:05:53 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067361"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "oKQwv0JLYost+zqlv8x+C7MEL7zRBbeMomoc54M5RZY="
+        }
+      ]
+    }, 
+    {
+      "seqno": 8, 
+      "headers": [
+        {
+          "content-length": "2626"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:00:19 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:08:50 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068570"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "zh8tRHKFtERIZ+K/eGiM1utm1H66OnOj1qwPAN7Ck9A="
+        }
+      ]
+    }, 
+    {
+      "seqno": 9, 
+      "headers": [
+        {
+          "content-length": "8036"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:09 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Fri, 28 Sep 2012 15:01:14 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31066940"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "pricqIchHztHxKAQSidQiwGmRf62vAL6I7Oi0r/Ki08="
+        }
+      ]
+    }, 
+    {
+      "seqno": 10, 
+      "headers": [
+        {
+          "content-length": "36302"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:58:39 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:42:19 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068470"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "Kur2FUUQjAQ0yPQJC9fvK56/+LWZHvyQF6Ce2Fuaf2k="
+        }
+      ]
+    }, 
+    {
+      "seqno": 11, 
+      "headers": [
+        {
+          "content-length": "8230"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 06:59:08 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:51 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25639699"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "wk2MWysJhw3Et7CRGMA1sE9HWuyzy8oCvtT2V7iPXeg="
+        }
+      ]
+    }, 
+    {
+      "seqno": 12, 
+      "headers": [
+        {
+          "content-length": "4878"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:59:38 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:38:44 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068529"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:49 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "GMzzyj0B89LYf1zKH9hqxZekz5mYTmsuxwLugWyc2Gg="
+        }
+      ]
+    }, 
+    {
+      "seqno": 13, 
+      "headers": [
+        {
+          "content-length": "1814"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "content-transfer-encoding": "binary"
+        }, 
+        {
+          "expires": "Sat, 10 Nov 2012 04:37:48 GMT"
+        }, 
+        {
+          "last-modified": "Sat, 03 Nov 2012 04:37:48 GMT"
+        }, 
+        {
+          "connection": "Keep-Alive"
+        }, 
+        {
+          "cache-control": "max-age=575215, public, no-transform, must-revalidate"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:53 GMT"
+        }, 
+        {
+          "nncoection": "close"
+        }, 
+        {
+          "content-type": "application/ocsp-response"
+        }
+      ]
+    }, 
+    {
+      "seqno": 14, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":53,\"r\":26,\"q\":0,\"a\":25}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.74.89.23"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "7iLjsQVXsunUKXe3NlV2ytaBGzQ0VHCkMX/J6rEuB6Y="
+        }
+      ]
+    }, 
+    {
+      "seqno": 15, 
+      "headers": [
+        {
+          "content-length": "1155"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:46:08 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 15:06:53 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067714"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "ur+THlFHeLotsmDlQWYPw2GRELyvg28JmE0JYVt56uo="
+        }
+      ]
+    }, 
+    {
+      "seqno": 16, 
+      "headers": [
+        {
+          "content-length": "516"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 04 Sep 2013 02:55:58 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Fri, 31 Aug 2012 22:13:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=26316304"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "6/fKHkRtBpT4oqBg33tFHk2pO6SDZlUG11Uq4/AlUIE="
+        }
+      ]
+    }, 
+    {
+      "seqno": 17, 
+      "headers": [
+        {
+          "content-length": "232"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Mon, 21 Oct 2013 14:44:35 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sat, 21 Apr 2012 07:03:57 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=30419619"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "XtTsONeGHGs/1vRRv8cvNY1ciB3XqlrvnTq2GZXvnqM="
+        }
+      ]
+    }, 
+    {
+      "seqno": 18, 
+      "headers": [
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:09 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "content-length": "400"
+        }, 
+        {
+          "last-modified": "Fri, 07 Sep 2012 15:18:40 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31066933"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "E2JBYTapyXFjxTTVqkrekTVKDp1lDQQT/7YxcxfNU2U="
+        }
+      ]
+    }, 
+    {
+      "seqno": 19, 
+      "headers": [
+        {
+          "content-length": "35766"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:14 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:41:45 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068980"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:54 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "iPbLdjapQzRoatbOUDrN+exDj8EPHJAcsZ48pVtprtA="
+        }
+      ]
+    }, 
+    {
+      "seqno": 20, 
+      "headers": [
+        {
+          "content-length": "10902"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:33:40 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:34:50 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31066965"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:55 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "0ci0R5R2ivIVCRrwtG507Eej+LTK8dUL8dIiZp70+dU="
+        }
+      ]
+    }, 
+    {
+      "seqno": 21, 
+      "headers": [
+        {
+          "content-length": "4676"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 08:36:24 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:38:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31088728"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "P2Bq0ebVXjtf8GyQp1HHux8NxlftUMXZuY8XF+yaOVo="
+        }
+      ]
+    }, 
+    {
+      "seqno": 22, 
+      "headers": [
+        {
+          "content-length": "20791"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:45:10 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:37:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067654"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "yHzV/c0w3ZyInkRbLCDrA0t5adSMyAG4prBOk+i+t6Y="
+        }
+      ]
+    }, 
+    {
+      "seqno": 23, 
+      "headers": [
+        {
+          "content-length": "11113"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:34:04 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:34:47 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31066988"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "u363OvKFmnm717JBUXA5ePB8Ts0ppRI7+eEJwOOep6w="
+        }
+      ]
+    }, 
+    {
+      "seqno": 24, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 28 Aug 2013 14:37:09 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:57 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25753573"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "Yty+Te4OzfswtmjzbJmJZaybyM0hxXiRU2NtHEbDuPE="
+        }
+      ]
+    }, 
+    {
+      "seqno": 25, 
+      "headers": [
+        {
+          "content-length": "571"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 28 Aug 2013 14:41:07 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:24 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25753811"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "yKFyrxwqBiumMPfWvv4morUUsmz9djZtSdmCoQMnchs="
+        }
+      ]
+    }, 
+    {
+      "seqno": 26, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 28 Aug 2013 14:40:26 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25753770"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "HbryxnP7HNa7kdTChA6BppSjLQw0gz9ZzESCqEH3/9k="
+        }
+      ]
+    }, 
+    {
+      "seqno": 27, 
+      "headers": [
+        {
+          "content-length": "12817"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Thu, 05 Sep 2013 18:18:17 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Tue, 28 Aug 2012 01:20:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=26458041"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:56 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "edgqdu1lFmUW32Et2hHoiAsp9kFIch8QDiciO71cQ4w="
+        }
+      ]
+    }, 
+    {
+      "seqno": 28, 
+      "headers": [
+        {
+          "content-length": "11688"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:09:30 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068990"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "rXXtxI3fPgNHe6wKIDRBR0xjttUNeG+BDQM8QfKQa+A="
+        }
+      ]
+    }, 
+    {
+      "seqno": 29, 
+      "headers": [
+        {
+          "content-length": "35165"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:59:38 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:06:47 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068521"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "fUJ2Nc9qJdBC1AnYFA5Vs1f7ozv+i/PTKO+Vep0A0HQ="
+        }
+      ]
+    }, 
+    {
+      "seqno": 30, 
+      "headers": [
+        {
+          "content-length": "1028"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 30 Oct 2013 13:15:07 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31191849"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "s9ZmJKnYGlEjIGo8xQzxlhVM4nilGHgcv1fhK1Z7F1w="
+        }
+      ]
+    }, 
+    {
+      "seqno": 31, 
+      "headers": [
+        {
+          "content-length": "47844"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:08 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068990"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "hMQvA7xhuAspt5fOxedr0fWzQZNLkyizVtlmspzgVG8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 32, 
+      "headers": [
+        {
+          "content-length": "42391"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 23:54:49 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Mon, 29 Oct 2012 19:17:24 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31143832"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "1EkJKYLfWucaDVhZCEVAAo57HpAH7rvF4r9IwDXM2B8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 33, 
+      "headers": [
+        {
+          "content-length": "13181"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:10:32 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068989"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "dO6OKUf38jDdtAnTrM28wZTBz9Y5hU/0EJdd1CkWGDs="
+        }
+      ]
+    }, 
+    {
+      "seqno": 34, 
+      "headers": [
+        {
+          "content-length": "23736"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Sat, 02 Nov 2013 20:50:17 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Fri, 02 Nov 2012 19:03:57 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31478360"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:57 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "IlZ4dyc3v7fqrfiamqJbFeFTWRkUvEUs2L8KLXNa+5o="
+        }
+      ]
+    }, 
+    {
+      "seqno": 35, 
+      "headers": [
+        {
+          "content-length": "12969"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Fri, 01 Nov 2013 21:39:03 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 01 Nov 2012 20:35:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31394885"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "REVz0k4Gud7bedzv9KSTG2i1KOporb0T14mWht95MIE="
+        }
+      ]
+    }, 
+    {
+      "seqno": 36, 
+      "headers": [
+        {
+          "content-length": "8457"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 08:36:26 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:06:44 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31088728"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "VKvuYL/9rqvjXh7mr8LjSJmcgQLZ/a+Ztqj2aUsPacc="
+        }
+      ]
+    }, 
+    {
+      "seqno": 37, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":26,\"r\":18,\"q\":0,\"a\":30}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.86.49"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "egJridVr0Ohgw3QbFe66p8hTV/ZDa+ldtrrj55f1Dwg="
+        }
+      ]
+    }, 
+    {
+      "seqno": 38, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":15,\"r\":74,\"q\":0,\"a\":21}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.212.85"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "7JVbUHGoJcLzIbHgkJPv0DSBycKYYPPorUc0i6OdRw8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 39, 
+      "headers": [
+        {
+          "content-length": "10334"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":33,\"r\":14,\"q\":0,\"a\":27}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.203.85"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }, 
+        {
+          "x-fb-debug": "SHFiC3r5rPZSoyQ6AT4o7Lrz58o2i0cRMRoLoKKAVLc="
+        }
+      ]
+    }, 
+    {
+      "seqno": 40, 
+      "headers": [
+        {
+          "content-length": "79019"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.121.55"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }, 
+        {
+          "x-fb-debug": "B8TQ25HLrpUM+2nuhej+798G7ib2rXsLxKDRmmd6364="
+        }
+      ]
+    }, 
+    {
+      "seqno": 41, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 21 May 2013 19:18:35 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:05 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=17216856"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "q1YlNQFhUrIi0HF88gF/s47itTMC0ALVS2i6Xo/eSFQ="
+        }
+      ]
+    }, 
+    {
+      "seqno": 42, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 21 May 2013 19:18:34 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:20 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=17216855"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "OOKrpYeJ1K2euVWUg0h3X4OLDU+bPXAhHe2ZbKmaIIo="
+        }
+      ]
+    }, 
+    {
+      "seqno": 43, 
+      "headers": [
+        {
+          "content-length": "55530"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:27 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:42:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068989"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:58 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "BWYgCEbzeWyERD5oPP51t1mG+xnS0km1r6TZrds9BdY="
+        }
+      ]
+    }, 
+    {
+      "seqno": 44, 
+      "headers": [
+        {
+          "content-length": "67"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":47,\"r\":27,\"q\":0,\"a\":24}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.121.55"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "6DDnMStngO3Ec4qHVJLnouT/OjWIKWOh3p7X19lwA2E="
+        }
+      ]
+    }, 
+    {
+      "seqno": 45, 
+      "headers": [
+        {
+          "content-length": "67"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "DY+dO6Fs6HOjJLzXfO2vzcoACugopwtj+ZfSFe3+0Io="
+        }
+      ]
+    }, 
+    {
+      "seqno": 46, 
+      "headers": [
+        {
+          "content-length": "6332"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 15 Oct 2013 04:49:02 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Mon, 15 Oct 2012 01:19:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=29865483"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:50:59 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "U3t5ojZAXSlz/rftvVXMdi+dQaAlCxv95u4nFdmaOpU="
+        }
+      ]
+    }, 
+    {
+      "seqno": 47, 
+      "headers": [
+        {
+          "content-length": "1025"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 21 May 2013 19:18:34 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:19 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=17216854"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:00 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "WkN9kzT0IbJnmPVAe/JpiO1KA3sDm5JiLNu+peaU22E="
+        }
+      ]
+    }, 
+    {
+      "seqno": 48, 
+      "headers": [
+        {
+          "content-length": "7905"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 30 Oct 2013 13:12:25 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:38:51 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31191685"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:00 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "flUDwRXAcKGlCZV+B6xp1kix2zMM2jCaLr8GXWfOS9o="
+        }
+      ]
+    }, 
+    {
+      "seqno": 49, 
+      "headers": [
+        {
+          "content-length": "960"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 28 Aug 2013 14:36:20 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 07 Jun 2012 20:17:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25753518"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "s2bSrOgSOrnc1I2Y+hCmZNjO4JKRAsJvvEShk7xvQh0="
+        }
+      ]
+    }, 
+    {
+      "seqno": 50, 
+      "headers": [
+        {
+          "content-length": "1421"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 28 Aug 2013 14:36:47 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Fri, 13 Jul 2012 13:05:49 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25753545"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "dSqFMj3BQam7KrjoHsDUySNYx2e/ZA4jk+iLwQD5q+M="
+        }
+      ]
+    }, 
+    {
+      "seqno": 51, 
+      "headers": [
+        {
+          "content-length": "3977"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 30 Oct 2013 05:00:35 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:41:38 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31162173"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:02 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "if1LyEGCEK6E/tHFIYqTdcReGf2YlH/8CNcvt0MSb5c="
+        }
+      ]
+    }, 
+    {
+      "seqno": 52, 
+      "headers": [
+        {
+          "content-length": "316"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:29 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:03 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25628126"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "0MQqsPt7SaQdEz9msJEk0wieC0zyyvfgvjy4gscfRm4="
+        }
+      ]
+    }, 
+    {
+      "seqno": 53, 
+      "headers": [
+        {
+          "content-length": "6779"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Wed, 09 May 2012 22:55:50 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 54, 
+      "headers": [
+        {
+          "content-length": "7899"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 14 May 2012 09:15:54 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 55, 
+      "headers": [
+        {
+          "content-length": "8961"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Fri, 10 Aug 2012 23:04:25 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 56, 
+      "headers": [
+        {
+          "content-length": "7270"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Thu, 17 May 2012 17:02:26 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 57, 
+      "headers": [
+        {
+          "content-length": "10284"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 14 Sep 2012 13:43:01 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 58, 
+      "headers": [
+        {
+          "content-length": "6932"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 16:53:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 59, 
+      "headers": [
+        {
+          "content-length": "19404"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Fri, 13 Jul 2012 21:38:17 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 60, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":23,\"r\":24,\"q\":0,\"a\":31}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.204.89"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "mhzgPOTS+rD7XyjD1gp3zWldoiZpmeeyK0sWCXxCmL8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 61, 
+      "headers": [
+        {
+          "content-length": "43"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":13,\"r\":137,\"q\":0,\"a\":23}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.167.53"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }, 
+        {
+          "x-fb-debug": "uWC6Yw5Jjt8tp6GMW/0c7q4sQiyN+cfsFumyrajMSLE="
+        }
+      ]
+    }, 
+    {
+      "seqno": 62, 
+      "headers": [
+        {
+          "content-length": "10334"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":20,\"r\":43,\"q\":0,\"a\":30}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.165.52.67"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }, 
+        {
+          "x-fb-debug": "K6O9zzGnsjkFUcjVnvogKEp8WyYKDD5/1SRA3JOqTz8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 63, 
+      "headers": [
+        {
+          "content-length": "79019"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.10.79"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }, 
+        {
+          "x-fb-debug": "gU+KRCRWrUp+aETSVFA2+QqzJ57Mry5y8i9NZISRzV4="
+        }
+      ]
+    }, 
+    {
+      "seqno": 64, 
+      "headers": [
+        {
+          "content-length": "67"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "x-fb-metrics": "{\"w\":40,\"r\":33,\"q\":0,\"a\":22}"
+        }, 
+        {
+          "expires": "Thu, 1 Apr 2004 01:01:01 GMT"
+        }, 
+        {
+          "x-fb-server": "10.164.10.79"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "last-modified": "Thu, 1 Apr 2004 01:01:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "2KYdrNd+vAjbaW2+l9lZ0c9qQnQQuLC0uV+aDWEfnEs="
+        }
+      ]
+    }, 
+    {
+      "seqno": 65, 
+      "headers": [
+        {
+          "content-length": "67"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:04 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "ltZY31wZe0x9jjXZ+/GQMCIZ6L+UzLcVFaj4Ye8cEag="
+        }
+      ]
+    }, 
+    {
+      "seqno": 66, 
+      "headers": [
+        {
+          "content-length": "32220"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 15 Oct 2012 15:37:08 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 67, 
+      "headers": [
+        {
+          "content-length": "105703"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 15 Oct 2012 15:38:03 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 68, 
+      "headers": [
+        {
+          "content-length": "36768"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Thu, 01 Nov 2012 01:55:42 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/gif"
+        }
+      ]
+    }, 
+    {
+      "seqno": 69, 
+      "headers": [
+        {
+          "content-length": "119574"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 26 Oct 2012 09:41:12 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 70, 
+      "headers": [
+        {
+          "content-length": "659"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Sat, 11 May 2013 07:12:06 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:22 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=16309260"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:06 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/x-icon"
+        }, 
+        {
+          "x-fb-debug": "yE8mx2kOMcI8Q4MtoKCXYAXv7xSMQBGufoB0y/qkYEs="
+        }
+      ]
+    }, 
+    {
+      "seqno": 71, 
+      "headers": [
+        {
+          "content-length": "6966"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Thu, 17 May 2012 16:26:06 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 72, 
+      "headers": [
+        {
+          "content-length": "4501"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 06 Jul 2012 11:36:45 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 73, 
+      "headers": [
+        {
+          "content-length": "37432"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 04 Jun 2012 08:35:52 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 74, 
+      "headers": [
+        {
+          "content-length": "7198"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 16:45:13 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 75, 
+      "headers": [
+        {
+          "content-length": "13454"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Thu, 31 May 2012 01:48:38 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 76, 
+      "headers": [
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "transfer-encoding": "chunked"
+        }, 
+        {
+          "access-control-allow-credentials": "true"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "pragma": "no-cache"
+        }, 
+        {
+          "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:08 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "http://www.facebook.com"
+        }, 
+        {
+          "content-type": "application/json"
+        }
+      ]
+    }, 
+    {
+      "seqno": 77, 
+      "headers": [
+        {
+          "content-length": "19537"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Tue, 19 Jun 2012 08:51:27 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 78, 
+      "headers": [
+        {
+          "content-length": "5842"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 14 May 2012 22:03:47 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 79, 
+      "headers": [
+        {
+          "content-length": "6973"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 22 May 2012 23:26:43 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 80, 
+      "headers": [
+        {
+          "content-length": "7263"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Mon, 11 Jun 2012 21:11:11 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 81, 
+      "headers": [
+        {
+          "content-length": "6222"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 02:10:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 82, 
+      "headers": [
+        {
+          "content-length": "8005"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 13 Jul 2012 02:50:27 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 83, 
+      "headers": [
+        {
+          "content-length": "7949"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Wed, 31 Oct 2012 17:25:30 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 84, 
+      "headers": [
+        {
+          "content-length": "5850"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Wed, 23 May 2012 13:04:05 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 85, 
+      "headers": [
+        {
+          "content-length": "4860"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 18 May 2012 06:59:13 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 86, 
+      "headers": [
+        {
+          "content-length": "36615"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 08 Jun 2012 09:18:35 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 87, 
+      "headers": [
+        {
+          "content-length": "26180"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 01 Jun 2012 12:58:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 88, 
+      "headers": [
+        {
+          "content-length": "8551"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Wed, 16 May 2012 00:19:20 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 89, 
+      "headers": [
+        {
+          "content-length": "7021"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 18 May 2012 08:58:03 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 90, 
+      "headers": [
+        {
+          "content-length": "8126"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Thu, 17 May 2012 10:31:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 91, 
+      "headers": [
+        {
+          "content-length": "21780"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 20 Jul 2012 20:43:14 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 92, 
+      "headers": [
+        {
+          "content-length": "16109"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 08 Jun 2012 21:45:00 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 93, 
+      "headers": [
+        {
+          "content-length": "5248"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 17:19:22 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 94, 
+      "headers": [
+        {
+          "content-length": "7600"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 00:02:13 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 95, 
+      "headers": [
+        {
+          "content-length": "8148"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Tue, 04 Sep 2012 05:25:17 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 96, 
+      "headers": [
+        {
+          "content-length": "23688"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "last-modified": "Tue, 05 Jun 2012 16:58:56 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:10 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 97, 
+      "headers": [
+        {
+          "content-length": "32579"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 15 Jun 2012 23:21:31 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 98, 
+      "headers": [
+        {
+          "content-length": "36154"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Tue, 15 May 2012 16:53:04 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 99, 
+      "headers": [
+        {
+          "content-length": "8261"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Thu, 17 May 2012 16:15:19 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/jpeg"
+        }
+      ]
+    }, 
+    {
+      "seqno": 100, 
+      "headers": [
+        {
+          "content-length": "34603"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "expires": "Sat, 17 Nov 2012 12:51:03 GMT"
+        }, 
+        {
+          "last-modified": "Tue, 05 Jun 2012 19:33:30 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 101, 
+      "headers": [
+        {
+          "content-length": "19320"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "accept-ranges": "bytes"
+        }, 
+        {
+          "last-modified": "Fri, 20 Jul 2012 22:33:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "max-age=1209600"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:09 GMT"
+        }, 
+        {
+          "content-type": "image/png"
+        }
+      ]
+    }, 
+    {
+      "seqno": 102, 
+      "headers": [
+        {
+          "content-length": "1589"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 30 Oct 2013 13:08:05 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sat, 27 Oct 2012 21:59:56 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31191410"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "cEr4CpqyPlutZEM5egM7EW1V/FoNLas8puqhILOyn6g="
+        }
+      ]
+    }, 
+    {
+      "seqno": 103, 
+      "headers": [
+        {
+          "content-length": "124"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 05:04:30 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:34 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25632795"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "SjbWzWIhc5uDeUgKzkah4oVawEfOfsqgn79tJvLiODA="
+        }
+      ]
+    }, 
+    {
+      "seqno": 104, 
+      "headers": [
+        {
+          "content-length": "178"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 06:45:13 GMT"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          "cache-control": "public, max-age=25638838"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "8BYYADIiLWZPRqrmghOTJnnu5b75InjLJYums29XQC4="
+        }
+      ]
+    }, 
+    {
+      "seqno": 105, 
+      "headers": [
+        {
+          "content-length": "3403"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 11:39:02 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Fri, 26 Oct 2012 21:42:07 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31099667"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "rg/3x10ePyW5+Yv14okaeMgQpdIDitUpRdeQlHd62wU="
+        }
+      ]
+    }, 
+    {
+      "seqno": 106, 
+      "headers": [
+        {
+          "content-length": "3794"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 09:12:42 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:11:34 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31090886"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "+G0d7Y1/nAK76h5l1ygZcgFyqkHdYYjzu9bN8TThTW0="
+        }
+      ]
+    }, 
+    {
+      "seqno": 107, 
+      "headers": [
+        {
+          "content-length": "4316"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 30 Oct 2013 13:08:38 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 27 Sep 2012 22:19:28 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31191442"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "Zx9+0hICgorbmj40+TVQqx/6DWk0JFijw5sOouOK4x8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 108, 
+      "headers": [
+        {
+          "content-length": "82"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:37 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:02:59 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25628121"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "y9gp03qLmGwdrjrggsFyxKUnduRuH6ZkhHy3J217wnA="
+        }
+      ]
+    }, 
+    {
+      "seqno": 109, 
+      "headers": [
+        {
+          "content-length": "281"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 27 Aug 2013 03:46:43 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 12 Apr 2012 03:03:15 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=25628127"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:16 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "y31IzOtXz6QEqDb4Yh8nL9E7Jz3QdrtFTVTfJpFI67s="
+        }
+      ]
+    }, 
+    {
+      "seqno": 110, 
+      "headers": [
+        {
+          "content-length": "18581"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 03:07:15 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:07:48 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31068960"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "cdKo7nf6SbFgEUsu8p8ZpYkyd14IkSsYwu8pEpjIPW8="
+        }
+      ]
+    }, 
+    {
+      "seqno": 111, 
+      "headers": [
+        {
+          "content-length": "686"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 02:40:01 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 21:28:22 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31067324"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:17 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "text/css; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "Mcoj0fymAm3BWRvLoE9uVgrJkXk8Wldn9hUKly6PE60="
+        }
+      ]
+    }, 
+    {
+      "seqno": 112, 
+      "headers": [
+        {
+          "content-length": "70824"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 29 Oct 2013 16:43:30 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Sun, 28 Oct 2012 14:35:10 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31117935"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:15 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "image/png"
+        }, 
+        {
+          "x-fb-debug": "U6CnJQe7lFM5/wvYBRcEyvixo284qs3dxFI4vIJ3Sfo="
+        }
+      ]
+    }, 
+    {
+      "seqno": 113, 
+      "headers": [
+        {
+          "content-length": "6953"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 06 Nov 2012 13:10:12 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=260332"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:20 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-shockwave-flash"
+        }, 
+        {
+          "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI="
+        }
+      ]
+    }, 
+    {
+      "seqno": 114, 
+      "headers": [
+        {
+          "content-length": "6953"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Tue, 06 Nov 2012 13:10:12 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Mon, 29 Oct 2012 18:56:50 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=260331"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:21 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-shockwave-flash"
+        }, 
+        {
+          "x-fb-debug": "8ROXKJ/K5IoNZG3RcJoN8LoohKyoDW2iTe6nY9hRINI="
+        }
+      ]
+    }, 
+    {
+      "seqno": 115, 
+      "headers": [
+        {
+          "content-length": "15685"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Thu, 31 Oct 2013 19:03:10 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Tue, 30 Oct 2012 17:45:29 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=31299110"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:20 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "casrvtlqM38DGgUK+sC64wYFWqXchCM2wnMjgM8VC98="
+        }
+      ]
+    }, 
+    {
+      "seqno": 116, 
+      "headers": [
+        {
+          "content-length": "1591"
+        }, 
+        {
+          "x-content-type-options": "nosniff"
+        }, 
+        {
+          "content-encoding": "gzip"
+        }, 
+        {
+          "expires": "Wed, 02 Oct 2013 14:15:24 GMT"
+        }, 
+        {
+          "vary": "Accept-Encoding"
+        }, 
+        {
+          "x-cnection": "close"
+        }, 
+        {
+          "last-modified": "Thu, 20 Sep 2012 01:12:35 GMT"
+        }, 
+        {
+          "connection": "keep-alive"
+        }, 
+        {
+          ":status": "200"
+        }, 
+        {
+          "cache-control": "public, max-age=28776235"
+        }, 
+        {
+          "date": "Sat, 03 Nov 2012 12:51:29 GMT"
+        }, 
+        {
+          "access-control-allow-origin": "*"
+        }, 
+        {
+          "content-type": "application/x-javascript; charset=utf-8"
+        }, 
+        {
+          "x-fb-debug": "E9XqLqcAPtaMWK+vlxTTyhNPMewUq9nSCKax+m9KMwk="
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..e40e8e4
--- /dev/null
+++ b/jetty-http2/http2-hpack/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.http2.LEVEL=INFO
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
diff --git a/jetty-http2/http2-http-client-transport/pom.xml b/jetty-http2/http2-http-client-transport/pom.xml
new file mode 100644
index 0000000..90517af
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.eclipse.jetty.http2</groupId>
+        <artifactId>http2-parent</artifactId>
+        <version>9.3.7-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>http2-http-client-transport</artifactId>
+    <name>Jetty :: HTTP2 :: HTTP Client Transport</name>
+
+    <properties>
+        <bundle-symbolic-name>${project.groupId}.client.http</bundle-symbolic-name>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.mortbay.jetty.alpn</groupId>
+                                    <artifactId>alpn-boot</artifactId>
+                                    <version>${alpn.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                    <outputDirectory>${project.build.directory}/alpn</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-test-helper</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java
new file mode 100644
index 0000000..92e1158
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpChannelOverHTTP2.java
@@ -0,0 +1,88 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client.http;
+
+import org.eclipse.jetty.client.HttpChannel;
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.HttpReceiver;
+import org.eclipse.jetty.client.HttpSender;
+import org.eclipse.jetty.client.api.Result;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+
+public class HttpChannelOverHTTP2 extends HttpChannel
+{
+    private final HttpConnectionOverHTTP2 connection;
+    private final Session session;
+    private final HttpSenderOverHTTP2 sender;
+    private final HttpReceiverOverHTTP2 receiver;
+
+    public HttpChannelOverHTTP2(HttpDestination destination, HttpConnectionOverHTTP2 connection, Session session)
+    {
+        super(destination);
+        this.connection = connection;
+        this.session = session;
+        this.sender = new HttpSenderOverHTTP2(this);
+        this.receiver = new HttpReceiverOverHTTP2(this);
+    }
+
+    public Session getSession()
+    {
+        return session;
+    }
+
+    public Stream.Listener getStreamListener()
+    {
+        return receiver;
+    }
+
+    @Override
+    protected HttpSender getHttpSender()
+    {
+        return sender;
+    }
+
+    @Override
+    protected HttpReceiver getHttpReceiver()
+    {
+        return receiver;
+    }
+
+    @Override
+    public void send()
+    {
+        HttpExchange exchange = getHttpExchange();
+        if (exchange != null)
+            sender.send(exchange);
+    }
+
+    @Override
+    public void release()
+    {
+        connection.release(this);
+    }
+
+    @Override
+    public void exchangeTerminated(HttpExchange exchange, Result result)
+    {
+        super.exchangeTerminated(exchange, result);
+        release();
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java
new file mode 100644
index 0000000..d722717
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java
@@ -0,0 +1,199 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpClientTransport;
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.Origin;
+import org.eclipse.jetty.client.api.Connection;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.io.ClientConnectionFactory;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+@ManagedObject("The HTTP/2 client transport")
+public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport
+{
+    private final HTTP2Client client;
+    private ClientConnectionFactory connectionFactory;
+    private HttpClient httpClient;
+
+    public HttpClientTransportOverHTTP2(HTTP2Client client)
+    {
+        this.client = client;
+    }
+
+    @ManagedAttribute(value = "The number of selectors", readonly = true)
+    public int getSelectors()
+    {
+        return client.getSelectors();
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        if (!client.isStarted())
+        {
+            client.setExecutor(httpClient.getExecutor());
+            client.setScheduler(httpClient.getScheduler());
+            client.setByteBufferPool(httpClient.getByteBufferPool());
+            client.setConnectTimeout(httpClient.getConnectTimeout());
+            client.setIdleTimeout(httpClient.getIdleTimeout());
+            client.setInputBufferSize(httpClient.getResponseBufferSize());
+        }
+        addBean(client);
+        super.doStart();
+
+        this.connectionFactory = new HTTP2ClientConnectionFactory();
+        client.setClientConnectionFactory((endPoint, context) ->
+        {
+            HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
+            return destination.getClientConnectionFactory().newConnection(endPoint, context);
+        });
+    }
+
+    @Override
+    protected void doStop() throws Exception
+    {
+        super.doStop();
+        removeBean(client);
+    }
+
+    @Override
+    public void setHttpClient(HttpClient client)
+    {
+        httpClient = client;
+    }
+
+    @Override
+    public HttpDestination newHttpDestination(Origin origin)
+    {
+        return new HttpDestinationOverHTTP2(httpClient, origin);
+    }
+
+    @Override
+    public void connect(InetSocketAddress address, Map<String, Object> context)
+    {
+        client.setConnectTimeout(httpClient.getConnectTimeout());
+
+        HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)context.get(HTTP_DESTINATION_CONTEXT_KEY);
+        @SuppressWarnings("unchecked")
+        Promise<Connection> connectionPromise = (Promise<Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
+
+        SessionListenerPromise listenerPromise = new SessionListenerPromise(destination, connectionPromise);
+
+        SslContextFactory sslContextFactory = null;
+        if (HttpScheme.HTTPS.is(destination.getScheme()))
+            sslContextFactory = httpClient.getSslContextFactory();
+
+        client.connect(sslContextFactory, address, listenerPromise, listenerPromise, context);
+    }
+
+    @Override
+    public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
+    {
+        ClientConnectionFactory factory = connectionFactory;
+        SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+        if (sslContextFactory != null)
+            factory = new ALPNClientConnectionFactory(client.getExecutor(), factory, client.getProtocols());
+        return factory.newConnection(endPoint, context);
+    }
+
+    protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session)
+    {
+        return new HttpConnectionOverHTTP2(destination, session);
+    }
+
+    private class SessionListenerPromise extends Session.Listener.Adapter implements Promise<Session>
+    {
+        private final HttpDestinationOverHTTP2 destination;
+        private final Promise<Connection> promise;
+        private HttpConnectionOverHTTP2 connection;
+
+        public SessionListenerPromise(HttpDestinationOverHTTP2 destination, Promise<Connection> promise)
+        {
+            this.destination = destination;
+            this.promise = promise;
+        }
+
+        @Override
+        public void succeeded(Session session)
+        {
+            connection = newHttpConnection(destination, session);
+            promise.succeeded(connection);
+        }
+
+        @Override
+        public void failed(Throwable failure)
+        {
+            promise.failed(failure);
+        }
+
+        @Override
+        public Map<Integer, Integer> onPreface(Session session)
+        {
+            Map<Integer, Integer> settings = new HashMap<>();
+            settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow());
+            return settings;
+        }
+
+        @Override
+        public void onSettings(Session session, SettingsFrame frame)
+        {
+            Map<Integer, Integer> settings = frame.getSettings();
+            if (settings.containsKey(SettingsFrame.MAX_CONCURRENT_STREAMS))
+                destination.setMaxRequestsPerConnection(settings.get(SettingsFrame.MAX_CONCURRENT_STREAMS));
+        }
+
+        @Override
+        public void onClose(Session session, GoAwayFrame frame)
+        {
+            connection.close();
+        }
+
+        @Override
+        public boolean onIdleTimeout(Session session)
+        {
+            return connection.onIdleTimeout();
+        }
+
+        @Override
+        public void onFailure(Session session, Throwable failure)
+        {
+            connection.close(failure);
+        }
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java
new file mode 100644
index 0000000..6bc69f9
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpConnectionOverHTTP2.java
@@ -0,0 +1,107 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import java.nio.channels.AsynchronousCloseException;
+import java.util.Set;
+
+import org.eclipse.jetty.client.HttpChannel;
+import org.eclipse.jetty.client.HttpConnection;
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.SendFailure;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.ConcurrentHashSet;
+
+public class HttpConnectionOverHTTP2 extends HttpConnection
+{
+    private final Set<HttpChannel> channels = new ConcurrentHashSet<>();
+    private final Session session;
+
+    public HttpConnectionOverHTTP2(HttpDestination destination, Session session)
+    {
+        super(destination);
+        this.session = session;
+    }
+
+    public Session getSession()
+    {
+        return session;
+    }
+
+    @Override
+    protected SendFailure send(HttpExchange exchange)
+    {
+        normalizeRequest(exchange.getRequest());
+
+        // One connection maps to N channels, so for each exchange we create a new channel.
+        HttpChannel channel = newHttpChannel();
+        channels.add(channel);
+
+        return send(channel, exchange);
+    }
+
+    protected HttpChannelOverHTTP2 newHttpChannel()
+    {
+        return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession());
+    }
+
+    protected void release(HttpChannel channel)
+    {
+        channels.remove(channel);
+        getHttpDestination().release(this);
+    }
+
+    @Override
+    public void close()
+    {
+        close(new AsynchronousCloseException());
+    }
+
+    protected void close(Throwable failure)
+    {
+        // First close then abort, to be sure that the connection cannot be reused
+        // from an onFailure() handler or by blocking code waiting for completion.
+        getHttpDestination().close(this);
+        session.close(ErrorCode.NO_ERROR.code, failure.getMessage(), Callback.NOOP);
+        abort(failure);
+    }
+
+    private void abort(Throwable failure)
+    {
+        for (HttpChannel channel : channels)
+        {
+            HttpExchange exchange = channel.getHttpExchange();
+            if (exchange != null)
+                exchange.getRequest().abort(failure);
+        }
+        channels.clear();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%h[%s]",
+                getClass().getSimpleName(),
+                this,
+                session);
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java
new file mode 100644
index 0000000..8355369
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpDestinationOverHTTP2.java
@@ -0,0 +1,39 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.MultiplexHttpDestination;
+import org.eclipse.jetty.client.Origin;
+import org.eclipse.jetty.client.SendFailure;
+
+public class HttpDestinationOverHTTP2 extends MultiplexHttpDestination<HttpConnectionOverHTTP2>
+{
+    public HttpDestinationOverHTTP2(HttpClient client, Origin origin)
+    {
+        super(client, origin);
+    }
+
+    @Override
+    protected SendFailure send(HttpConnectionOverHTTP2 connection, HttpExchange exchange)
+    {
+        return connection.send(exchange);
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java
new file mode 100644
index 0000000..827a874
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java
@@ -0,0 +1,118 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import java.io.IOException;
+
+import org.eclipse.jetty.client.HttpChannel;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.HttpReceiver;
+import org.eclipse.jetty.client.HttpResponse;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.util.Callback;
+
+public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listener
+{
+    public HttpReceiverOverHTTP2(HttpChannel channel)
+    {
+        super(channel);
+    }
+
+    @Override
+    protected HttpChannelOverHTTP2 getHttpChannel()
+    {
+        return (HttpChannelOverHTTP2)super.getHttpChannel();
+    }
+
+    @Override
+    public void onHeaders(Stream stream, HeadersFrame frame)
+    {
+        HttpExchange exchange = getHttpExchange();
+        if (exchange == null)
+            return;
+
+        HttpResponse response = exchange.getResponse();
+        MetaData.Response metaData = (MetaData.Response)frame.getMetaData();
+        response.version(metaData.getVersion()).status(metaData.getStatus()).reason(metaData.getReason());
+
+        if (responseBegin(exchange))
+        {
+            HttpFields headers = metaData.getFields();
+            for (HttpField header : headers)
+            {
+                if (!responseHeader(exchange, header))
+                    return;
+            }
+
+            if (responseHeaders(exchange))
+            {
+                if (frame.isEndStream())
+                    responseSuccess(exchange);
+            }
+        }
+    }
+
+    @Override
+    public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+    {
+        // Not supported.
+        stream.reset(new ResetFrame(stream.getId(), ErrorCode.REFUSED_STREAM_ERROR.code), Callback.NOOP);
+        return null;
+    }
+
+    @Override
+    public void onData(Stream stream, DataFrame frame, Callback callback)
+    {
+        HttpExchange exchange = getHttpExchange();
+        if (exchange == null)
+            return;
+
+        if (responseContent(exchange, frame.getData(), callback))
+        {
+            if (frame.isEndStream())
+                responseSuccess(exchange);
+        }
+    }
+
+    @Override
+    public void onReset(Stream stream, ResetFrame frame)
+    {
+        HttpExchange exchange = getHttpExchange();
+        if (exchange == null)
+            return;
+
+        ErrorCode error = ErrorCode.from(frame.getError());
+        String reason = error == null ? "reset" : error.name().toLowerCase();
+        exchange.getRequest().abort(new IOException(reason));
+    }
+
+    @Override
+    public void onTimeout(Stream stream, Throwable failure)
+    {
+        responseFailure(failure);
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java
new file mode 100644
index 0000000..db01d33
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpSenderOverHTTP2.java
@@ -0,0 +1,109 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http2.client.http;
+
+import org.eclipse.jetty.client.HttpContent;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.HttpSender;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+
+public class HttpSenderOverHTTP2 extends HttpSender
+{
+    private Stream stream;
+
+    public HttpSenderOverHTTP2(HttpChannelOverHTTP2 channel)
+    {
+        super(channel);
+    }
+
+    @Override
+    protected HttpChannelOverHTTP2 getHttpChannel()
+    {
+        return (HttpChannelOverHTTP2)super.getHttpChannel();
+    }
+
+    @Override
+    protected void sendHeaders(HttpExchange exchange, final HttpContent content, final Callback callback)
+    {
+        final Request request = exchange.getRequest();
+        HttpURI uri = new HttpURI(request.getScheme(), request.getHost(), request.getPort(), request.getPath(), null, request.getQuery(), null);
+        MetaData.Request metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders());
+        HeadersFrame headersFrame = new HeadersFrame(metaData, null, !content.hasContent());
+        HttpChannelOverHTTP2 channel = getHttpChannel();
+        Promise<Stream> promise = new Promise<Stream>()
+        {
+            @Override
+            public void succeeded(Stream stream)
+            {
+                HttpSenderOverHTTP2.this.stream = stream;
+                stream.setIdleTimeout(request.getIdleTimeout());
+
+                if (content.hasContent() && !expects100Continue(request))
+                {
+                    boolean advanced = content.advance();
+                    boolean lastContent = content.isLast();
+                    if (advanced || lastContent)
+                    {
+                        DataFrame dataFrame = new DataFrame(stream.getId(), content.getByteBuffer(), lastContent);
+                        stream.data(dataFrame, callback);
+                        return;
+                    }
+                }
+                callback.succeeded();
+            }
+
+            @Override
+            public void failed(Throwable failure)
+            {
+                callback.failed(failure);
+            }
+        };
+        // TODO optimize the send of HEADERS and DATA frames.
+        channel.getSession().newStream(headersFrame, promise, channel.getStreamListener());
+    }
+
+    @Override
+    protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback)
+    {
+        if (content.isConsumed())
+        {
+            callback.succeeded();
+        }
+        else
+        {
+            DataFrame frame = new DataFrame(stream.getId(), content.getByteBuffer(), content.isLast());
+            stream.data(frame, callback);
+        }
+    }
+
+    @Override
+    protected void reset()
+    {
+        super.reset();
+        stream = null;
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java
new file mode 100644
index 0000000..d4214dd
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/AbstractTest.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Rule;
+
+public class AbstractTest
+{
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    protected Server server;
+    protected ServerConnector connector;
+    protected HttpClient client;
+
+    protected void start(int maxConcurrentStreams, Handler handler) throws Exception
+    {
+        QueuedThreadPool serverExecutor = new QueuedThreadPool();
+        serverExecutor.setName("server");
+        server = new Server(serverExecutor);
+
+        HTTP2ServerConnectionFactory http2 = new HTTP2ServerConnectionFactory(new HttpConfiguration());
+        http2.setMaxConcurrentStreams(maxConcurrentStreams);
+        connector = new ServerConnector(server, 1, 1, http2);
+        server.addConnector(connector);
+
+        server.setHandler(handler);
+        server.start();
+
+        client = new HttpClient(new HttpClientTransportOverHTTP2(new HTTP2Client()), null);
+        QueuedThreadPool clientExecutor = new QueuedThreadPool();
+        clientExecutor.setName("client");
+        client.setExecutor(clientExecutor);
+        client.start();
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (client != null)
+            client.stop();
+        if (server != null)
+            server.stop();
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
new file mode 100644
index 0000000..c2334ea
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
@@ -0,0 +1,78 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class HttpClientTransportOverHTTP2Test
+{
+    @Test
+    public void testPropertiesAreForwarded() throws Exception
+    {
+        HTTP2Client http2Client = new HTTP2Client();
+        HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(http2Client), null);
+        Executor executor = new QueuedThreadPool();
+        httpClient.setExecutor(executor);
+        httpClient.setConnectTimeout(13);
+        httpClient.setIdleTimeout(17);
+
+        httpClient.start();
+
+        Assert.assertTrue(http2Client.isStarted());
+        Assert.assertSame(httpClient.getExecutor(), http2Client.getExecutor());
+        Assert.assertSame(httpClient.getScheduler(), http2Client.getScheduler());
+        Assert.assertSame(httpClient.getByteBufferPool(), http2Client.getByteBufferPool());
+        Assert.assertEquals(httpClient.getConnectTimeout(), http2Client.getConnectTimeout());
+        Assert.assertEquals(httpClient.getIdleTimeout(), http2Client.getIdleTimeout());
+
+        httpClient.stop();
+
+        Assert.assertTrue(http2Client.isStopped());
+    }
+
+    @Ignore
+    @Test
+    public void testExternalServer() throws Exception
+    {
+        HTTP2Client http2Client = new HTTP2Client();
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(http2Client), sslContextFactory);
+        Executor executor = new QueuedThreadPool();
+        httpClient.setExecutor(executor);
+
+        httpClient.start();
+
+//        ContentResponse response = httpClient.GET("https://http2.akamai.com/");
+        ContentResponse response = httpClient.GET("https://webtide.com/");
+
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+        httpClient.stop();
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java
new file mode 100644
index 0000000..e4ec296
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java
@@ -0,0 +1,165 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.client.http;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MaxConcurrentStreamsTest extends AbstractTest
+{
+    @Test
+    public void testOneConcurrentStream() throws Exception
+    {
+        long sleep = 1000;
+        start(1, new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                // Sleep a bit to allow the second request to be queued.
+                sleep(sleep);
+            }
+        });
+
+        // Prime the connection so that the maxConcurrentStream setting arrives to the client.
+        client.newRequest("localhost", connector.getLocalPort()).path("/prime").send();
+
+        CountDownLatch latch = new CountDownLatch(2);
+
+        // First request is sent immediately.
+        client.newRequest("localhost", connector.getLocalPort())
+                .path("/first")
+                .send(result ->
+                {
+                    if (result.isSucceeded())
+                        latch.countDown();
+                });
+
+        // Second request is queued.
+        client.newRequest("localhost", connector.getLocalPort())
+                .path("/second")
+                .send(result ->
+                {
+                    if (result.isSucceeded())
+                        latch.countDown();
+                });
+
+        // When the first request returns, the second must be sent.
+        Assert.assertTrue(latch.await(5 * sleep, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testTwoConcurrentStreamsThirdWaits() throws Exception
+    {
+        int maxStreams = 2;
+        long sleep = 1000;
+        start(maxStreams, new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                sleep(sleep);
+            }
+        });
+
+        // Prime the connection so that the maxConcurrentStream setting arrives to the client.
+        client.newRequest("localhost", connector.getLocalPort()).path("/prime").send();
+
+        // Send requests up to the max allowed.
+        for (int i = 0; i < maxStreams; ++i)
+        {
+            client.newRequest("localhost", connector.getLocalPort())
+                    .path("/" + i)
+                    .send(null);
+        }
+
+        // Send the request in excess.
+        CountDownLatch latch = new CountDownLatch(1);
+        String path = "/excess";
+        client.newRequest("localhost", connector.getLocalPort())
+                .path(path)
+                .send(result ->
+                {
+                    if (result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+
+        // The last exchange should remain in the queue.
+        HttpDestinationOverHTTP2 destination = (HttpDestinationOverHTTP2)client.getDestination("http", "localhost", connector.getLocalPort());
+        Assert.assertEquals(1, destination.getHttpExchanges().size());
+        Assert.assertEquals(path, destination.getHttpExchanges().peek().getRequest().getPath());
+
+        Assert.assertTrue(latch.await(5 * sleep, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testAbortedWhileQueued() throws Exception
+    {
+        long sleep = 1000;
+        start(1, new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                sleep(sleep);
+            }
+        });
+
+        // Prime the connection so that the maxConcurrentStream setting arrives to the client.
+        client.newRequest("localhost", connector.getLocalPort()).path("/prime").send();
+
+        // Send a request that is aborted while queued.
+        client.newRequest("localhost", connector.getLocalPort())
+                .path("/aborted")
+                .onRequestQueued(request -> request.abort(new Exception()))
+                .send(null);
+
+        // Must be able to send another request.
+        ContentResponse response = client.newRequest("localhost", connector.getLocalPort()).path("/check").send();
+
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+    }
+
+    private void sleep(long time)
+    {
+        try
+        {
+            Thread.sleep(time);
+        }
+        catch (InterruptedException x)
+        {
+            throw new RuntimeException(x);
+        }
+    }
+}
diff --git a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..287d283
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
@@ -0,0 +1,5 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+#org.eclipse.jetty.client.LEVEL=DEBUG
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.LEVEL=DEBUG
+#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
diff --git a/jetty-http2/http2-server/pom.xml b/jetty-http2/http2-server/pom.xml
new file mode 100644
index 0000000..c5bac99
--- /dev/null
+++ b/jetty-http2/http2-server/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty.http2</groupId>
+    <artifactId>http2-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>http2-server</artifactId>
+  <name>Jetty :: HTTP2 :: Server</name>
+
+ <properties>
+    <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name>
+  </properties>
+
+  <build>
+    <plugins>
+    </plugins>
+  </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.alpn</groupId>
+            <artifactId>alpn-api</artifactId>
+            <version>${alpn.api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlets</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-test-helper</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml
new file mode 100644
index 0000000..b23f25b
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- Configure a HTTP2 on the ssl connector.                       -->
+<!-- ============================================================= -->
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory">
+        <Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
+        <Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="1024"/></Set>
+        <Set name="initialStreamSendWindow"><Property name="jetty.http2.initialStreamSendWindow" default="65535"/></Set>
+      </New>
+    </Arg>
+  </Call>
+
+  <Ref refid="sslContextFactory">
+    <Set name="CipherComparator">
+      <Get class="org.eclipse.jetty.http2.HTTP2Cipher" name="COMPARATOR"/>
+    </Set>
+    <Set name="useCipherSuitesOrder">true</Set>
+  </Ref>
+
+</Configure>
+
diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml
new file mode 100644
index 0000000..ccd3af1
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- Configure a HTTP2 on the ssl connector.                       -->
+<!-- ============================================================= -->
+<Configure id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory">
+        <Arg name="config"><Ref refid="httpConfig"/></Arg>
+        <Set name="maxConcurrentStreams"><Property name="jetty.http2c.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="1024"/></Set>
+        <Set name="initialStreamSendWindow"><Property name="jetty.http2c.initialStreamSendWindow" default="65535"/></Set>
+      </New>
+    </Arg>
+  </Call>
+</Configure>
+
diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod
new file mode 100644
index 0000000..585c1fa
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod
@@ -0,0 +1,20 @@
+#
+# HTTP2 Support Module
+#
+
+[depend]
+ssl
+alpn
+
+[lib]
+lib/http2/*.jar
+
+[xml]
+etc/jetty-http2.xml
+
+[ini-template]
+## Max number of concurrent streams per connection
+# jetty.http2.maxConcurrentStreams=1024
+
+## Initial stream send (server to client) window
+# jetty.http2.initialStreamSendWindow=65535
diff --git a/jetty-http2/http2-server/src/main/config/modules/http2c.mod b/jetty-http2/http2-server/src/main/config/modules/http2c.mod
new file mode 100644
index 0000000..1c78016
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/config/modules/http2c.mod
@@ -0,0 +1,22 @@
+#
+# HTTP2 Clear Text Support Module
+# This module adds support for HTTP/2 clear text to the
+# HTTP/1 clear text connector (defined in jetty-http.xml).
+# The resulting connector will accept both HTTP/1 and HTTP/2 connections.
+#
+
+[depend]
+http
+
+[lib]
+lib/http2/*.jar
+
+[xml]
+etc/jetty-http2c.xml
+
+[ini-template]
+## Max number of concurrent streams per connection
+# jetty.http2c.maxConcurrentStreams=1024
+
+## Initial stream send (server to client) window
+# jetty.http2c.initialStreamSendWindow=65535
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java
new file mode 100644
index 0000000..8b6debe
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java
@@ -0,0 +1,175 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.util.Objects;
+
+import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.HTTP2Connection;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.ServerParser;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.AbstractConnectionFactory;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.component.LifeCycle;
+
+@ManagedObject
+public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
+{
+    private final Connection.Listener connectionListener = new ConnectionListener();
+    private final HttpConfiguration httpConfiguration;
+    private int maxDynamicTableSize = 4096;
+    private int initialStreamSendWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
+    private int maxConcurrentStreams = -1;
+    private int maxHeaderBlockFragment = 0;
+    private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
+
+    public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
+    {
+        this(httpConfiguration,"h2","h2-17","h2-16","h2-15","h2-14");
+    }
+
+    protected AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, String... protocols)
+    {
+        super(protocols);
+        this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
+        addBean(httpConfiguration);
+    }
+
+    @ManagedAttribute("The HPACK dynamic table maximum size")
+    public int getMaxDynamicTableSize()
+    {
+        return maxDynamicTableSize;
+    }
+
+    public void setMaxDynamicTableSize(int maxDynamicTableSize)
+    {
+        this.maxDynamicTableSize = maxDynamicTableSize;
+    }
+
+    @ManagedAttribute("The initial size of stream's flow control send window")
+    public int getInitialStreamSendWindow()
+    {
+        return initialStreamSendWindow;
+    }
+
+    public void setInitialStreamSendWindow(int initialStreamSendWindow)
+    {
+        this.initialStreamSendWindow = initialStreamSendWindow;
+    }
+
+    @ManagedAttribute("The max number of concurrent streams per session")
+    public int getMaxConcurrentStreams()
+    {
+        return maxConcurrentStreams;
+    }
+
+    public void setMaxConcurrentStreams(int maxConcurrentStreams)
+    {
+        this.maxConcurrentStreams = maxConcurrentStreams;
+    }
+
+    public int getMaxHeaderBlockFragment()
+    {
+        return maxHeaderBlockFragment;
+    }
+
+    public void setMaxHeaderBlockFragment(int maxHeaderBlockFragment)
+    {
+        this.maxHeaderBlockFragment = maxHeaderBlockFragment;
+    }
+
+    public FlowControlStrategy.Factory getFlowControlStrategyFactory()
+    {
+        return flowControlStrategyFactory;
+    }
+
+    public void setFlowControlStrategyFactory(FlowControlStrategy.Factory flowControlStrategyFactory)
+    {
+        this.flowControlStrategyFactory = flowControlStrategyFactory;
+    }
+
+    public HttpConfiguration getHttpConfiguration()
+    {
+        return httpConfiguration;
+    }
+
+    @Override
+    public Connection newConnection(Connector connector, EndPoint endPoint)
+    {
+        ServerSessionListener listener = newSessionListener(connector, endPoint);
+
+        Generator generator = new Generator(connector.getByteBufferPool(), getMaxDynamicTableSize(), getMaxHeaderBlockFragment());
+        FlowControlStrategy flowControl = newFlowControlStrategy();
+        if (flowControl == null)
+            flowControl = getFlowControlStrategyFactory().newFlowControlStrategy();
+        HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, flowControl);
+        session.setMaxLocalStreams(getMaxConcurrentStreams());
+        session.setMaxRemoteStreams(getMaxConcurrentStreams());
+        // For a single stream in a connection, there will be a race between
+        // the stream idle timeout and the connection idle timeout. However,
+        // the typical case is that the connection will be busier and the
+        // stream idle timeout will expire earlier that the connection's.
+        session.setStreamIdleTimeout(endPoint.getIdleTimeout());
+
+        ServerParser parser = newServerParser(connector, session);
+        HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
+                        endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
+        connection.addListener(connectionListener);
+        return configure(connection, connector, endPoint);
+    }
+
+    /**
+     * @deprecated use {@link #setFlowControlStrategyFactory(FlowControlStrategy.Factory)} instead
+     */
+    @Deprecated
+    protected FlowControlStrategy newFlowControlStrategy()
+    {
+        return null;
+    }
+
+    protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
+
+    protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
+    {
+        return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
+    }
+
+    private class ConnectionListener implements Connection.Listener
+    {
+        @Override
+        public void onOpened(Connection connection)
+        {
+            addManaged((LifeCycle)((HTTP2Connection)connection).getSession());
+        }
+
+        @Override
+        public void onClosed(Connection connection)
+        {
+            removeBean(((HTTP2Connection)connection).getSession());
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java
new file mode 100644
index 0000000..87bd4e32
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/ByteBufferCallback.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.Callback;
+
+public class ByteBufferCallback implements Callback
+{
+    private final ByteBufferPool byteBufferPool;
+    private final ByteBuffer buffer;
+    private final Callback callback;
+
+    public ByteBufferCallback(ByteBufferPool byteBufferPool, ByteBuffer buffer, Callback callback)
+    {
+        this.byteBufferPool = byteBufferPool;
+        this.buffer = buffer;
+        this.callback = callback;
+    }
+
+    @Override
+    public boolean isNonBlocking()
+    {
+        return callback.isNonBlocking();
+    }
+    
+    public ByteBuffer getByteBuffer()
+    {
+        return buffer;
+    }
+
+    @Override
+    public void succeeded()
+    {
+        recycle();
+        callback.succeeded();
+    }
+
+    @Override
+    public void failed(Throwable x)
+    {
+        recycle();
+        callback.failed(x);
+    }
+
+    private void recycle()
+    {
+        byteBufferPool.release(buffer);
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java
new file mode 100644
index 0000000..874e4ea
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2CServerConnectionFactory.java
@@ -0,0 +1,78 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.MetaData.Request;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** HTTP2 Clear Text Connection factory.
+ * <p>This extension of HTTP2ServerConnection Factory sets the
+ * protocol name to "h2c" as used by the clear text upgrade mechanism
+ * for HTTP2 and marks all TLS ciphers as unacceptable.
+ * </p>
+ * <p>If used in combination with a {@link HttpConnectionFactory} as the
+ * default protocol, this factory can support the non-standard direct
+ * update mechanism, where a HTTP1 request of the form "PRI * HTTP/2.0"
+ * is used to trigger a switch to a HTTP2 connection.    This approach
+ * allows a single port to accept either HTTP/1 or HTTP/2 direct
+ * connections.
+ */
+public class HTTP2CServerConnectionFactory extends HTTP2ServerConnectionFactory implements ConnectionFactory.Upgrading
+{
+    private static final Logger LOG = Log.getLogger(HTTP2CServerConnectionFactory.class);
+
+    public HTTP2CServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
+    {
+        super(httpConfiguration,"h2c","h2c-17","h2c-16","h2c-15","h2c-14");
+    }
+
+    @Override
+    public boolean isAcceptable(String protocol, String tlsProtocol, String tlsCipher)
+    {
+        // Never use TLS with h2c
+        return false;
+    }
+
+    @Override
+    public Connection upgradeConnection(Connector connector, EndPoint endPoint, Request request, HttpFields response101) throws BadMessageException
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} upgraded {}{}", this, request.toString(), request.getFields());
+
+        if (request.getContentLength() > 0)
+            return null;
+
+        HTTP2ServerConnection connection = (HTTP2ServerConnection)newConnection(connector, endPoint);
+        if (connection.upgrade(request))
+            return connection;
+        return null;
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
new file mode 100644
index 0000000..0b97551
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
@@ -0,0 +1,204 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http.MetaData.Request;
+import org.eclipse.jetty.http2.HTTP2Connection;
+import org.eclipse.jetty.http2.ISession;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.parser.ServerParser;
+import org.eclipse.jetty.http2.parser.SettingsBodyParser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.eclipse.jetty.util.TypeUtil;
+
+public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo
+{
+    private final Queue<HttpChannelOverHTTP2> channels = new ConcurrentArrayQueue<>();
+    private final ServerSessionListener listener;
+    private final HttpConfiguration httpConfig;
+    private final List<Frame> upgradeFrames = new ArrayList<>();
+
+    public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener)
+    {
+        super(byteBufferPool, executor, endPoint, parser, session, inputBufferSize);
+        this.listener = listener;
+        this.httpConfig = httpConfig;
+    }
+
+    @Override
+    protected ServerParser getParser()
+    {
+        return (ServerParser)super.getParser();
+    }
+
+    @Override
+    public void onUpgradeTo(ByteBuffer buffer)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP2 onUpgradeTo {} {}", this, BufferUtil.toDetailString(buffer));
+        setInputBuffer(buffer);
+    }
+
+    @Override
+    public void onOpen()
+    {
+        notifyAccept(getSession());
+        for (Frame frame : upgradeFrames)
+            getSession().onFrame(frame);
+        super.onOpen();
+    }
+
+    private void notifyAccept(ISession session)
+    {
+        try
+        {
+            listener.onAccept(session);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+        }
+    }
+
+    public void onNewStream(Connector connector, IStream stream, HeadersFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Processing {} on {}", frame, stream);
+        HttpChannelOverHTTP2 channel = provideHttpChannel(connector, stream);
+        Runnable task = channel.onRequest(frame);
+        if (task != null)
+            offerTask(task, false);
+    }
+
+    public void onData(IStream stream, DataFrame frame, Callback callback)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Processing {} on {}", frame, stream);
+        HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
+        Runnable task = channel.requestContent(frame, callback);
+        if (task != null)
+            offerTask(task, false);
+    }
+
+    public void push(Connector connector, IStream stream, MetaData.Request request)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Processing push {} on {}", request, stream);
+        HttpChannelOverHTTP2 channel = provideHttpChannel(connector, stream);
+        Runnable task = channel.onPushRequest(request);
+        if (task != null)
+            offerTask(task, true);
+    }
+
+    private HttpChannelOverHTTP2 provideHttpChannel(Connector connector, IStream stream)
+    {
+        HttpChannelOverHTTP2 channel = channels.poll();
+        if (channel != null)
+        {
+            channel.getHttpTransport().setStream(stream);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Recycling channel {} for {}", channel, this);
+        }
+        else
+        {
+            HttpTransportOverHTTP2 transport = new HttpTransportOverHTTP2(connector, this);
+            transport.setStream(stream);
+            channel = new ServerHttpChannelOverHTTP2(connector, httpConfig, getEndPoint(), transport);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Creating channel {} for {}", channel, this);
+        }
+        stream.setAttribute(IStream.CHANNEL_ATTRIBUTE, channel);
+        return channel;
+    }
+
+    public boolean upgrade(Request request)
+    {
+        if (HttpMethod.PRI.is(request.getMethod()))
+        {
+            getParser().directUpgrade();
+        }
+        else
+        {
+            HttpField settingsField = request.getFields().getField(HttpHeader.HTTP2_SETTINGS);
+            if (settingsField == null)
+                throw new BadMessageException("Missing " + HttpHeader.HTTP2_SETTINGS + " header");
+            String value = settingsField.getValue();
+            final byte[] settings = B64Code.decodeRFC4648URL(value == null ? "" : value);
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} settings {}",this,TypeUtil.toHexString(settings));
+
+            SettingsFrame settingsFrame = SettingsBodyParser.parseBody(BufferUtil.toBuffer(settings));
+            if (settingsFrame == null)
+            {
+                LOG.warn("Invalid {} header value: {}", HttpHeader.HTTP2_SETTINGS, value);
+                throw new BadMessageException();
+            }
+
+            getParser().standardUpgrade();
+
+            upgradeFrames.add(new PrefaceFrame());
+            upgradeFrames.add(settingsFrame);
+            // Remember the request to send a response from onOpen().
+            upgradeFrames.add(new HeadersFrame(1, request, null, true));
+        }
+        return true;
+    }
+
+    private class ServerHttpChannelOverHTTP2 extends HttpChannelOverHTTP2
+    {
+        public ServerHttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransportOverHTTP2 transport)
+        {
+            super(connector, configuration, endPoint, transport);
+        }
+
+        @Override
+        public void onCompleted()
+        {
+            super.onCompleted();
+            recycle();
+            channels.offer(this);
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java
new file mode 100644
index 0000000..89b2abb
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java
@@ -0,0 +1,150 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.NegotiatingServerConnection.CipherDiscriminator;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory implements CipherDiscriminator
+{
+    private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class);
+
+    public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
+    {
+        super(httpConfiguration);
+    }
+    
+    protected HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration,String... protocols)
+    {
+        super(httpConfiguration,protocols);
+    }
+
+    @Override
+    protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint)
+    {
+        return new HTTPServerSessionListener(connector, endPoint);
+    }
+
+    @Override
+    public boolean isAcceptable(String protocol, String tlsProtocol, String tlsCipher)
+    {
+        // TODO remove this draft 14 protection
+        // Implement 9.2.2
+        boolean acceptable = "h2-14".equals(protocol) || !(HTTP2Cipher.isBlackListProtocol(tlsProtocol) && HTTP2Cipher.isBlackListCipher(tlsCipher));
+        if (LOG.isDebugEnabled())
+            LOG.debug("proto={} tls={} cipher={} 9.2.2-acceptable={}",protocol,tlsProtocol,tlsCipher,acceptable);
+        return acceptable;
+    }
+
+    private class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener
+    {
+        private final Connector connector;
+        private final EndPoint endPoint;
+
+        public HTTPServerSessionListener(Connector connector, EndPoint endPoint)
+        {
+            this.connector = connector;
+            this.endPoint = endPoint;
+        }
+
+        private HTTP2ServerConnection getConnection()
+        {
+            return (HTTP2ServerConnection)endPoint.getConnection();
+        }
+
+        @Override
+        public Map<Integer, Integer> onPreface(Session session)
+        {
+            Map<Integer, Integer> settings = new HashMap<>();
+            settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxDynamicTableSize());
+            settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialStreamSendWindow());
+            int maxConcurrentStreams = getMaxConcurrentStreams();
+            if (maxConcurrentStreams >= 0)
+                settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams);
+            return settings;
+        }
+
+        @Override
+        public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+        {
+            getConnection().onNewStream(connector, (IStream)stream, frame);
+            return frame.isEndStream() ? null : this;
+        }
+
+        @Override
+        public void onHeaders(Stream stream, HeadersFrame frame)
+        {
+            // Servers do not receive responses.
+            close(stream, "response_headers");
+        }
+
+        @Override
+        public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
+        {
+            // Servers do not receive pushes.
+            close(stream, "push_promise");
+            return null;
+        }
+
+        @Override
+        public void onData(Stream stream, DataFrame frame, Callback callback)
+        {
+            getConnection().onData((IStream)stream, frame, callback);
+        }
+
+        @Override
+        public void onReset(Stream stream, ResetFrame frame)
+        {
+            // TODO:
+        }
+
+        @Override
+        public void onTimeout(Stream stream, Throwable x)
+        {
+            // TODO
+        }
+
+        private void close(Stream stream, String reason)
+        {
+            final Session session = stream.getSession();
+            session.close(ErrorCode.PROTOCOL_ERROR.code, reason, Callback.NOOP);
+        }
+    }
+
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java
new file mode 100644
index 0000000..69bf297
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java
@@ -0,0 +1,130 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.FlowControlStrategy;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.Frame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.ServerParser;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Listener
+{
+    private static final Logger LOG = Log.getLogger(HTTP2ServerSession.class);
+
+    private final ServerSessionListener listener;
+
+    public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControlStrategy flowControl)
+    {
+        super(scheduler, endPoint, generator, listener, flowControl, 2);
+        this.listener = listener;
+    }
+
+    @Override
+    public void onPreface()
+    {
+        // SPEC: send a SETTINGS frame upon receiving the preface.
+        Map<Integer, Integer> settings = notifyPreface(this);
+        if (settings == null)
+            settings = Collections.emptyMap();
+        SettingsFrame frame = new SettingsFrame(settings, false);
+        // TODO: consider sending a WINDOW_UPDATE to enlarge the session send window of the client.
+        frames(null, Callback.NOOP, frame, Frame.EMPTY_ARRAY);
+    }
+
+    @Override
+    public void onHeaders(HeadersFrame frame)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Received {}", frame);
+
+        MetaData metaData = frame.getMetaData();
+        if (metaData.isRequest())
+        {
+            IStream stream = createRemoteStream(frame.getStreamId());
+            if (stream != null)
+            {
+                stream.process(frame, Callback.NOOP);
+                Stream.Listener listener = notifyNewStream(stream, frame);
+                stream.setListener(listener);
+            }
+        }
+        else
+        {
+            onConnectionFailure(ErrorCode.INTERNAL_ERROR.code, "invalid_request");
+        }
+    }
+
+    @Override
+    public void onPushPromise(PushPromiseFrame frame)
+    {
+        onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "push_promise");
+    }
+
+    private Map<Integer, Integer> notifyPreface(Session session)
+    {
+        try
+        {
+            return listener.onPreface(session);
+        }
+        catch (Throwable x)
+        {
+            LOG.info("Failure while notifying listener " + listener, x);
+            return null;
+        }
+    }
+
+    @Override
+    public void onFrame(Frame frame)
+    {
+        switch (frame.getType())
+        {
+            case PREFACE:
+                onPreface();
+                break;
+            case SETTINGS:
+                // SPEC: the required reply to this SETTINGS frame is the 101 response.
+                onSettings((SettingsFrame)frame, false);
+                break;
+            case HEADERS:
+                onHeaders((HeadersFrame)frame);
+                break;
+            default:
+                super.onFrame(frame);
+                break;
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java
new file mode 100644
index 0000000..2c9451c
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java
@@ -0,0 +1,249 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpInput;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class HttpChannelOverHTTP2 extends HttpChannel
+{
+    private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class);
+    private static final HttpField SERVER_VERSION = new PreEncodedHttpField(HttpHeader.SERVER, HttpConfiguration.SERVER_VERSION);
+    private static final HttpField POWERED_BY = new PreEncodedHttpField(HttpHeader.X_POWERED_BY, HttpConfiguration.SERVER_VERSION);
+
+    private boolean _expect100Continue;
+    private boolean _delayedUntilContent;
+
+    public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransportOverHTTP2 transport)
+    {
+        super(connector, configuration, endPoint, transport);
+    }
+
+    private IStream getStream()
+    {
+        return getHttpTransport().getStream();
+    }
+
+    @Override
+    public boolean isExpecting100Continue()
+    {
+        return _expect100Continue;
+    }
+
+    public Runnable onRequest(HeadersFrame frame)
+    {
+        MetaData.Request request = (MetaData.Request)frame.getMetaData();
+        HttpFields fields = request.getFields();
+
+        // HTTP/2 sends the Host header as the :authority
+        // pseudo-header, so we need to synthesize a Host header.
+        if (!fields.contains(HttpHeader.HOST))
+        {
+            String authority = request.getURI().getAuthority();
+            if (authority != null)
+            {
+                // Lower-case to be consistent with other HTTP/2 headers.
+                fields.put("host", authority);
+            }
+        }
+
+        _expect100Continue = fields.contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
+
+        HttpFields response = getResponse().getHttpFields();
+        if (getHttpConfiguration().getSendServerVersion())
+            response.add(SERVER_VERSION);
+        if (getHttpConfiguration().getSendXPoweredBy())
+            response.add(POWERED_BY);
+
+        onRequest(request);
+
+        boolean endStream = frame.isEndStream();
+        if (endStream)
+            onRequestComplete();
+
+        _delayedUntilContent = getHttpConfiguration().isDelayDispatchUntilContent() &&
+                !endStream && !_expect100Continue;
+
+        if (LOG.isDebugEnabled())
+        {
+            Stream stream = getStream();
+            LOG.debug("HTTP2 Request #{}/{}, delayed={}:{}{} {} {}{}{}",
+                    stream.getId(), Integer.toHexString(stream.getSession().hashCode()),
+                    _delayedUntilContent, System.lineSeparator(),
+                    request.getMethod(), request.getURI(), request.getVersion(),
+                    System.lineSeparator(), fields);
+        }
+
+        return _delayedUntilContent ? null : this;
+    }
+
+    public Runnable onPushRequest(MetaData.Request request)
+    {
+        onRequest(request);
+        getRequest().setAttribute("org.eclipse.jetty.pushed", Boolean.TRUE);
+        onRequestComplete();
+
+        if (LOG.isDebugEnabled())
+        {
+            Stream stream = getStream();
+            LOG.debug("HTTP2 PUSH Request #{}/{}:{}{} {} {}{}{}",
+                    stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(),
+                    request.getMethod(), request.getURI(), request.getVersion(),
+                    System.lineSeparator(), request.getFields());
+        }
+
+        return this;
+    }
+
+    @Override
+    public HttpTransportOverHTTP2 getHttpTransport()
+    {
+        return (HttpTransportOverHTTP2)super.getHttpTransport();
+    }
+
+    @Override
+    public void recycle()
+    {
+        _expect100Continue = false;
+        _delayedUntilContent = false;
+        super.recycle();
+        getHttpTransport().recycle();
+    }
+
+    @Override
+    protected void commit(MetaData.Response info)
+    {
+        super.commit(info);
+        if (LOG.isDebugEnabled())
+        {
+            Stream stream = getStream();
+            LOG.debug("HTTP2 Commit Response #{}/{}:{}{} {} {}{}{}",
+                    stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(), info.getVersion(), info.getStatus(), info.getReason(),
+                    System.lineSeparator(), info.getFields());
+        }
+    }
+
+    public Runnable requestContent(DataFrame frame, final Callback callback)
+    {
+        // We must copy the data since we do not know when the
+        // application will consume its bytes (we queue them by
+        // calling onContent()), and we cannot stop the parsing
+        // since there may be frames for other streams.
+        final ByteBufferPool byteBufferPool = getByteBufferPool();
+        ByteBuffer original = frame.getData();
+        int length = original.remaining();
+        final ByteBuffer copy = byteBufferPool.acquire(length, original.isDirect());
+        BufferUtil.clearToFill(copy);
+        copy.put(original).flip();
+
+        boolean handle = onContent(new HttpInput.Content(copy)
+        {
+            @Override
+            public boolean isNonBlocking()
+            {
+                return callback.isNonBlocking();
+            }
+
+            @Override
+            public void succeeded()
+            {
+                byteBufferPool.release(copy);
+                callback.succeeded();
+            }
+
+            @Override
+            public void failed(Throwable x)
+            {
+                byteBufferPool.release(copy);
+                callback.failed(x);
+            }
+        });
+
+        boolean endStream = frame.isEndStream();
+        if (endStream)
+            handle |= onRequestComplete();
+
+        if (LOG.isDebugEnabled())
+        {
+            Stream stream = getStream();
+            LOG.debug("HTTP2 Request #{}/{}: {} bytes of {} content, handle: {}",
+                    stream.getId(),
+                    Integer.toHexString(stream.getSession().hashCode()),
+                    length,
+                    endStream ? "last" : "some",
+                    handle);
+        }
+
+        boolean delayed = _delayedUntilContent;
+        _delayedUntilContent = false;
+
+        return handle || delayed ? this : null;
+    }
+
+    /**
+     * If the associated response has the Expect header set to 100 Continue,
+     * then accessing the input stream indicates that the handler/servlet
+     * is ready for the request body and thus a 100 Continue response is sent.
+     *
+     * @throws IOException if the InputStream cannot be created
+     */
+    @Override
+    public void continue100(int available) throws IOException
+    {
+        // If the client is expecting 100 CONTINUE, then send it now.
+        // TODO: consider using an AtomicBoolean ?
+        if (isExpecting100Continue())
+        {
+            _expect100Continue = false;
+
+            // is content missing?
+            if (available == 0)
+            {
+                if (getResponse().isCommitted())
+                    throw new IOException("Committed before 100 Continues");
+
+                boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false);
+                if (!committed)
+                    throw new IOException("Concurrent commit while trying to send 100-Continue");
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
new file mode 100644
index 0000000..102734b
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java
@@ -0,0 +1,231 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.IStream;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PushPromiseFrame;
+import org.eclipse.jetty.http2.frames.ResetFrame;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpTransport;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class HttpTransportOverHTTP2 implements HttpTransport
+{
+    private static final Logger LOG = Log.getLogger(HttpTransportOverHTTP2.class);
+
+    private final AtomicBoolean commit = new AtomicBoolean();
+    private final Callback commitCallback = new CommitCallback();
+    private final Connector connector;
+    private final HTTP2ServerConnection connection;
+    private IStream stream;
+
+    public HttpTransportOverHTTP2(Connector connector, HTTP2ServerConnection connection)
+    {
+        this.connector = connector;
+        this.connection = connection;
+    }
+
+    @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        // Because sent buffers are passed directly to the endpoint without
+        // copying we can defer to the endpoint
+        return connection.getEndPoint().isOptimizedForDirectBuffers();
+    }
+    
+    public IStream getStream()
+    {
+        return stream;
+    }
+
+    public void setStream(IStream stream)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} setStream {}", this, stream.getId());
+        this.stream = stream;
+    }
+
+    public void recycle()
+    {
+        this.stream = null;
+        commit.set(false);
+    }
+
+    @Override
+    public void send(MetaData.Response info, boolean isHeadRequest, ByteBuffer content, boolean lastContent, Callback callback)
+    {
+        // info != null | content != 0 | last = true => commit + send/end
+        // info != null | content != 0 | last = false => commit + send
+        // info != null | content == 0 | last = true => commit/end
+        // info != null | content == 0 | last = false => commit
+        // info == null | content != 0 | last = true => send/end
+        // info == null | content != 0 | last = false => send
+        // info == null | content == 0 | last = true => send/end
+        // info == null | content == 0 | last = false => noop
+
+        boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest;
+
+        if (info != null)
+        {
+            if (commit.compareAndSet(false, true))
+            {
+                if (hasContent)
+                {
+                    commit(info, false, commitCallback);
+                    send(content, lastContent, callback);
+                }
+                else
+                {
+                    commit(info, lastContent, callback);
+                }
+            }
+            else
+            {
+                callback.failed(new IllegalStateException("committed"));
+            }
+        }
+        else
+        {
+            if (hasContent || lastContent)
+            {
+                send(content, lastContent, callback);
+            }
+            else
+            {
+                callback.succeeded();
+            }
+        }
+    }
+
+    @Override
+    public boolean isPushSupported()
+    {
+        return stream.getSession().isPushEnabled();
+    }
+
+    @Override
+    public void push(final MetaData.Request request)
+    {
+        if (!stream.getSession().isPushEnabled())
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("HTTP/2 Push disabled for {}", request);
+            return;
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP/2 Push {}",request);
+        
+        stream.push(new PushPromiseFrame(stream.getId(), 0, request), new Promise<Stream>()
+        {
+            @Override
+            public void succeeded(Stream pushStream)
+            {
+                connection.push(connector, (IStream)pushStream, request);
+            }
+
+            @Override
+            public void failed(Throwable x)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Could not push " + request, x);
+            }
+        }, new Stream.Listener.Adapter()); // TODO: handle reset from the client ?
+    }
+
+    private void commit(MetaData.Response info, boolean endStream, Callback callback)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("HTTP2 Response #{}:{}{} {}{}{}",
+                    stream.getId(), System.lineSeparator(), HttpVersion.HTTP_2, info.getStatus(),
+                    System.lineSeparator(), info.getFields());
+        }
+
+        HeadersFrame frame = new HeadersFrame(stream.getId(), info, null, endStream);
+        stream.headers(frame, callback);
+    }
+
+    private void send(ByteBuffer content, boolean lastContent, Callback callback)
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("HTTP2 Response #{}: {} content bytes{}",
+                    stream.getId(), content.remaining(), lastContent ? " (last chunk)" : "");
+        }
+        DataFrame frame = new DataFrame(stream.getId(), content, lastContent);
+        stream.data(frame, callback);
+    }
+
+    @Override
+    public void onCompleted()
+    {
+        if (!stream.isClosed())
+        {
+            // If the stream is not closed, it is still reading the request content.
+            // Send a reset to the other end so that it stops sending data.
+            stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
+            // Now that this stream is reset, in-flight data frames will be consumed and discarded.
+            // Consume the existing queued data frames to avoid stalling the flow control.
+            HttpChannel channel = (HttpChannel)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
+            channel.getRequest().getHttpInput().consumeAll();
+        }
+    }
+
+    @Override
+    public void abort(Throwable failure)
+    {
+        IStream stream = this.stream;
+        if (LOG.isDebugEnabled())
+            LOG.debug("HTTP2 Response #{} aborted", stream == null ? -1 : stream.getId());
+        if (stream != null)
+            stream.reset(new ResetFrame(stream.getId(), ErrorCode.INTERNAL_ERROR.code), Callback.NOOP);
+    }
+
+    private class CommitCallback implements Callback.NonBlocking
+    {   
+        @Override
+        public void succeeded()
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("HTTP2 Response #{} committed", stream.getId());
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("HTTP2 Response #" + stream.getId() + " failed to commit", x);
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java
new file mode 100644
index 0000000..ab01369
--- /dev/null
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java
@@ -0,0 +1,41 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+
+public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory
+{
+    private final ServerSessionListener listener;
+
+    public RawHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration,ServerSessionListener listener)
+    {
+        super(httpConfiguration);
+        this.listener = listener;
+    }
+
+    @Override
+    protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint)
+    {
+        return listener;
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java
new file mode 100644
index 0000000..e37ec2e
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/AbstractServerTest.java
@@ -0,0 +1,128 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
+
+import javax.servlet.http.HttpServlet;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Rule;
+
+public class AbstractServerTest
+{
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    protected ServerConnector connector;
+    protected ByteBufferPool byteBufferPool;
+    protected Generator generator;
+    protected Server server;
+    protected String path;
+
+    protected void startServer(HttpServlet servlet) throws Exception
+    {
+        prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration()));
+        ServletContextHandler context = new ServletContextHandler(server, "/");
+        context.addServlet(new ServletHolder(servlet), path);
+        server.start();
+    }
+
+    protected void startServer(ServerSessionListener listener) throws Exception
+    {
+        prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(),listener));
+        server.start();
+    }
+
+    private void prepareServer(ConnectionFactory connectionFactory)
+    {
+        QueuedThreadPool serverExecutor = new QueuedThreadPool();
+        serverExecutor.setName("server");
+        server = new Server(serverExecutor);
+        connector = new ServerConnector(server, connectionFactory);
+        server.addConnector(connector);
+        path = "/test";
+        byteBufferPool = new MappedByteBufferPool();
+        generator = new Generator(byteBufferPool);
+    }
+
+    protected MetaData.Request newRequest(String method, HttpFields fields)
+    {
+        String host = "localhost";
+        int port = connector.getLocalPort();
+        String authority = host + ":" + port;
+        return new MetaData.Request(method, HttpScheme.HTTP, new HostPortHttpField(authority), path, HttpVersion.HTTP_2, fields);
+    }
+
+    @After
+    public void dispose() throws Exception
+    {
+        if (server!=null)
+            server.stop();
+    }
+
+    protected boolean parseResponse(Socket client, Parser parser) throws IOException
+    {
+        return parseResponse(client, parser, 1000);
+    }
+
+    protected boolean parseResponse(Socket client, Parser parser, long timeout) throws IOException
+    {
+        byte[] buffer = new byte[2048];
+        InputStream input = client.getInputStream();
+        client.setSoTimeout((int)timeout);
+        while (true)
+        {
+            try
+            {
+                int read = input.read(buffer);
+                if (read < 0)
+                    return true;
+                parser.parse(ByteBuffer.wrap(buffer, 0, read));
+                if (client.isClosed())
+                    return true;
+            }
+            catch (SocketTimeoutException x)
+            {
+                return false;
+            }
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java
new file mode 100644
index 0000000..2acf5a0
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java
@@ -0,0 +1,254 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.HTTP2Session;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.RuntimeIOException;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CloseTest extends AbstractServerTest
+{
+    @Test
+    public void testClientAbruptlyClosesConnection() throws Exception
+    {
+        final CountDownLatch closeLatch = new CountDownLatch(1);
+        final AtomicReference<Session> sessionRef = new AtomicReference<>();
+        startServer(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                try
+                {
+                    sessionRef.set(stream.getSession());
+                    MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                    // Reply with HEADERS.
+                    stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                    closeLatch.await(5, TimeUnit.SECONDS);
+                    return null;
+                }
+                catch (InterruptedException x)
+                {
+                    return null;
+                }
+            }
+        });
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    try
+                    {
+                        // Close the connection just after
+                        // receiving the response headers.
+                        client.close();
+                        closeLatch.countDown();
+                    }
+                    catch (IOException x)
+                    {
+                        throw new RuntimeIOException(x);
+                    }
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            // We need to give some time to the server to receive and process the TCP FIN.
+            Thread.sleep(1000);
+
+            Session session = sessionRef.get();
+            Assert.assertTrue(session.isClosed());
+            Assert.assertTrue(((HTTP2Session)session).isDisconnected());
+        }
+    }
+
+    @Test
+    public void testClientSendsGoAwayButDoesNotCloseConnectionServerCloses() throws Exception
+    {
+        final AtomicReference<Session> sessionRef = new AtomicReference<>();
+        startServer(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                sessionRef.set(stream.getSession());
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                return null;
+            }
+        });
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+        generator.control(lease, new GoAwayFrame(1, ErrorCode.NO_ERROR.code, "OK".getBytes("UTF-8")));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            // Don't close the connection; the server should close.
+
+            final CountDownLatch responseLatch = new CountDownLatch(1);
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    // Even if we sent the GO_AWAY immediately after the
+                    // HEADERS, the server is able to send us the response.
+                    responseLatch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+
+            // Wait for the server to close.
+            Thread.sleep(1000);
+
+            // Client received the TCP FIN from server.
+            Assert.assertEquals(-1, client.getInputStream().read());
+
+            // Server is closed.
+            Session session = sessionRef.get();
+            Assert.assertTrue(session.isClosed());
+            Assert.assertTrue(((HTTP2Session)session).isDisconnected());
+        }
+    }
+
+    @Test
+    public void testServerSendsGoAwayClientDoesNotCloseServerIdleTimeout() throws Exception
+    {
+        final long idleTimeout = 1000;
+        final AtomicReference<Session> sessionRef = new AtomicReference<>();
+        startServer(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                stream.setIdleTimeout(10 * idleTimeout);
+                sessionRef.set(stream.getSession());
+                MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
+                stream.getSession().close(ErrorCode.NO_ERROR.code, "OK", Callback.NOOP);
+                return null;
+            }
+        });
+        connector.setIdleTimeout(idleTimeout);
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            final CountDownLatch responseLatch = new CountDownLatch(1);
+            final CountDownLatch closeLatch = new CountDownLatch(1);
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    responseLatch.countDown();
+                }
+
+                @Override
+                public void onGoAway(GoAwayFrame frame)
+                {
+                    closeLatch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
+            Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
+
+            // Don't close the connection.
+
+            // Wait for the server to idle timeout.
+            Thread.sleep(2 * idleTimeout);
+
+            // Client received the TCP FIN from server.
+            Assert.assertEquals(-1, client.getInputStream().read());
+
+            // Server is closed.
+            Session session = sessionRef.get();
+            Assert.assertTrue(session.isClosed());
+            Assert.assertTrue(((HTTP2Session)session).isDisconnected());
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java
new file mode 100644
index 0000000..5f4c1c0
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServer.java
@@ -0,0 +1,83 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.Date;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SocketCustomizationListener;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+
+public class HTTP2CServer extends Server
+{
+    public HTTP2CServer(int port)
+    {
+        HttpConfiguration config = new HttpConfiguration();
+        // HTTP + HTTP/2 connector
+        
+        HttpConnectionFactory http1 = new HttpConnectionFactory(config);
+        HTTP2CServerConnectionFactory http2c = new HTTP2CServerConnectionFactory(config);
+        ServerConnector connector = new ServerConnector(this,http1,http2c);
+        connector.setPort(port);
+        addConnector(connector);
+
+        ((QueuedThreadPool)getThreadPool()).setName("server");
+
+        setHandler(new SimpleHandler());
+        
+    }
+
+    public static void main(String... args ) throws Exception
+    {
+        HTTP2CServer server = new HTTP2CServer(8080);
+        server.start();
+    }
+
+    private static class SimpleHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            String code=request.getParameter("code");
+            if (code!=null)
+                response.setStatus(Integer.parseInt(code));
+
+            response.setHeader("Custom","Value");
+            response.setContentType("text/plain");
+            String content = "Hello from Jetty using "+request.getProtocol() +"\n";
+            content+="uri="+request.getRequestURI()+"\n";
+            content+="date="+new Date()+"\n";
+            response.setContentLength(content.length());
+            response.getOutputStream().print(content);
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
new file mode 100644
index 0000000..adacd9c
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
@@ -0,0 +1,279 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.server.NetworkConnector;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.Utf8StringBuilder;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class HTTP2CServerTest extends AbstractServerTest
+{
+    private HTTP2CServer _server;
+    private int _port;
+
+    @Before
+    public void before() throws Exception
+    {
+        _server = new HTTP2CServer(0);
+        _server.start();
+        _port = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort();
+    }
+
+    @After
+    public void after() throws Exception
+    {
+        _server.stop();
+    }
+
+    @Test
+    public void testHTTP_1_0_Simple() throws Exception
+    {
+        try (Socket client = new Socket("localhost", _port))
+        {
+            client.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
+            client.getOutputStream().flush();
+
+            String response = IO.toString(client.getInputStream());
+
+            assertThat(response, containsString("HTTP/1.1 200 OK"));
+            assertThat(response, containsString("Hello from Jetty using HTTP/1.0"));
+        }
+    }
+
+    @Test
+    public void testHTTP_1_1_Simple() throws Exception
+    {
+        try (Socket client = new Socket("localhost", _port))
+        {
+            client.getOutputStream().write("GET /one HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
+            client.getOutputStream().write("GET /two HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
+            client.getOutputStream().flush();
+
+            String response = IO.toString(client.getInputStream());
+
+            assertThat(response, containsString("HTTP/1.1 200 OK"));
+            assertThat(response, containsString("Hello from Jetty using HTTP/1.1"));
+            assertThat(response, containsString("uri=/one"));
+            assertThat(response, containsString("uri=/two"));
+        }
+    }
+
+    @Test
+    public void testHTTP_1_1_Upgrade() throws Exception
+    {
+        try (Socket client = new Socket("localhost", _port))
+        {
+            OutputStream output = client.getOutputStream();
+            output.write(("" +
+                    "GET /one HTTP/1.1\r\n" +
+                    "Host: localhost\r\n" +
+                    "Connection: something, else, upgrade, HTTP2-Settings\r\n" +
+                    "Upgrade: h2c\r\n" +
+                    "HTTP2-Settings: \r\n" +
+                    "\r\n").getBytes(StandardCharsets.ISO_8859_1));
+            output.flush();
+
+            InputStream input = client.getInputStream();
+            Utf8StringBuilder upgrade = new Utf8StringBuilder();
+            int crlfs = 0;
+            while (true)
+            {
+                int read = input.read();
+                if (read == '\r' || read == '\n')
+                    ++crlfs;
+                else
+                    crlfs = 0;
+                upgrade.append((byte)read);
+                if (crlfs == 4)
+                    break;
+            }
+
+            assertTrue(upgrade.toString().startsWith("HTTP/1.1 101 "));
+
+            byteBufferPool = new MappedByteBufferPool();
+            generator = new Generator(byteBufferPool);
+
+            final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
+            final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
+            final AtomicReference<CountDownLatch> latchRef = new AtomicReference<>(new CountDownLatch(2));
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    headersRef.set(frame);
+                    latchRef.get().countDown();
+                }
+
+                @Override
+                public void onData(DataFrame frame)
+                {
+                    dataRef.set(frame);
+                    latchRef.get().countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latchRef.get().await(5, TimeUnit.SECONDS));
+
+            HeadersFrame response = headersRef.get();
+            Assert.assertNotNull(response);
+            MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData();
+            Assert.assertEquals(200, responseMetaData.getStatus());
+
+            DataFrame responseData = dataRef.get();
+            Assert.assertNotNull(responseData);
+
+            String content = BufferUtil.toString(responseData.getData());
+
+            // The upgrade request is seen as HTTP/1.1.
+            assertThat(content, containsString("Hello from Jetty using HTTP/1.1"));
+            assertThat(content, containsString("uri=/one"));
+
+            // Send a HTTP/2 request.
+            headersRef.set(null);
+            dataRef.set(null);
+            latchRef.set(new CountDownLatch(2));
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + _port), "/two", HttpVersion.HTTP_2, new HttpFields());
+            generator.control(lease, new HeadersFrame(3, metaData, null, true));
+            for (ByteBuffer buffer : lease.getByteBuffers())
+                output.write(BufferUtil.toArray(buffer));
+            output.flush();
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latchRef.get().await(5, TimeUnit.SECONDS));
+
+            response = headersRef.get();
+            Assert.assertNotNull(response);
+            responseMetaData = (MetaData.Response)response.getMetaData();
+            Assert.assertEquals(200, responseMetaData.getStatus());
+
+            responseData = dataRef.get();
+            Assert.assertNotNull(responseData);
+
+            content = BufferUtil.toString(responseData.getData());
+
+            assertThat(content, containsString("Hello from Jetty using HTTP/2.0"));
+            assertThat(content, containsString("uri=/two"));
+        }
+    }
+
+    @Test
+    public void testHTTP_2_0_Direct() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(3);
+
+        byteBufferPool = new MappedByteBufferPool();
+        generator = new Generator(byteBufferPool);
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + _port), "/test", HttpVersion.HTTP_2, new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", _port))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
+            final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onSettings(SettingsFrame frame)
+                {
+                    latch.countDown();
+                }
+
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    headersRef.set(frame);
+                    latch.countDown();
+                }
+
+                @Override
+                public void onData(DataFrame frame)
+                {
+                    dataRef.set(frame);
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
+            HeadersFrame response = headersRef.get();
+            Assert.assertNotNull(response);
+            MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData();
+            Assert.assertEquals(200, responseMetaData.getStatus());
+
+            DataFrame responseData = dataRef.get();
+            Assert.assertNotNull(responseData);
+
+            String s = BufferUtil.toString(responseData.getData());
+
+            assertThat(s, containsString("Hello from Jetty using HTTP/2.0"));
+            assertThat(s, containsString("uri=/test"));
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java
new file mode 100644
index 0000000..28a04a5
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java
@@ -0,0 +1,588 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.http2.server;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.ErrorCode;
+import org.eclipse.jetty.http2.Flags;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.FrameType;
+import org.eclipse.jetty.http2.frames.GoAwayFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.http2.frames.PingFrame;
+import org.eclipse.jetty.http2.frames.PrefaceFrame;
+import org.eclipse.jetty.http2.frames.PriorityFrame;
+import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.generator.Generator;
+import org.eclipse.jetty.http2.parser.Parser;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.ManagedSelector;
+import org.eclipse.jetty.io.SelectChannelEndPoint;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.StdErrLog;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HTTP2ServerTest extends AbstractServerTest
+{
+    @Test
+    public void testNoPrefaceBytes() throws Exception
+    {
+        startServer(new HttpServlet(){});
+
+        // No preface bytes.
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onGoAway(GoAwayFrame frame)
+                {
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+        }
+    }
+
+    @Test
+    public void testRequestResponseNoContent() throws Exception
+    {
+        final CountDownLatch latch = new CountDownLatch(3);
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                latch.countDown();
+            }
+        });
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            final AtomicReference<HeadersFrame> frameRef = new AtomicReference<>();
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onSettings(SettingsFrame frame)
+                {
+                    latch.countDown();
+                }
+
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    frameRef.set(frame);
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
+            HeadersFrame response = frameRef.get();
+            Assert.assertNotNull(response);
+            MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData();
+            Assert.assertEquals(200, responseMetaData.getStatus());
+        }
+    }
+
+    @Test
+    public void testRequestResponseContent() throws Exception
+    {
+        final byte[] content = "Hello, world!".getBytes(StandardCharsets.UTF_8);
+        final CountDownLatch latch = new CountDownLatch(4);
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                latch.countDown();
+                resp.getOutputStream().write(content);
+            }
+        });
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
+            final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onSettings(SettingsFrame frame)
+                {
+                    latch.countDown();
+                }
+
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    headersRef.set(frame);
+                    latch.countDown();
+                }
+
+                @Override
+                public void onData(DataFrame frame)
+                {
+                    dataRef.set(frame);
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+
+            HeadersFrame response = headersRef.get();
+            Assert.assertNotNull(response);
+            MetaData.Response responseMetaData = (MetaData.Response)response.getMetaData();
+            Assert.assertEquals(200, responseMetaData.getStatus());
+
+            DataFrame responseData = dataRef.get();
+            Assert.assertNotNull(responseData);
+            Assert.assertArrayEquals(content, BufferUtil.toArray(responseData.getData()));
+        }
+    }
+
+    @Test
+    public void testBadPingWrongPayload() throws Exception
+    {
+        startServer(new HttpServlet(){});
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        generator.control(lease, new PingFrame(new byte[8], false));
+        // Modify the length of the frame to a wrong one.
+        lease.getByteBuffers().get(2).putShort(0, (short)7);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onGoAway(GoAwayFrame frame)
+                {
+                    Assert.assertEquals(ErrorCode.FRAME_SIZE_ERROR.code, frame.getError());
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+        }
+    }
+
+    @Test
+    public void testBadPingWrongStreamId() throws Exception
+    {
+        startServer(new HttpServlet(){});
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        generator.control(lease, new PingFrame(new byte[8], false));
+        // Modify the streamId of the frame to non zero.
+        lease.getByteBuffers().get(2).putInt(4, 1);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+            {
+                output.write(BufferUtil.toArray(buffer));
+            }
+
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onGoAway(GoAwayFrame frame)
+                {
+                    Assert.assertEquals(ErrorCode.PROTOCOL_ERROR.code, frame.getError());
+                    latch.countDown();
+                }
+            }, 4096, 8192);
+
+            parseResponse(client, parser);
+
+            Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+        }
+    }
+
+    @Test
+    public void testCommitFailure() throws Exception
+    {
+        final long delay = 1000;
+        final AtomicBoolean broken = new AtomicBoolean();
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+            {
+                try
+                {
+                    // Wait for the SETTINGS frames to be exchanged.
+                    Thread.sleep(delay);
+                    broken.set(true);
+                }
+                catch (InterruptedException x)
+                {
+                    throw new InterruptedIOException();
+                }
+            }
+        });
+        server.stop();
+
+        ServerConnector connector2 = new ServerConnector(server, new HTTP2ServerConnectionFactory(new HttpConfiguration()))
+        {
+            @Override
+            protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
+            {
+                return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout())
+                {
+                    @Override
+                    public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
+                    {
+                        if (broken.get())
+                            callback.failed(new IOException("explicitly_thrown_by_test"));
+                        else
+                            super.write(callback, buffers);
+                    }
+                };
+            }
+        };
+        server.addConnector(connector2);
+        server.start();
+
+        ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+        generator.control(lease, new PrefaceFrame());
+        generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+        MetaData.Request metaData = newRequest("GET", new HttpFields());
+        generator.control(lease, new HeadersFrame(1, metaData, null, true));
+        try (Socket client = new Socket("localhost", connector2.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+                output.write(BufferUtil.toArray(buffer));
+
+            // The server will close the connection abruptly since it
+            // cannot write and therefore cannot even send the GO_AWAY.
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
+            boolean closed = parseResponse(client, parser, 2 * delay);
+            Assert.assertTrue(closed);
+        }
+    }
+
+    @Test
+    public void testNonISOHeader() throws Exception
+    {
+        StdErrLog logger = StdErrLog.getLogger(HttpChannel.class);
+        logger.setHideStacks(true);
+        try
+        {
+            startServer(new HttpServlet()
+            {
+                @Override
+                protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+                {
+                    // Invalid header name, the connection must be closed.
+                    response.setHeader("Euro_(\u20AC)", "42");
+                }
+            });
+
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, null, true));
+
+            try (Socket client = new Socket("localhost", connector.getLocalPort()))
+            {
+                OutputStream output = client.getOutputStream();
+                for (ByteBuffer buffer : lease.getByteBuffers())
+                    output.write(BufferUtil.toArray(buffer));
+                output.flush();
+
+                Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192);
+                boolean closed = parseResponse(client, parser);
+
+                Assert.assertTrue(closed);
+            }
+        }
+        finally
+        {
+            logger.setHideStacks(false);
+        }
+    }
+
+    @Test
+    public void testRequestWithContinuationFrames() throws Exception
+    {
+        testRequestWithContinuationFrames(null, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, null, true));
+            return lease;
+        });
+    }
+
+    @Test
+    public void testRequestWithPriorityWithContinuationFrames() throws Exception
+    {
+        PriorityFrame priority = new PriorityFrame(1, 13, 200, true);
+        testRequestWithContinuationFrames(priority, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, priority, true));
+            return lease;
+        });
+    }
+
+    @Test
+    public void testRequestWithContinuationFramesWithEmptyHeadersFrame() throws Exception
+    {
+        testRequestWithContinuationFrames(null, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, null, true));
+            // Take the HeadersFrame header and set the length to zero.
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            ByteBuffer headersFrameHeader = buffers.get(2);
+            headersFrameHeader.put(0, (byte)0);
+            headersFrameHeader.putShort(1, (short)0);
+            // Insert a CONTINUATION frame header for the body of the HEADERS frame.
+            lease.insert(3, buffers.get(4).slice(), false);
+            return lease;
+        });
+    }
+
+    @Test
+    public void testRequestWithPriorityWithContinuationFramesWithEmptyHeadersFrame() throws Exception
+    {
+        PriorityFrame priority = new PriorityFrame(1, 13, 200, true);
+        testRequestWithContinuationFrames(null, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, priority, true));
+            // Take the HeadersFrame header and set the length to just the priority frame.
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            ByteBuffer headersFrameHeader = buffers.get(2);
+            headersFrameHeader.put(0, (byte)0);
+            headersFrameHeader.putShort(1, (short)PriorityFrame.PRIORITY_LENGTH);
+            // Insert a CONTINUATION frame header for the body of the HEADERS frame.
+            lease.insert(3, buffers.get(4).slice(), false);
+            return lease;
+        });
+    }
+
+    @Test
+    public void testRequestWithContinuationFramesWithEmptyContinuationFrame() throws Exception
+    {
+        testRequestWithContinuationFrames(null, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, null, true));
+            // Take the ContinuationFrame header, duplicate it, and set the length to zero.
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            ByteBuffer continuationFrameHeader = buffers.get(4);
+            ByteBuffer duplicate = ByteBuffer.allocate(continuationFrameHeader.remaining());
+            duplicate.put(continuationFrameHeader).flip();
+            continuationFrameHeader.flip();
+            continuationFrameHeader.put(0, (byte)0);
+            continuationFrameHeader.putShort(1, (short)0);
+            // Insert a CONTINUATION frame header for the body of the previous CONTINUATION frame.
+            lease.insert(5, duplicate, false);
+            return lease;
+        });
+    }
+
+    @Test
+    public void testRequestWithContinuationFramesWithEmptyLastContinuationFrame() throws Exception
+    {
+        testRequestWithContinuationFrames(null, () ->
+        {
+            ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
+            generator.control(lease, new PrefaceFrame());
+            generator.control(lease, new SettingsFrame(new HashMap<>(), false));
+            MetaData.Request metaData = newRequest("GET", new HttpFields());
+            generator.control(lease, new HeadersFrame(1, metaData, null, true));
+            // Take the last CONTINUATION frame and reset the flag.
+            List<ByteBuffer> buffers = lease.getByteBuffers();
+            ByteBuffer continuationFrameHeader = buffers.get(buffers.size() - 2);
+            continuationFrameHeader.put(4, (byte)0);
+            // Add a last, empty, CONTINUATION frame.
+            ByteBuffer last = ByteBuffer.wrap(new byte[]{
+                    0, 0, 0, // Length
+                    (byte)FrameType.CONTINUATION.getType(),
+                    (byte)Flags.END_HEADERS,
+                    0, 0, 0, 1 // Stream ID
+            });
+            lease.append(last, false);
+            return lease;
+        });
+    }
+
+    private void testRequestWithContinuationFrames(PriorityFrame priorityFrame, Callable<ByteBufferPool.Lease> frames) throws Exception
+    {
+        final CountDownLatch serverLatch = new CountDownLatch(1);
+        startServer(new ServerSessionListener.Adapter()
+        {
+            @Override
+            public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+            {
+                if (priorityFrame != null)
+                {
+                    PriorityFrame priority = frame.getPriority();
+                    Assert.assertNotNull(priority);
+                    Assert.assertEquals(priorityFrame.getStreamId(), priority.getStreamId());
+                    Assert.assertEquals(priorityFrame.getParentStreamId(), priority.getParentStreamId());
+                    Assert.assertEquals(priorityFrame.getWeight(), priority.getWeight());
+                    Assert.assertEquals(priorityFrame.isExclusive(), priority.isExclusive());
+                }
+
+                serverLatch.countDown();
+
+                MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
+                HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
+                stream.headers(responseFrame, Callback.NOOP);
+                return null;
+            }
+        });
+        generator = new Generator(byteBufferPool, 4096, 4);
+
+        ByteBufferPool.Lease lease = frames.call();
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            for (ByteBuffer buffer : lease.getByteBuffers())
+                output.write(BufferUtil.toArray(buffer));
+            output.flush();
+
+            Assert.assertTrue(serverLatch.await(5, TimeUnit.SECONDS));
+
+            final CountDownLatch clientLatch = new CountDownLatch(1);
+            Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
+            {
+                @Override
+                public void onHeaders(HeadersFrame frame)
+                {
+                    if (frame.isEndStream())
+                        clientLatch.countDown();
+                }
+            }, 4096, 8192);
+            boolean closed = parseResponse(client, parser);
+
+            Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS));
+            Assert.assertFalse(closed);
+        }
+    }
+}
diff --git a/jetty-http2/http2-server/src/test/resources/jetty-logging.properties b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..13f7aba
--- /dev/null
+++ b/jetty-http2/http2-server/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.LEVEL=DEBUG
diff --git a/jetty-http2/pom.xml b/jetty-http2/pom.xml
new file mode 100644
index 0000000..6887506
--- /dev/null
+++ b/jetty-http2/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>jetty-project</artifactId>
+    <groupId>org.eclipse.jetty</groupId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.eclipse.jetty.http2</groupId>
+  <artifactId>http2-parent</artifactId>
+  <packaging>pom</packaging>
+  <name>Jetty :: HTTP2</name>
+
+  <modules>
+    <module>http2-alpn-tests</module>
+    <module>http2-client</module>
+    <module>http2-common</module>
+    <module>http2-hpack</module>
+    <module>http2-http-client-transport</module>
+    <module>http2-server</module>
+  </modules>
+
+</project>
diff --git a/jetty-infinispan/pom.xml b/jetty-infinispan/pom.xml
new file mode 100644
index 0000000..28ed8c8
--- /dev/null
+++ b/jetty-infinispan/pom.xml
@@ -0,0 +1,66 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.eclipse.jetty</groupId>
+    <artifactId>jetty-project</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>jetty-infinispan</artifactId>
+  <name>Jetty :: Infinispan Session Managers</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.infinispan</bundle-symbolic-name>
+    <infinispan.version>7.1.1.Final</infinispan.version>
+  </properties>
+  <build>
+    <defaultGoal>install</defaultGoal>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptorRefs>
+                <descriptorRef>config</descriptorRef>
+              </descriptorRefs>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>artifact-jar</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+          </archive>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+         <groupId>org.infinispan</groupId>
+         <artifactId>infinispan-core</artifactId>
+         <version>${infinispan.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.eclipse.jetty</groupId>
+       <artifactId>jetty-server</artifactId>
+       <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/jetty-infinispan/src/main/config/etc/jetty-infinispan.xml b/jetty-infinispan/src/main/config/etc/jetty-infinispan.xml
new file mode 100644
index 0000000..49d7ab6
--- /dev/null
+++ b/jetty-infinispan/src/main/config/etc/jetty-infinispan.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- ===================================================================== -->
+  <!-- Get a reference to the default local cache.                           -->
+  <!-- ===================================================================== -->
+  <New id="local" class="org.infinispan.manager.DefaultCacheManager">
+     <Get id="cache" name="cache"></Get>
+  </New>
+
+  <!-- ===================================================================== -->
+  <!-- Get a reference to a hotrod client for a remote cache.               -->
+  <!-- Change the name of the cache to match your setup.                    -->
+  <!-- ===================================================================== -->
+  <!--
+  <New id="hotrodMgr" class="org.infinispan.client.hotrod.RemoteCacheManager">
+    <Call id="cache" name="getCache">
+      <Arg>sessions</Arg>
+    </Call>
+  </New>
+  -->
+
+
+  <!-- ===================================================================== -->
+  <!-- Configure a SessionIdManager with the cache selected above.          -->
+  <!-- ===================================================================== -->
+  <Set name="sessionIdManager">
+    <New id="idMgr" class="org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager">
+      <Arg>
+        <Ref refid="Server"/>
+      </Arg>
+      <Set name="workerName"><Property name="jetty.infinispanSession.workerName" default="node1"/></Set>
+      <Set name="cache"><Ref refid="cache"/></Set>
+    </New>
+  </Set>
+
+</Configure>
diff --git a/jetty-infinispan/src/main/config/modules/infinispan.mod b/jetty-infinispan/src/main/config/modules/infinispan.mod
new file mode 100644
index 0000000..afa39fc
--- /dev/null
+++ b/jetty-infinispan/src/main/config/modules/infinispan.mod
@@ -0,0 +1,33 @@
+#
+# Jetty Infinispan module
+#
+
+[depend]
+annotations
+webapp
+
+[files]
+maven://org.infinispan/infinispan-core/7.1.1.Final|lib/infinispan/infinispan-core-7.1.1.Final.jar
+maven://org.infinispan/infinispan-commons/7.1.1.Final|lib/infinispan/infinispan-commons-7.1.1.Final.jar
+maven://org.jgroups/jgroups/3.6.1.Final|lib/infinispan/jgroups-3.6.1.Final.jar
+maven://org.jboss.marshalling/jboss-marshalling-osgi/1.4.4.Final|lib/infinispan/jboss-marshalling-osgi-1.4.4.Final.jar
+maven://org.jboss.logging/jboss-logging/3.1.2.GA|lib/infinispan/jboss-logging-3.1.2.GA.jar
+
+[lib]
+lib/jetty-infinispan-${jetty.version}.jar
+lib/infinispan/*.jar
+
+[xml]
+etc/jetty-infinispan.xml
+
+[license]
+Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+http://infinispan.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini-template]
+## Infinispan Session config
+
+## Unique identifier for this node in the cluster
+# jetty.infinispanSession.workerName=node1
+
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java
new file mode 100644
index 0000000..4dfd6c0
--- /dev/null
+++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java
@@ -0,0 +1,374 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.session.infinispan;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.session.AbstractSession;
+import org.eclipse.jetty.server.session.AbstractSessionIdManager;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.infinispan.commons.api.BasicCache;
+
+
+
+
+/**
+ * InfinispanSessionIdManager
+ *
+ * Maintain a set of in-use session ids. This session id manager does NOT locally store 
+ * a list of in-use sesssion ids, but rather stores them in the cluster cache. Thus,
+ * all operations to this session manager involve interaction with a possibly remote
+ * cache.
+ * 
+ * For each session id that is in-use, an entry of the following form is put into 
+ * the cluster cache:
+ * <pre>
+ *   ("__o.e.j.s.infinispanIdMgr__"+[id], [id])
+ * </pre>
+ * where [id] is the id of the session.
+ * 
+ * If the first session to be added is not immortal (ie it has a timeout on it) then
+ * the corresponding session id is entered into infinispan with an idle expiry timeout
+ * equivalent to double the session's timeout (the multiplier is configurable).
+ * 
+ * 
+ * Having one entry per in-use session id means that there is no contention on
+ * cache entries (as would be the case if a single entry was kept containing a 
+ * list of in-use session ids).
+ * 
+ * 
+ */
+public class InfinispanSessionIdManager extends AbstractSessionIdManager
+{
+    private  final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
+    public final static String ID_KEY = "__o.e.j.s.infinispanIdMgr__";
+    public static final int DEFAULT_IDLE_EXPIRY_MULTIPLE = 2;
+    protected BasicCache<String,Object> _cache;
+    private Server _server;
+    private int _idleExpiryMultiple = DEFAULT_IDLE_EXPIRY_MULTIPLE;
+
+    
+    
+    
+    
+    public InfinispanSessionIdManager(Server server)
+    {
+        super();
+        _server = server;
+    }
+
+    public InfinispanSessionIdManager(Server server, Random random)
+    {
+       super(random);
+       _server = server;
+    }
+
+    
+    
+    /** 
+     * Start the id manager.
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStart()
+     */
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+    }
+
+    
+    
+    /** 
+     * Stop the id manager
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#doStop()
+     */
+    @Override
+    protected void doStop() throws Exception
+    {
+        super.doStop();
+    }
+
+    
+   
+
+    
+    /** 
+     * Check to see if the given session id is being
+     * used by a session in any context.
+     * 
+     * This method will consult the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#idInUse(java.lang.String)
+     */
+    @Override
+    public boolean idInUse(String id)
+    {
+        if (id == null)
+            return false;
+        
+        String clusterId = getClusterId(id);
+        
+        //ask the cluster - this should also tickle the idle expiration timer on the sessionid entry
+        //keeping it valid
+        try
+        {
+            return exists(clusterId);
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Problem checking inUse for id="+clusterId, e);
+            return false;
+        }
+        
+    }
+
+    /** 
+     * Remember a new in-use session id.
+     * 
+     * This will save the in-use session id to the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#addSession(javax.servlet.http.HttpSession)
+     */
+    @Override
+    public void addSession(HttpSession session)
+    {
+        if (session == null)
+            return;
+
+        //insert into the cache and set an idle expiry on the entry that
+        //is based off the max idle time configured for the session. If the
+        //session is immortal, then there is no idle expiry on the corresponding
+        //session id
+        if (session.getMaxInactiveInterval() == 0)
+            insert (((AbstractSession)session).getClusterId());
+        else
+            insert (((AbstractSession)session).getClusterId(), session.getMaxInactiveInterval() * getIdleExpiryMultiple());
+    }
+    
+    
+    public void setIdleExpiryMultiple (int multiplier)
+    {
+        if (multiplier <= 1)
+        {
+            LOG.warn("Idle expiry multiple of {} for session ids set to less than minimum. Using value of {} instead.", multiplier, DEFAULT_IDLE_EXPIRY_MULTIPLE);
+        }
+        _idleExpiryMultiple = multiplier;
+    }
+
+    public int getIdleExpiryMultiple ()
+    {
+        return _idleExpiryMultiple;
+    }
+    
+    
+    /** 
+     * Remove a session id from the list of in-use ids.
+     * 
+     * This will remvove the corresponding session id from the cluster.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#removeSession(javax.servlet.http.HttpSession)
+     */
+    @Override
+    public void removeSession(HttpSession session)
+    {
+        if (session == null)
+            return;
+
+        //delete from the cache
+        delete (((AbstractSession)session).getClusterId());
+    }
+
+    /** 
+     * Remove a session id. This compels all other contexts who have a session
+     * with the same id to also remove it.
+     * 
+     * @see org.eclipse.jetty.server.SessionIdManager#invalidateAll(java.lang.String)
+     */
+    @Override
+    public void invalidateAll(String id)
+    {
+        //delete the session id from list of in-use sessions
+        delete (id);
+
+
+        //tell all contexts that may have a session object with this id to
+        //get rid of them
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
+        {
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null)
+            {
+                SessionManager manager = sessionHandler.getSessionManager();
+
+                if (manager != null && manager instanceof InfinispanSessionManager)
+                {
+                    ((InfinispanSessionManager)manager).invalidateSession(id);
+                }
+            }
+        }
+
+    }
+
+    /** 
+     * Change a session id. 
+     * 
+     * Typically this occurs when a previously existing session has passed through authentication.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionIdManager#renewSessionId(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest)
+     */
+    @Override
+    public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request)
+    {
+        //generate a new id
+        String newClusterId = newSessionId(request.hashCode());
+
+        delete(oldClusterId);
+        insert(newClusterId);
+
+
+        //tell all contexts to update the id 
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
+        {
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null) 
+            {
+                SessionManager manager = sessionHandler.getSessionManager();
+
+                if (manager != null && manager instanceof InfinispanSessionManager)
+                {
+                    ((InfinispanSessionManager)manager).renewSessionId(oldClusterId, oldNodeId, newClusterId, getNodeId(newClusterId, request));
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Get the cache.
+     * @return the cache
+     */
+    public BasicCache<String,Object> getCache() 
+    {
+        return _cache;
+    }
+
+    /**
+     * Set the cache.
+     * @param cache the cache
+     */
+    public void setCache(BasicCache<String,Object> cache) 
+    {
+        this._cache = cache;
+    }
+    
+    
+    
+    /**
+     * Do any operation to the session id in the cache to
+     * ensure its idle expiry time moves forward
+     * @param id the session id
+     */
+    public void touch (String id)
+    {
+        exists(id);
+    }
+    
+    
+    
+    /**
+     * Ask the cluster if a particular id exists.
+     * 
+     * @param id the session id
+     * @return true if exists
+     */
+    protected boolean exists (String id)
+    {
+        if (_cache == null)
+            throw new IllegalStateException ("No cache");
+        
+        return _cache.containsKey(makeKey(id));
+    }
+    
+
+    /**
+     * Put a session id into the cluster.
+     * 
+     * @param id the session id
+     */
+    protected void insert (String id)
+    {        
+        if (_cache == null)
+            throw new IllegalStateException ("No cache");
+        
+        _cache.putIfAbsent(makeKey(id), id);
+    }
+    
+    
+    /**
+     * Put a session id into the cluster with an idle expiry.
+     * 
+     * @param id the session id
+     * @param idleTimeOutSec idle timeout in seconds
+     */
+    protected void insert (String id, long idleTimeOutSec)
+    {
+        if (_cache == null)
+            throw new IllegalStateException ("No cache");
+        
+        _cache.putIfAbsent(makeKey(id),id,-1L, TimeUnit.SECONDS, idleTimeOutSec, TimeUnit.SECONDS);
+    }
+   
+    
+    /**
+     * Remove a session id from the cluster.
+     * 
+     * @param id the session id
+     */
+    protected void delete (String id)
+    {
+        if (_cache == null)
+            throw new IllegalStateException ("No cache");
+        
+        _cache.remove(makeKey(id));
+    }
+    
+    
+
+    /**
+     * Generate a unique cache key from the session id.
+     * 
+     * @param id the session id
+     * @return unique cache id
+     */
+    protected String makeKey (String id)
+    {
+        return ID_KEY+id;
+    }
+}
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java
new file mode 100644
index 0000000..ef635fe
--- /dev/null
+++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java
@@ -0,0 +1,1170 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.session.infinispan;
+
+import java.io.IOException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandler.Context;
+import org.eclipse.jetty.server.session.AbstractSession;
+import org.eclipse.jetty.server.session.AbstractSessionManager;
+import org.eclipse.jetty.server.session.MemSession;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
+import org.eclipse.jetty.util.thread.Scheduler;
+import org.infinispan.Cache;
+import org.infinispan.commons.api.BasicCache;
+import org.omg.CORBA._IDLTypeStub;
+
+/**
+ * InfinispanSessionManager
+ * 
+ * The data for a session relevant to a particular context is stored in an Infinispan (clustered) cache:
+ * <pre>
+ * Key:   is the id of the session + the context path + the vhost for the context 
+ * Value: is the data of the session
+ * </pre>
+ * 
+ * The key is necessarily complex because the same session id can be in-use by more than one
+ * context. In this case, the contents of the session will strictly be different for each
+ * context, although the id will be the same.
+ * 
+ * Sessions are also kept in local memory when they are used by this session manager. This allows
+ * multiple different request threads in the same context to call Request.getSession() and
+ * obtain the same object.
+ * 
+ * This session manager support scavenging, which is only done over the set of sessions in its
+ * local memory. This can result in some sessions being "stranded" in the cluster cache if no
+ * session manager is currently managing it (eg the node managing the session crashed and it
+ * was never requested on another node).
+ * 
+ */
+public class InfinispanSessionManager extends AbstractSessionManager
+{
+    private  final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
+    
+    /**
+     * Clustered cache of sessions
+     */
+    private BasicCache<String, Object> _cache;
+    
+    
+    /**
+     * Sessions known to this node held in memory
+     */
+    private ConcurrentHashMap<String, InfinispanSessionManager.Session> _sessions;
+
+    
+    /**
+     * The length of time a session can be in memory without being checked against
+     * the cluster. A value of 0 indicates that the session is never checked against
+     * the cluster - the current node is considered to be the master for the session.
+     *
+     */
+    private long _staleIntervalSec = 0;
+    
+    protected Scheduler.Task _task; //scavenge task
+    protected Scheduler _scheduler;
+    protected Scavenger _scavenger;
+    protected long _scavengeIntervalMs = 1000L * 60 * 10; //10mins
+    protected boolean _ownScheduler;
+    
+    
+
+    /**
+     * Scavenger
+     *
+     */
+    protected class Scavenger implements Runnable
+    {
+
+        @Override
+        public void run()
+        {
+           try
+           {
+               scavenge();
+           }
+           finally
+           {
+               if (_scheduler != null && _scheduler.isRunning())
+                   _task = _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS);
+           }
+        }
+    }
+    
+    
+    /*
+     * Every time a Session is put into the cache one of these objects
+     * is created to copy the data out of the in-memory session, and 
+     * every time an object is read from the cache one of these objects
+     * a fresh Session object is created based on the data held by this
+     * object.
+     */
+    public class SerializableSessionData implements Serializable
+    {
+        /**
+         * 
+         */
+        private static final long serialVersionUID = -7779120106058533486L;
+        String clusterId;
+        String contextPath;
+        String vhost;
+        long accessed;
+        long lastAccessed;
+        long createTime;
+        long cookieSetTime;
+        String lastNode;
+        long expiry;
+        long maxInactive;
+        Map<String, Object> attributes;
+
+        public SerializableSessionData()
+        {
+
+        }
+
+       
+       public SerializableSessionData(Session s)
+       {
+           clusterId = s.getClusterId();
+           contextPath = s.getContextPath();
+           vhost = s.getVHost();
+           accessed = s.getAccessed();
+           lastAccessed = s.getLastAccessedTime();
+           createTime = s.getCreationTime();
+           cookieSetTime = s.getCookieSetTime();
+           lastNode = s.getLastNode();
+           expiry = s.getExpiry();
+           maxInactive = s.getMaxInactiveInterval();
+           attributes = s.getAttributeMap(); // TODO pointer, not a copy
+       }
+        
+        private void writeObject(java.io.ObjectOutputStream out) throws IOException
+        {  
+            out.writeUTF(clusterId); //session id
+            out.writeUTF(contextPath); //context path
+            out.writeUTF(vhost); //first vhost
+
+            out.writeLong(accessed);//accessTime
+            out.writeLong(lastAccessed); //lastAccessTime
+            out.writeLong(createTime); //time created
+            out.writeLong(cookieSetTime);//time cookie was set
+            out.writeUTF(lastNode); //name of last node managing
+      
+            out.writeLong(expiry); 
+            out.writeLong(maxInactive);
+            out.writeObject(attributes);
+        }
+        
+        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
+        {
+            clusterId = in.readUTF();
+            contextPath = in.readUTF();
+            vhost = in.readUTF();
+            
+            accessed = in.readLong();//accessTime
+            lastAccessed = in.readLong(); //lastAccessTime
+            createTime = in.readLong(); //time created
+            cookieSetTime = in.readLong();//time cookie was set
+            lastNode = in.readUTF(); //last managing node
+            expiry = in.readLong(); 
+            maxInactive = in.readLong();
+            attributes = (HashMap<String,Object>)in.readObject();
+        }
+        
+    }
+    
+ 
+    
+    
+    /**
+     * Session
+     *
+     * Representation of a session in local memory.
+     */
+    public class Session extends MemSession
+    {
+        
+        private ReentrantLock _lock = new ReentrantLock();
+        
+        /**
+         * The (canonical) context path for with which this session is associated
+         */
+        private String _contextPath;
+        
+        
+        
+        /**
+         * The time in msec since the epoch at which this session should expire
+         */
+        private long _expiryTime; 
+        
+        
+        /**
+         * Time in msec since the epoch at which this session was last read from cluster
+         */
+        private long _lastSyncTime;
+        
+        
+        /**
+         * The workername of last node known to be managing the session
+         */
+        private String _lastNode;
+        
+        
+        /**
+         * If dirty, session needs to be (re)sent to cluster
+         */
+        protected boolean _dirty=false;
+        
+        
+     
+
+        /**
+         * Any virtual hosts for the context with which this session is associated
+         */
+        private String _vhost;
+
+        
+        /**
+         * Count of how many threads are active in this session
+         */
+        private AtomicInteger _activeThreads = new AtomicInteger(0);
+        
+        
+        
+        
+        /**
+         * A new session.
+         * 
+         * @param request the request
+         */
+        protected Session (HttpServletRequest request)
+        {
+            super(InfinispanSessionManager.this,request);
+            long maxInterval = getMaxInactiveInterval();
+            _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L));
+            _lastNode = getSessionIdManager().getWorkerName();
+           setVHost(InfinispanSessionManager.getVirtualHost(_context));
+           setContextPath(InfinispanSessionManager.getContextPath(_context));
+           _activeThreads.incrementAndGet(); //access will not be called on a freshly created session so increment here
+        }
+        
+        
+        protected Session (SerializableSessionData sd)
+        {
+            super(InfinispanSessionManager.this, sd.createTime, sd.accessed, sd.clusterId);
+            _expiryTime = (sd.maxInactive <= 0 ? 0 : (System.currentTimeMillis() + sd.maxInactive*1000L));
+            setLastNode(sd.lastNode);
+            setContextPath(sd.contextPath);
+            setVHost(sd.vhost);
+            addAttributes(sd.attributes);
+        }
+        
+        
+        /**
+         * A restored session.
+         * 
+         * @param sessionId the session id
+         * @param created time created
+         * @param accessed time last accessed
+         * @param maxInterval max expiry interval
+         */
+        protected Session (String sessionId, long created, long accessed, long maxInterval)
+        {
+            super(InfinispanSessionManager.this, created, accessed, sessionId);
+            _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L));
+        }
+        
+        /** 
+         * Called on entry to the session.
+         * 
+         * @see org.eclipse.jetty.server.session.AbstractSession#access(long)
+         */
+        @Override
+        protected boolean access(long time)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Access session({}) for context {} on worker {}", getId(), getContextPath(), getSessionIdManager().getWorkerName());
+            try
+            {
+
+                long now = System.currentTimeMillis();
+                //lock so that no other thread can call access or complete until the first one has refreshed the session object if necessary
+                _lock.lock();
+                //a request thread is entering
+                if (_activeThreads.incrementAndGet() == 1)
+                {
+                    //if the first thread, check that the session in memory is not stale, if we're checking for stale sessions
+                    if (getStaleIntervalSec() > 0  && (now - getLastSyncTime()) >= (getStaleIntervalSec() * 1000L))
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Acess session({}) for context {} on worker {} stale session. Reloading.", getId(), getContextPath(), getSessionIdManager().getWorkerName());
+                        refresh();
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+            }
+            finally
+            {            
+                _lock.unlock();
+            }
+
+            if (super.access(time))
+            {
+                int maxInterval=getMaxInactiveInterval();
+                _expiryTime = (maxInterval <= 0 ? 0 : (time + maxInterval*1000L));
+                return true;
+            }
+            return false;
+        }
+
+
+        /**
+         * Exit from session
+         * @see org.eclipse.jetty.server.session.AbstractSession#complete()
+         */
+        @Override
+        protected void complete()
+        {
+            super.complete();
+
+            //lock so that no other thread that might be calling access can proceed until this complete is done
+            _lock.lock();
+
+            try
+            {
+                //if this is the last request thread to be in the session
+                if (_activeThreads.decrementAndGet() == 0)
+                {
+                    try
+                    {
+                        //an invalid session will already have been removed from the
+                        //local session map and deleted from the cluster. If its valid save
+                        //it to the cluster.
+                        //TODO consider doing only periodic saves if only the last access
+                        //time to the session changes
+                        if (isValid())
+                        {
+                            //if session still valid && its dirty or stale or never been synced, write it to the cluster
+                            //otherwise, we just keep the updated last access time in memory
+                            if (_dirty || getLastSyncTime() == 0 || isStale(System.currentTimeMillis()))
+                            {
+                                willPassivate();
+                                save(this);
+                                didActivate();
+                            }
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        LOG.warn("Problem saving session({})",getId(), e);
+                    } 
+                    finally
+                    {
+                        _dirty = false;
+                    }
+                }
+            }
+            finally
+            {
+                _lock.unlock();
+            }
+        }
+        
+        /** Test if the session is stale
+         * @param atTime time when stale
+         * @return true if stale
+         */
+        protected boolean isStale (long atTime)
+        {
+            return (getStaleIntervalSec() > 0) && (atTime - getLastSyncTime() >= (getStaleIntervalSec()*1000L));
+        }
+        
+        
+        /** Test if the session is dirty
+         * @return true if dirty
+         */
+        protected boolean isDirty ()
+        {
+            return _dirty;
+        }
+
+        /** 
+         * Expire the session.
+         * 
+         * @see org.eclipse.jetty.server.session.AbstractSession#timeout()
+         */
+        @Override
+        protected void timeout()
+        {
+            super.timeout();
+        }
+        
+      
+        
+        /**
+         * Reload the session from the cluster. If the node that
+         * last managed the session from the cluster is ourself,
+         * then the session does not need refreshing.
+         * NOTE: this method MUST be called with sufficient locks
+         * in place to prevent 2 or more concurrent threads from
+         * simultaneously updating the session.
+         */
+        private void refresh ()
+        {
+            //get fresh copy from the cluster
+            Session fresh = load(makeKey(getClusterId(), _context));
+
+            //if the session no longer exists, invalidate
+            if (fresh == null)
+            {
+                invalidate();
+                return;
+            }
+
+            //cluster copy assumed to be the same as we were the last
+            //node to manage it
+            if (fresh.getLastNode().equals(getLastNode()))
+                return;
+
+            setLastNode(getSessionIdManager().getWorkerName());
+            
+            //prepare for refresh
+            willPassivate();
+
+            //if fresh has no attributes, remove them
+            if (fresh.getAttributes() == 0)
+                this.clearAttributes();
+            else
+            {
+                //reconcile attributes
+                for (String key:fresh.getAttributeMap().keySet())
+                {
+                    Object freshvalue = fresh.getAttribute(key);
+
+                    //session does not already contain this attribute, so bind it
+                    if (getAttribute(key) == null)
+                    { 
+                        doPutOrRemove(key,freshvalue);
+                        bindValue(key,freshvalue);
+                    }
+                    else //session already contains this attribute, update its value
+                    {
+                        doPutOrRemove(key,freshvalue);
+                    }
+
+                }
+                // cleanup, remove values from session, that don't exist in data anymore:
+                for (String key : getNames())
+                {
+                    if (fresh.getAttribute(key) == null)
+                    {
+                        Object oldvalue = getAttribute(key);
+                        doPutOrRemove(key,null);
+                        unbindValue(key,oldvalue);
+                    }
+                }
+            }
+            //finish refresh
+            didActivate();
+        }
+
+
+        public void setExpiry (long expiry)
+        {
+            _expiryTime = expiry;
+        }
+        
+
+        public long getExpiry ()
+        {
+            return _expiryTime;
+        }
+        
+        public void swapId (String newId, String newNodeId)
+        {
+            //TODO probably synchronize rather than use the access/complete lock?
+            _lock.lock();
+            setClusterId(newId);
+            setNodeId(newNodeId);
+            _lock.unlock();
+        }
+        
+        @Override
+        public void setAttribute (String name, Object value)
+        {
+            Object old = changeAttribute(name, value);
+            if (value == null && old == null)
+                return; //if same as remove attribute but attribute was already removed, no change
+            
+           _dirty = true;
+        }
+        
+        
+        public String getContextPath()
+        {
+            return _contextPath;
+        }
+
+
+        public void setContextPath(String contextPath)
+        {
+            this._contextPath = contextPath;
+        }
+
+
+        public String getVHost()
+        {
+            return _vhost;
+        }
+
+
+        public void setVHost(String vhost)
+        {
+            this._vhost = vhost;
+        }
+        
+        public String getLastNode()
+        {
+            return _lastNode;
+        }
+
+
+        public void setLastNode(String lastNode)
+        {
+            _lastNode = lastNode;
+        }
+
+
+        public long getLastSyncTime()
+        {
+            return _lastSyncTime;
+        }
+
+
+        public void setLastSyncTime(long lastSyncTime)
+        {
+            _lastSyncTime = lastSyncTime;
+        }
+
+    }
+
+
+
+    
+    /**
+     * Start the session manager.
+     *
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#doStart()
+     */
+    @Override
+    public void doStart() throws Exception
+    {
+        if (_sessionIdManager == null)
+            throw new IllegalStateException("No session id manager defined");
+        
+        if (_cache == null)
+            throw new IllegalStateException("No session cache defined");
+        
+        _sessions = new ConcurrentHashMap<String, Session>();
+
+        //try and use a common scheduler, fallback to own
+        _scheduler = getSessionHandler().getServer().getBean(Scheduler.class);
+        if (_scheduler == null)
+        {
+            _scheduler = new ScheduledExecutorScheduler();
+            _ownScheduler = true;
+            _scheduler.start();
+        }
+        else if (!_scheduler.isStarted())
+            throw new IllegalStateException("Shared scheduler not started");
+ 
+        setScavengeInterval(getScavengeInterval());
+        
+        super.doStart();
+    }
+
+
+    /**
+     * Stop the session manager.
+     *
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#doStop()
+     */
+    @Override
+    public void doStop() throws Exception
+    {
+        super.doStop();
+
+        if (_task!=null)
+            _task.cancel();
+        _task=null;
+        if (_ownScheduler && _scheduler !=null)
+            _scheduler.stop();
+        _scheduler = null;
+        
+        _sessions.clear();
+        _sessions = null;
+    }
+    
+    
+    
+    /**
+     * Look for sessions in local memory that have expired.
+     */
+    /**
+     * 
+     */
+    public void scavenge ()
+    {
+        Set<String> candidateIds = new HashSet<String>();
+        long now = System.currentTimeMillis();
+        
+        LOG.info("SessionManager for context {} scavenging at {} ", getContextPath(getContext()), now);
+        for (Map.Entry<String, Session> entry:_sessions.entrySet())
+        {
+            long expiry = entry.getValue().getExpiry();
+            if (expiry > 0 && expiry < now)
+                candidateIds.add(entry.getKey());
+        }
+
+        for (String candidateId:candidateIds)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Session {} expired ", candidateId);
+            
+            Session candidateSession = _sessions.get(candidateId);
+            if (candidateSession != null)
+            {
+                //double check the state of the session in the cache, as the
+                //session may have migrated to another node. This leaves a window
+                //where the cached session may have been changed by another node
+                Session cachedSession = load(makeKey(candidateId, _context));
+                if (cachedSession == null)
+                {
+                   if (LOG.isDebugEnabled()) LOG.debug("Locally expired session({}) does not exist in cluster ",candidateId);
+                    //the session no longer exists, do a full invalidation
+                    candidateSession.timeout();
+                }
+                else if (getSessionIdManager().getWorkerName().equals(cachedSession.getLastNode()))
+                {
+                    if (LOG.isDebugEnabled()) LOG.debug("Expiring session({}) local to session manager",candidateId);
+                    //if I am the master of the session then it can be timed out
+                    candidateSession.timeout();
+                }
+                else
+                {
+                    //some other node is the master of the session, simply remove it from my memory
+                    if (LOG.isDebugEnabled()) LOG.debug("Session({}) not local to this session manager, removing from local memory", candidateId);
+                    candidateSession.willPassivate();
+                    _sessions.remove(candidateSession.getClusterId());
+                }
+
+            }
+        }
+    }
+    
+    
+
+    public long getScavengeInterval ()
+    {
+        return _scavengeIntervalMs/1000;
+    }
+
+    
+    
+    /**
+     * Set the interval between runs of the scavenger. It should not be run too
+     * often.
+     * 
+     * 
+     * @param sec scavenge interval in seconds
+     */
+    public void setScavengeInterval (long sec)
+    {
+        if (sec<=0)
+            sec=60;
+
+        long old_period=_scavengeIntervalMs;
+        long period=sec*1000L;
+
+        _scavengeIntervalMs=period;
+
+        //add a bit of variability into the scavenge time so that not all
+        //nodes with the same scavenge time sync up
+        long tenPercent = _scavengeIntervalMs/10;
+        if ((System.currentTimeMillis()%2) == 0)
+            _scavengeIntervalMs += tenPercent;
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms");
+        
+        synchronized (this)
+        {
+            if (_scheduler != null && (period!=old_period || _task==null))
+            {
+                if (_task!=null)
+                    _task.cancel();
+                if (_scavenger == null)
+                    _scavenger = new Scavenger();
+                
+                _task = _scheduler.schedule(_scavenger,_scavengeIntervalMs,TimeUnit.MILLISECONDS);
+            }
+        }
+    }
+    
+    
+    
+
+    /**
+     * Get the clustered cache instance.
+     * 
+     * @return the cache
+     */
+    public BasicCache<String, Object> getCache() 
+    {
+        return _cache;
+    }
+
+    
+    
+    /**
+     * Set the clustered cache instance.
+     * 
+     * @param cache the cache
+     */
+    public void setCache (BasicCache<String, Object> cache) 
+    {
+        this._cache = cache;
+    }
+
+
+    
+    
+    
+    public long getStaleIntervalSec()
+    {
+        return _staleIntervalSec;
+    }
+
+
+    public void setStaleIntervalSec(long staleIntervalSec)
+    {
+        _staleIntervalSec = staleIntervalSec;
+    }
+
+
+    /** 
+     * Add a new session for the context related to this session manager
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#addSession(org.eclipse.jetty.server.session.AbstractSession)
+     */
+    @Override
+    protected void addSession(AbstractSession session)
+    {
+        if (session==null)
+            return;
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Adding session({}) to session manager for context {} on worker {}",session.getClusterId(), getContextPath(getContext()),getSessionIdManager().getWorkerName() + " with lastnode="+((Session)session).getLastNode());
+        _sessions.put(session.getClusterId(), (Session)session);
+        
+        try
+        {     
+                session.willPassivate();
+                save(((InfinispanSessionManager.Session)session));
+                session.didActivate();
+            
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Unable to store new session id="+session.getId() , e);
+        }
+    }
+
+    /** 
+     * Ask the cluster for the session.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#getSession(java.lang.String)
+     */
+    @Override
+    public AbstractSession getSession(String idInCluster)
+    {
+        Session session = null;
+
+        //try and find the session in this node's memory
+        Session memSession = (Session)_sessions.get(idInCluster);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("getSession({}) {} in session map",idInCluster,(memSession==null?"not":""));
+
+        long now = System.currentTimeMillis();
+        try
+        {
+            //if the session is not in this node's memory, then load it from the cluster cache
+            if (memSession == null)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("getSession({}): loading session data from cluster", idInCluster);
+
+                session = load(makeKey(idInCluster, _context));
+                if (session != null)
+                {
+                    //We retrieved a session with the same key from the database
+
+                    //Check that it wasn't expired
+                    if (session.getExpiry() > 0 && session.getExpiry() <= now)
+                    {
+                        if (LOG.isDebugEnabled()) LOG.debug("getSession ({}): Session expired", idInCluster);
+                        //ensure that the session id for the expired session is deleted so that a new session with the 
+                        //same id cannot be created (because the idInUse() test would succeed)
+                        ((InfinispanSessionIdManager)getSessionIdManager()).removeSession(session);
+                        return null;  
+                    }
+
+                    //Update the last worker node to me
+                    session.setLastNode(getSessionIdManager().getWorkerName());                            
+                    //TODO consider saving session here if lastNode was not this node
+
+                    //Check that another thread hasn't loaded the same session
+                    Session existingSession = _sessions.putIfAbsent(idInCluster, session);
+                    if (existingSession != null)
+                    {
+                        //use the one that the other thread inserted
+                        session = existingSession;
+                        LOG.debug("getSession({}): using session loaded by another request thread ", idInCluster);
+                    }
+                    else
+                    {
+                        //indicate that the session was reinflated
+                        session.didActivate();
+                        LOG.debug("getSession({}): loaded session from cluster", idInCluster);
+                    }
+                    return session;
+                }
+                else
+                {
+                    //The requested session does not exist anywhere in the cluster
+                    LOG.debug("getSession({}): No session in cluster matching",idInCluster);
+                    return null;
+                }
+            }
+            else
+            {
+               //The session exists in this node's memory
+               LOG.debug("getSession({}): returning session from local memory ", memSession.getClusterId());
+                return memSession;
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Unable to load session="+idInCluster, e);
+            return null;
+        }
+    }
+    
+    
+
+    /** 
+     * The session manager is stopping.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#shutdownSessions()
+     */
+    @Override
+    protected void shutdownSessions() throws Exception
+    {
+        Set<String> keys = new HashSet<String>(_sessions.keySet());
+        for (String key:keys)
+        {
+            Session session = _sessions.remove(key); //take the session out of the session list
+            //If the session is dirty, then write it to the cluster.
+            //If the session is simply stale do NOT write it to the cluster, as some other node
+            //may have started managing that session - this means that the last accessed/expiry time
+            //will not be updated, meaning it may look like it can expire sooner than it should.
+            try
+            {
+                if (session.isDirty())
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Saving dirty session {} before exiting ", session.getId());
+                    save(session);
+                }
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+            }
+        }
+    }
+
+
+    @Override
+    protected AbstractSession newSession(HttpServletRequest request)
+    {
+        return new Session(request);
+    }
+
+    /** 
+     * Remove a session from local memory, and delete it from
+     * the cluster cache.
+     * 
+     * @see org.eclipse.jetty.server.session.AbstractSessionManager#removeSession(java.lang.String)
+     */
+    @Override
+    protected boolean removeSession(String idInCluster)
+    {
+        Session session = (Session)_sessions.remove(idInCluster);
+        try
+        {
+            if (session != null)
+                delete(session);
+        }
+        catch (Exception e)
+        {
+            LOG.warn("Problem deleting session id="+idInCluster, e);
+        }
+        return session!=null;
+    }
+    
+    
+    
+    
+    @Override
+    public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId)
+    {
+        Session session = null;
+        try
+        {
+            //take the session with that id out of our managed list
+            session = (Session)_sessions.remove(oldClusterId);
+            if (session != null)
+            {
+                //TODO consider transactionality and ramifications if the session is live on another node
+                delete(session); //delete the old session from the cluster  
+                session.swapId(newClusterId, newNodeId); //update the session
+                _sessions.put(newClusterId, session); //put it into managed list under new key
+                save(session); //put the session under the new id into the cluster
+            }
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+        }
+
+        super.renewSessionId(oldClusterId, oldNodeId, newClusterId, newNodeId);
+    }
+
+
+    /**
+     * Load a session from the clustered cache.
+     * 
+     * @param key the session key
+     * @return the session
+     */
+    protected Session load (String key)
+    {
+        if (_cache == null)
+            throw new IllegalStateException("No cache");
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from cluster", key);
+
+        SerializableSessionData storableSession = (SerializableSessionData)_cache.get(key);
+        if (storableSession == null)
+        {
+            if (LOG.isDebugEnabled()) LOG.debug("No session {} in cluster ",key);
+            return null;
+        }
+        else
+        {
+            Session session = new Session (storableSession);
+            session.setLastSyncTime(System.currentTimeMillis());
+            return session;
+        }
+    }
+    
+    
+    
+    /**
+     * Save or update the session to the cluster cache
+     * 
+     * @param session the session
+     * @throws Exception if unable to save
+     */
+    protected void save (InfinispanSessionManager.Session session)
+    throws Exception
+    {
+        if (_cache == null)
+            throw new IllegalStateException("No cache");
+        
+        if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to cluster", session.getId());
+    
+        SerializableSessionData storableSession = new SerializableSessionData(session);
+
+        //Put an idle timeout on the cache entry if the session is not immortal - 
+        //if no requests arrive at any node before this timeout occurs, or no node 
+        //scavenges the session before this timeout occurs, the session will be removed.
+        //NOTE: that no session listeners can be called for this.
+        InfinispanSessionIdManager sessionIdManager = (InfinispanSessionIdManager)getSessionIdManager();
+        if (storableSession.maxInactive > 0)
+            _cache.put(makeKey(session, _context), storableSession, -1, TimeUnit.SECONDS, storableSession.maxInactive*sessionIdManager.getIdleExpiryMultiple(), TimeUnit.SECONDS);
+        else
+            _cache.put(makeKey(session, _context), storableSession);
+        
+        //tickle the session id manager to keep the sessionid entry for this session up-to-date
+        sessionIdManager.touch(session.getClusterId());
+        
+        session.setLastSyncTime(System.currentTimeMillis());
+    }
+    
+    
+    
+    /**
+     * Remove the session from the cluster cache.
+     * 
+     * @param session the session
+     */
+    protected void delete (InfinispanSessionManager.Session session)
+    {  
+        if (_cache == null)
+            throw new IllegalStateException("No cache");
+        if (LOG.isDebugEnabled()) LOG.debug("Removing session {} from cluster", session.getId());
+        _cache.remove(makeKey(session, _context));
+    }
+
+    
+    /**
+     * Invalidate a session for this context with the given id
+     * 
+     * @param idInCluster session id in cluster
+     */
+    public void invalidateSession (String idInCluster)
+    {
+        Session session = (Session)_sessions.get(idInCluster);
+
+        if (session != null)
+        {
+            session.invalidate();
+        }
+    }
+
+    
+    /**
+     * Make a unique key for this session.
+     * As the same session id can be used across multiple contexts, to
+     * make it unique, the key must be composed of:
+     * <ol>
+     * <li>the id</li>
+     * <li>the context path</li>
+     * <li>the virtual hosts</li>
+     * </ol>
+     * 
+     *TODO consider the difference between getClusterId and getId
+     * @param session
+     * @return
+     */
+    private String makeKey (Session session, Context context)
+    {
+       return makeKey(session.getId(), context);
+    }
+    
+    /**
+     * Make a unique key for this session.
+     * As the same session id can be used across multiple contexts, to
+     * make it unique, the key must be composed of:
+     * <ol>
+     * <li>the id</li>
+     * <li>the context path</li>
+     * <li>the virtual hosts</li>
+     * </ol>
+     * 
+     *TODO consider the difference between getClusterId and getId
+     * @param session
+     * @return
+     */
+    private String makeKey (String id, Context context)
+    {
+        String key = getContextPath(context);
+        key = key + "_" + getVirtualHost(context);
+        key = key+"_"+id;
+        return key;
+    }
+    
+    /**
+     * Turn the context path into an acceptable string
+     * 
+     * @param context
+     * @return
+     */
+    private static String getContextPath (ContextHandler.Context context)
+    {
+        return canonicalize (context.getContextPath());
+    }
+
+    /**
+     * Get the first virtual host for the context.
+     *
+     * Used to help identify the exact session/contextPath.
+     *
+     * @return 0.0.0.0 if no virtual host is defined
+     */
+    private static String getVirtualHost (ContextHandler.Context context)
+    {
+        String vhost = "0.0.0.0";
+
+        if (context==null)
+            return vhost;
+
+        String [] vhosts = context.getContextHandler().getVirtualHosts();
+        if (vhosts==null || vhosts.length==0 || vhosts[0]==null)
+            return vhost;
+
+        return vhosts[0];
+    }
+
+    /**
+     * Make an acceptable name from a context path.
+     *
+     * @param path
+     * @return
+     */
+    private static String canonicalize (String path)
+    {
+        if (path==null)
+            return "";
+
+        return path.replace('/', '_').replace('.','_').replace('\\','_');
+    }
+
+}
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java
new file mode 100644
index 0000000..3f604ae
--- /dev/null
+++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java
@@ -0,0 +1,84 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.session.infinispan;
+
+import org.infinispan.commons.marshall.jboss.AbstractJBossMarshaller;
+import org.jboss.marshalling.ContextClassResolver;
+
+
+/**
+ * WebAppMarshaller
+ *
+ * An implementation of the AbstractJBossMarshaller code that is just
+ * enough to provide a ContextClassResolver that will use the Thread Context Classloader
+ * in order to deserialize session attribute classes.  
+ * 
+ * This is necessary because the standard infinispan marshaller (GenericJBossMarshaller) uses the
+ * classloader of the loader that loaded itself. When using the infinispan module in Jetty, all of
+ * the infinispan classes will be on the container classpath. That means that the GenericJBossMarshaller
+ * returns the container classloader which is unable to load any webapp classes. This class ensures
+ * that it is always the webapp's classloader that will be used.
+ * 
+ * In order to use this class, you should put a hotrod-client.properties file into the
+ * ${jetty.base}/resources directory that contains this line:
+ * 
+ * infinispan.client.hotrod.marshaller=org.eclipse.jetty.session.infinispan.WebAppMarshaller
+ * 
+ * You will also need to add the following lines to a context xml file for your webapp to
+ * permit the webapp's classloader to see the org.eclipse.jetty.session.infinispan classes for
+ * the deserialization to work correctly:
+ * 
+ *  &lt;Call name="prependServerClass"&gt;
+ *   &lt;Arg&gt;-org.eclipse.jetty.session.infinispan.&lt;/Arg&gt;
+ * &lt;/Call&gt;
+ *
+ */
+public class WebAppMarshaller extends AbstractJBossMarshaller 
+{
+
+    /**
+     * WebAppContextClassResolver
+     *
+     * Provides the Thread Context Classloader to use for deserializing.
+     * 
+     */
+    public static class WebAppContextClassResolver extends ContextClassResolver
+    {
+        public WebAppContextClassResolver ()
+        {
+            super();
+        }
+
+        @Override
+        protected ClassLoader getClassLoader()
+        {
+            return Thread.currentThread().getContextClassLoader();
+        }
+    }
+
+
+
+    public WebAppMarshaller ()
+    {
+        super();		
+        baseCfg.setClassResolver(new WebAppContextClassResolver());                         
+    }
+
+
+}
diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml
index 0f50850..e2d784d 100644
--- a/jetty-io/pom.xml
+++ b/jetty-io/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <artifactId>jetty-project</artifactId>
     <groupId>org.eclipse.jetty</groupId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-io</artifactId>
@@ -31,35 +31,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
index 28c7082..8bd212c 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
@@ -23,12 +23,10 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.NonBlockingThread;
 
 /**
  * <p>A convenience base implementation of {@link Connection}.</p>
@@ -41,31 +39,20 @@
 {
     private static final Logger LOG = Log.getLogger(AbstractConnection.class);
 
-    public static final boolean EXECUTE_ONFILLABLE=true;
-
     private final List<Listener> listeners = new CopyOnWriteArrayList<>();
-    private final AtomicReference<State> _state = new AtomicReference<>(IDLE);
     private final long _created=System.currentTimeMillis();
     private final EndPoint _endPoint;
     private final Executor _executor;
     private final Callback _readCallback;
-    private final boolean _executeOnfillable;
     private int _inputBufferSize=2048;
 
     protected AbstractConnection(EndPoint endp, Executor executor)
     {
-        this(endp,executor,EXECUTE_ONFILLABLE);
-    }
-
-    protected AbstractConnection(EndPoint endp, Executor executor, final boolean executeOnfillable)
-    {
         if (executor == null)
             throw new IllegalArgumentException("Executor must not be null!");
         _endPoint = endp;
         _executor = executor;
         _readCallback = new ReadCallback();
-        _executeOnfillable=executeOnfillable;
-        _state.set(IDLE);
     }
 
     @Override
@@ -74,6 +61,12 @@
         listeners.add(listener);
     }
 
+    @Override
+    public void removeListener(Listener listener)
+    {
+        listeners.remove(listener);
+    }
+
     public int getInputBufferSize()
     {
         return _inputBufferSize;
@@ -89,9 +82,26 @@
         return _executor;
     }
 
+    @Deprecated
+    public boolean isDispatchIO()
+    {
+        return false;
+    }
+
     protected void failedCallback(final Callback callback, final Throwable x)
     {
-        if (NonBlockingThread.isNonBlockingThread())
+        if (callback.isNonBlocking())
+        {
+            try
+            {
+                callback.failed(x);
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+            }
+        }
+        else
         {
             try
             {
@@ -100,7 +110,14 @@
                     @Override
                     public void run()
                     {
-                        callback.failed(x);
+                        try
+                        {
+                            callback.failed(x);
+                        }
+                        catch (Exception e)
+                        {
+                            LOG.warn(e);
+                        }
                     }
                 });
             }
@@ -110,10 +127,6 @@
                 callback.failed(x);
             }
         }
-        else
-        {
-            callback.failed(x);
-        }
     }
 
     /**
@@ -126,30 +139,12 @@
     {
         if (LOG.isDebugEnabled())
             LOG.debug("fillInterested {}",this);
-
-        while(true)
-        {
-            State state=_state.get();
-            if (next(state,state.fillInterested()))
-                break;
-        }
+        getEndPoint().fillInterested(_readCallback);
     }
 
-    public void fillInterested(Callback callback)
+    public boolean isFillInterested()
     {
-        if (LOG.isDebugEnabled())
-            LOG.debug("fillInterested {}",this);
-
-        while(true)
-        {
-            State state=_state.get();
-            // TODO yuck
-            if (state instanceof FillingInterestedCallback && ((FillingInterestedCallback)state)._callback==callback)
-                break;
-            State next=new FillingInterestedCallback(callback,state);
-            if (next(state,next))
-                break;
-        }
+        return getEndPoint().isFillInterested();
     }
 
     /**
@@ -176,12 +171,12 @@
                 if (_endPoint.isOutputShutdown())
                     _endPoint.close();
                 else
+                {
                     _endPoint.shutdownOutput();
+                    fillInterested();
+                }
             }
         }
-
-        if (_endPoint.isOpen())
-            fillInterested();
     }
 
     /**
@@ -226,6 +221,12 @@
     }
 
     @Override
+    public boolean onIdleExpired()
+    {
+        return true;
+    }
+
+    @Override
     public int getMessagesIn()
     {
         return -1;
@@ -258,334 +259,24 @@
     @Override
     public String toString()
     {
-        return String.format("%s@%x[%s,%s]",
+        return String.format("%s@%x[%s]",
                 getClass().getSimpleName(),
                 hashCode(),
-                _state.get(),
                 _endPoint);
     }
 
-    public boolean next(State state, State next)
-    {
-        if (next==null)
-            return true;
-        if(_state.compareAndSet(state,next))
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("{}-->{} {}",state,next,this);
-            if (next!=state)
-                next.onEnter(AbstractConnection.this);
-            return true;
-        }
-        return false;
-    }
-
-    private static final class IdleState extends State
-    {
-        private IdleState()
-        {
-            super("IDLE");
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return FILL_INTERESTED;
-        }
-    }
-
-
-    private static final class FillInterestedState extends State
-    {
-        private FillInterestedState()
-        {
-            super("FILL_INTERESTED");
-        }
-
-        @Override
-        public void onEnter(AbstractConnection connection)
-        {
-            connection.getEndPoint().fillInterested(connection._readCallback);
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return this;
-        }
-
-        @Override
-        public State onFillable()
-        {
-            return FILLING;
-        }
-
-        @Override
-        State onFailed()
-        {
-            return IDLE;
-        }
-    }
-
-
-    private static final class RefillingState extends State
-    {
-        private RefillingState()
-        {
-            super("REFILLING");
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return FILLING_FILL_INTERESTED;
-        }
-
-        @Override
-        public State onFilled()
-        {
-            return IDLE;
-        }
-    }
-
-
-    private static final class FillingFillInterestedState extends State
-    {
-        private FillingFillInterestedState(String name)
-        {
-            super(name);
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return this;
-        }
-
-        State onFilled()
-        {
-            return FILL_INTERESTED;
-        }
-    }
-
-
-    private static final class FillingState extends State
-    {
-        private FillingState()
-        {
-            super("FILLING");
-        }
-
-        @Override
-        public void onEnter(AbstractConnection connection)
-        {
-            if (connection._executeOnfillable)
-                connection.getExecutor().execute(connection._runOnFillable);
-            else
-                connection._runOnFillable.run();
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return FILLING_FILL_INTERESTED;
-        }
-
-        @Override
-        public State onFilled()
-        {
-            return IDLE;
-        }
-    }
-
-
-    public static class State
-    {
-        private final String _name;
-        State(String name)
-        {
-            _name=name;
-        }
-
-        @Override
-        public String toString()
-        {
-            return _name;
-        }
-
-        void onEnter(AbstractConnection connection)
-        {
-        }
-
-        State fillInterested()
-        {
-            throw new IllegalStateException(this.toString());
-        }
-
-        State onFillable()
-        {
-            throw new IllegalStateException(this.toString());
-        }
-
-        State onFilled()
-        {
-            throw new IllegalStateException(this.toString());
-        }
-
-        State onFailed()
-        {
-            throw new IllegalStateException(this.toString());
-        }
-    }
-
-
-    public static final State IDLE=new IdleState();
-
-    public static final State FILL_INTERESTED=new FillInterestedState();
-
-    public static final State FILLING=new FillingState();
-
-    public static final State REFILLING=new RefillingState();
-
-    public static final State FILLING_FILL_INTERESTED=new FillingFillInterestedState("FILLING_FILL_INTERESTED");
-
-    public class NestedState extends State
-    {
-        private final State _nested;
-
-        NestedState(State nested)
-        {
-            super("NESTED("+nested+")");
-            _nested=nested;
-        }
-        NestedState(String name,State nested)
-        {
-            super(name+"("+nested+")");
-            _nested=nested;
-        }
-
-        @Override
-        State fillInterested()
-        {
-            return new NestedState(_nested.fillInterested());
-        }
-
-        @Override
-        State onFillable()
-        {
-            return new NestedState(_nested.onFillable());
-        }
-
-        @Override
-        State onFilled()
-        {
-            return new NestedState(_nested.onFilled());
-        }
-    }
-
-
-    public class FillingInterestedCallback extends NestedState
-    {
-        private final Callback _callback;
-
-        FillingInterestedCallback(Callback callback,State nested)
-        {
-            super("FILLING_INTERESTED_CALLBACK",nested==FILLING?REFILLING:nested);
-            _callback=callback;
-        }
-
-        @Override
-        void onEnter(final AbstractConnection connection)
-        {
-            Callback callback=new Callback()
-            {
-                @Override
-                public void succeeded()
-                {
-                    while(true)
-                    {
-                        State state = connection._state.get();
-                        if (!(state instanceof NestedState))
-                            break;
-                        State nested=((NestedState)state)._nested;
-                        if (connection.next(state,nested))
-                            break;
-                    }
-                    _callback.succeeded();
-                }
-
-                @Override
-                public void failed(Throwable x)
-                {
-                    while(true)
-                    {
-                        State state = connection._state.get();
-                        if (!(state instanceof NestedState))
-                            break;
-                        State nested=((NestedState)state)._nested;
-                        if (connection.next(state,nested))
-                            break;
-                    }
-                    _callback.failed(x);
-                }
-            };
-
-            connection.getEndPoint().fillInterested(callback);
-        }
-    }
-
-    private final Runnable _runOnFillable = new Runnable()
-    {
-        @Override
-        public void run()
-        {
-            try
-            {
-                onFillable();
-            }
-            finally
-            {
-                while(true)
-                {
-                    State state=_state.get();
-                    if (next(state,state.onFilled()))
-                        break;
-                }
-            }
-        }
-    };
-
-
     private class ReadCallback implements Callback
     {
         @Override
         public void succeeded()
         {
-            while(true)
-            {
-                State state=_state.get();
-                if (next(state,state.onFillable()))
-                    break;
-            }
+            onFillable();
         }
 
         @Override
         public void failed(final Throwable x)
         {
-            _executor.execute(new Runnable()
-            {
-                @Override
-                public void run()
-                {
-                    while(true)
-                    {
-                        State state=_state.get();
-                        if (next(state,state.onFailed()))
-                            break;
-                    }
-                    onFillInterestedFailed(x);
-                }
-            });
+            onFillInterestedFailed(x);
         }
 
         @Override
@@ -593,5 +284,5 @@
         {
             return String.format("AC.ReadCB@%x{%s}", AbstractConnection.this.hashCode(),AbstractConnection.this);
         }
-    };
+    }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
index 44a38ec..0d00a17 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
@@ -40,16 +40,16 @@
     private final FillInterest _fillInterest = new FillInterest()
     {
         @Override
-        protected boolean needsFill() throws IOException
+        protected void needsFillInterest() throws IOException
         {
-            return AbstractEndPoint.this.needsFill();
+            AbstractEndPoint.this.needsFillInterest();
         }
     };
 
     private final WriteFlusher _writeFlusher = new WriteFlusher(this)
     {
         @Override
-        protected void onIncompleteFlushed()
+        protected void onIncompleteFlush()
         {
             AbstractEndPoint.this.onIncompleteFlush();
         }
@@ -93,6 +93,12 @@
     }
 
     @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        return false;
+    }
+
+    @Override
     public void onOpen()
     {
         if (LOG.isDebugEnabled())
@@ -124,6 +130,12 @@
     }
 
     @Override
+    public boolean isFillInterested()
+    {
+        return _fillInterest.isInterested();
+    }
+
+    @Override
     public void write(Callback callback, ByteBuffer... buffers) throws IllegalStateException
     {
         _writeFlusher.write(callback, buffers);
@@ -131,9 +143,9 @@
 
     protected abstract void onIncompleteFlush();
 
-    protected abstract boolean needsFill() throws IOException;
+    protected abstract void needsFillInterest() throws IOException;
 
-    protected FillInterest getFillInterest()
+    public FillInterest getFillInterest()
     {
         return _fillInterest;
     }
@@ -146,6 +158,10 @@
     @Override
     protected void onIdleExpired(TimeoutException timeout)
     {
+        Connection connection = _connection;
+        if (connection != null && !_connection.onIdleExpired())
+            return;
+
         boolean output_shutdown=isOutputShutdown();
         boolean input_shutdown=isInputShutdown();
         boolean fillFailed = _fillInterest.onFail(timeout);
@@ -188,16 +204,24 @@
     @Override
     public String toString()
     {
+        Class<?> c=getClass();
+        String name=c.getSimpleName();
+        while (name.length()==0 && c.getSuperclass()!=null)
+        {
+            c=c.getSuperclass();
+            name=c.getSimpleName();
+        }
+
         return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d/%d,%s}",
-                getClass().getSimpleName(),
+                name,
                 hashCode(),
                 getRemoteAddress(),
                 getLocalAddress().getPort(),
                 isOpen()?"Open":"CLOSED",
                 isInputShutdown()?"ISHUT":"in",
                 isOutputShutdown()?"OSHUT":"out",
-                _fillInterest.isInterested()?"R":"-",
-                _writeFlusher.isInProgress()?"W":"-",
+                _fillInterest.toStateString(),
+                _writeFlusher.toStateString(),
                 getIdleFor(),
                 getIdleTimeout(),
                 getConnection()==null?null:getConnection().getClass().getSimpleName());
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
index 73cea8c..4b5a407 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java
@@ -18,16 +18,20 @@
 
 package org.eclipse.jetty.io;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedChannelException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.Queue;
 
+import org.eclipse.jetty.util.ArrayQueue;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Locker;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 
@@ -39,14 +43,24 @@
 {
     static final Logger LOG = Log.getLogger(ByteArrayEndPoint.class);
     public final static InetSocketAddress NOIP=new InetSocketAddress(0);
+    private static final ByteBuffer EOF = BufferUtil.allocate(0);
 
-    protected volatile ByteBuffer _in;
-    protected volatile ByteBuffer _out;
-    protected volatile boolean _ishut;
-    protected volatile boolean _oshut;
-    protected volatile boolean _closed;
-    protected volatile boolean _growOutput;
+    private final Runnable _runFillable = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            getFillInterest().fillable();
+        }
+    };
 
+    private final Locker _locker = new Locker();
+    private final Queue<ByteBuffer> _inQ = new ArrayQueue<>();
+    private ByteBuffer _out;
+    private boolean _ishut;
+    private boolean _oshut;
+    private boolean _closed;
+    private boolean _growOutput;
 
     /* ------------------------------------------------------------ */
     /**
@@ -59,7 +73,8 @@
 
     /* ------------------------------------------------------------ */
     /**
-     *
+     * @param input the input bytes
+     * @param outputSize the output size
      */
     public ByteArrayEndPoint(byte[] input, int outputSize)
     {
@@ -68,7 +83,8 @@
 
     /* ------------------------------------------------------------ */
     /**
-     *
+     * @param input the input string (converted to bytes using default encoding charset)
+     * @param outputSize the output size
      */
     public ByteArrayEndPoint(String input, int outputSize)
     {
@@ -97,15 +113,12 @@
     public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, ByteBuffer input, ByteBuffer output)
     {
         super(timer,NOIP,NOIP);
-        _in=input==null?BufferUtil.EMPTY_BUFFER:input;
+        if (BufferUtil.hasContent(input))
+            addInput(input);
         _out=output==null?BufferUtil.allocate(1024):output;
         setIdleTimeout(idleTimeoutMs);
     }
 
-
-
-
-
     /* ------------------------------------------------------------ */
     @Override
     protected void onIncompleteFlush()
@@ -114,52 +127,94 @@
     }
 
     /* ------------------------------------------------------------ */
+    protected void execute(Runnable task)
+    {
+        new Thread(task,"BAEPoint-"+Integer.toHexString(hashCode())).start();
+    }
+
+    /* ------------------------------------------------------------ */
     @Override
-    protected boolean needsFill() throws IOException
+    protected void needsFillInterest() throws IOException
     {
-        if (_closed)
-            throw new ClosedChannelException();
-        return _in == null || BufferUtil.hasContent(_in);
-    }
+        try(Locker.Lock lock = _locker.lock())
+        {
+            if (_closed)
+                throw new ClosedChannelException();
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @return Returns the in.
-     */
-    public ByteBuffer getIn()
-    {
-        return _in;
+            ByteBuffer in = _inQ.peek();
+            if (BufferUtil.hasContent(in) || in==EOF)
+                execute(_runFillable);
+        }
     }
 
     /* ------------------------------------------------------------ */
     /**
      */
-    public void setInputEOF()
+    public void addInputEOF()
     {
-        _in = null;
+        addInput((ByteBuffer)null);
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @param in The in to set.
      */
-    public void setInput(ByteBuffer in)
+    public void addInput(ByteBuffer in)
     {
-        _in = in;
-        if (in == null || BufferUtil.hasContent(in))
-            getFillInterest().fillable();
+        boolean fillable=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            if (_inQ.peek()==EOF)
+                throw new RuntimeIOException(new EOFException());
+            boolean was_empty=_inQ.isEmpty();
+            if (in==null)
+            {
+                _inQ.add(EOF);
+                fillable=true;
+            }
+            if (BufferUtil.hasContent(in))
+            {
+                _inQ.add(in);
+                fillable=was_empty;
+            }
+        }
+        if (fillable)
+            _runFillable.run();
+    }
+
+    public void addInputAndExecute(ByteBuffer in)
+    {
+        boolean fillable=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            if (_inQ.peek()==EOF)
+                throw new RuntimeIOException(new EOFException());
+            boolean was_empty=_inQ.isEmpty();
+            if (in==null)
+            {
+                _inQ.add(EOF);
+                fillable=true;
+            }
+            if (BufferUtil.hasContent(in))
+            {
+                _inQ.add(in);
+                fillable=was_empty;
+            }
+        }
+        if (fillable)
+            execute(_runFillable);
     }
 
     /* ------------------------------------------------------------ */
-    public void setInput(String s)
+    public void addInput(String s)
     {
-        setInput(BufferUtil.toBuffer(s,StandardCharsets.UTF_8));
+        addInput(BufferUtil.toBuffer(s,StandardCharsets.UTF_8));
     }
 
     /* ------------------------------------------------------------ */
-    public void setInput(String s,Charset charset)
+    public void addInput(String s,Charset charset)
     {
-        setInput(BufferUtil.toBuffer(s,charset));
+        addInput(BufferUtil.toBuffer(s,charset));
     }
 
     /* ------------------------------------------------------------ */
@@ -182,6 +237,7 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * @param charset the charset to encode the output as
      * @return Returns the out.
      */
     public String getOutputString(Charset charset)
@@ -212,6 +268,7 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * @param charset the charset to encode the output as
      * @return Returns the out.
      */
     public String takeOutputString(Charset charset)
@@ -237,7 +294,10 @@
     @Override
     public boolean isOpen()
     {
-        return !_closed;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return !_closed;
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -246,7 +306,10 @@
     @Override
     public boolean isInputShutdown()
     {
-        return _ishut||_closed;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _ishut||_closed;
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -255,15 +318,24 @@
     @Override
     public boolean isOutputShutdown()
     {
-        return _oshut||_closed;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _oshut||_closed;
+        }
     }
 
     /* ------------------------------------------------------------ */
-    private void shutdownInput()
+    public void shutdownInput()
     {
-        _ishut=true;
-        if (_oshut)
-            close();
+        boolean close=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            _ishut=true;
+            if (_oshut && !_closed)
+                close=_closed=true;
+        }
+        if (close)
+            super.close();
     }
 
     /* ------------------------------------------------------------ */
@@ -273,9 +345,15 @@
     @Override
     public void shutdownOutput()
     {
-        _oshut=true;
-        if (_ishut)
-            close();
+        boolean close=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            _oshut=true;
+            if (_ishut && !_closed)
+                close=_closed=true;
+        }
+        if (close)
+            super.close();
     }
 
     /* ------------------------------------------------------------ */
@@ -285,8 +363,14 @@
     @Override
     public void close()
     {
-        super.close();
-        _closed=true;
+        boolean close=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            if (!_closed)
+                close=_closed=_ishut=_oshut=true;
+        }
+        if (close)
+            super.close();
     }
 
     /* ------------------------------------------------------------ */
@@ -305,13 +389,44 @@
     @Override
     public int fill(ByteBuffer buffer) throws IOException
     {
-        if (_closed)
-            throw new EofException("CLOSED");
-        if (_in==null)
-            shutdownInput();
-        if (_ishut)
-            return -1;
-        int filled=BufferUtil.append(buffer,_in);
+        int filled=0;
+        boolean close=false;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            while(true)
+            {
+                if (_closed)
+                    throw new EofException("CLOSED");
+
+                if (_ishut)
+                    return -1;
+
+                if (_inQ.isEmpty())
+                    break;
+
+                ByteBuffer in= _inQ.peek();
+                if (in==EOF)
+                {
+                    _ishut=true;
+                    if (_oshut)
+                        close=_closed=true;
+                    filled=-1;
+                    break;
+                }
+
+                if (BufferUtil.hasContent(in))
+                {
+                    filled=BufferUtil.append(buffer,in);
+                    if (BufferUtil.isEmpty(in))
+                        _inQ.poll();
+                    break;
+                }
+                _inQ.poll();
+            }
+        }
+
+        if (close)
+            super.close();
         if (filled>0)
             notIdle();
         return filled;
@@ -373,7 +488,7 @@
         _ishut=false;
         _oshut=false;
         _closed=false;
-        _in=null;
+        _inQ.clear();
         BufferUtil.clear(_out);
     }
 
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java
index 4b5bada..6067d78 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java
@@ -19,6 +19,10 @@
 package org.eclipse.jetty.io;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.util.BufferUtil;
 
 /**
  * <p>A {@link ByteBuffer} pool.</p>
@@ -48,4 +52,67 @@
      * @see #acquire(int, boolean)
      */
     public void release(ByteBuffer buffer);
+
+    public static class Lease
+    {
+        private final ByteBufferPool byteBufferPool;
+        private final List<ByteBuffer> buffers;
+        private final List<Boolean> recycles;
+
+        public Lease(ByteBufferPool byteBufferPool)
+        {
+            this.byteBufferPool = byteBufferPool;
+            this.buffers = new ArrayList<>();
+            this.recycles = new ArrayList<>();
+        }
+
+        public ByteBuffer acquire(int capacity, boolean direct)
+        {
+            ByteBuffer buffer = byteBufferPool.acquire(capacity, direct);
+            BufferUtil.clearToFill(buffer);
+            return buffer;
+        }
+
+        public void append(ByteBuffer buffer, boolean recycle)
+        {
+            buffers.add(buffer);
+            recycles.add(recycle);
+        }
+
+        public void insert(int index, ByteBuffer buffer, boolean recycle)
+        {
+            buffers.add(index, buffer);
+            recycles.add(index, recycle);
+        }
+
+        public List<ByteBuffer> getByteBuffers()
+        {
+            return buffers;
+        }
+
+        public long getTotalLength()
+        {
+            long length = 0;
+            for (int i = 0; i < buffers.size(); ++i)
+                length += buffers.get(i).remaining();
+            return length;
+        }
+
+        public int getSize()
+        {
+            return buffers.size();
+        }
+
+        public void recycle()
+        {
+            for (int i = 0; i < buffers.size(); ++i)
+            {
+                ByteBuffer buffer = buffers.get(i);
+                if (recycles.get(i))
+                    byteBufferPool.release(buffer);
+            }
+            buffers.clear();
+            recycles.clear();
+        }
+    }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
index 5ce60e7..1952760 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ChannelEndPoint.java
@@ -23,7 +23,6 @@
 import java.net.Socket;
 import java.nio.ByteBuffer;
 import java.nio.channels.ByteChannel;
-import java.nio.channels.GatheringByteChannel;
 import java.nio.channels.SocketChannel;
 
 import org.eclipse.jetty.util.BufferUtil;
@@ -39,7 +38,7 @@
 {
     private static final Logger LOG = Log.getLogger(ChannelEndPoint.class);
 
-    private final ByteChannel _channel;
+    private final SocketChannel _channel;
     private final Socket _socket;
     private volatile boolean _ishut;
     private volatile boolean _oshut;
@@ -49,11 +48,17 @@
         super(scheduler,
             (InetSocketAddress)channel.socket().getLocalSocketAddress(),
             (InetSocketAddress)channel.socket().getRemoteSocketAddress());
-        _channel = channel;
+        _channel=channel;
         _socket=channel.socket();
     }
 
     @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isOpen()
     {
         return _channel.isOpen();
@@ -163,13 +168,13 @@
     @Override
     public boolean flush(ByteBuffer... buffers) throws IOException
     {
-        int flushed=0;
+        long flushed=0;
         try
         {
             if (buffers.length==1)
                 flushed=_channel.write(buffers[0]);
-            else if (buffers.length>1 && _channel instanceof GatheringByteChannel)
-                flushed= (int)((GatheringByteChannel)_channel).write(buffers,0,buffers.length);
+            else if (buffers.length>1)
+                flushed=_channel.write(buffers,0,buffers.length);
             else
             {
                 for (ByteBuffer b : buffers)
@@ -225,7 +230,7 @@
     }
 
     @Override
-    protected boolean needsFill() throws IOException
+    protected void needsFillInterest() throws IOException
     {
         throw new UnsupportedOperationException();
     }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java
index a11fe8e..ee028e1 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ClientConnectionFactory.java
@@ -19,12 +19,8 @@
 package org.eclipse.jetty.io;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.util.Map;
 
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
 /**
  * Factory for client-side {@link Connection} instances.
  */
@@ -38,53 +34,4 @@
      * @throws IOException if the connection cannot be created
      */
     public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException;
-
-    public static class Helper
-    {
-        private static Logger LOG = Log.getLogger(Helper.class);
-
-        private Helper()
-        {
-        }
-
-        /**
-         * Replaces the given {@code oldConnection} with the given {@code newConnection} on the
-         * {@link EndPoint} associated with {@code oldConnection}, performing connection lifecycle management.
-         * <p />
-         * The {@code oldConnection} will be closed by invoking {@link org.eclipse.jetty.io.Connection#onClose()}
-         * and the {@code newConnection} will be opened by invoking {@link org.eclipse.jetty.io.Connection#onOpen(ByteBuffer)}.
-         * @param oldConnection the old connection to replace
-         * @param newConnection the new connection replacement
-         */
-        public static void replaceConnection(Connection oldConnection, Connection newConnection)
-        {
-            close(oldConnection);
-            oldConnection.getEndPoint().setConnection(newConnection);
-            open(newConnection);
-        }
-
-        private static void open(Connection connection)
-        {
-            try
-            {
-                connection.onOpen();
-            }
-            catch (Throwable x)
-            {
-                LOG.debug(x);
-            }
-        }
-
-        private static void close(Connection connection)
-        {
-            try
-            {
-                connection.onClose();
-            }
-            catch (Throwable x)
-            {
-                LOG.debug(x);
-            }
-        }
-    }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
index 5c7d564..564493c 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java
@@ -21,22 +21,40 @@
 import java.io.Closeable;
 import java.nio.ByteBuffer;
 
+import org.eclipse.jetty.util.component.Container;
+
 /**
  * <p>A {@link Connection} is associated to an {@link EndPoint} so that I/O events
  * happening on the {@link EndPoint} can be processed by the {@link Connection}.</p>
- * <p>A typical implementation of {@link Connection} overrides {@link #onOpen(ByteBuffer)} to
- * {@link EndPoint#fillInterested(Callback) set read interest} on the {@link EndPoint},
+ * <p>A typical implementation of {@link Connection} overrides {@link #onOpen()} to
+ * {@link EndPoint#fillInterested(org.eclipse.jetty.util.Callback) set read interest} on the {@link EndPoint},
  * and when the {@link EndPoint} signals read readyness, this {@link Connection} can
  * read bytes from the network and interpret them.</p>
  */
 public interface Connection extends Closeable
 {
+    /**
+     * <p>Adds a listener of connection events.</p>
+     *
+     * @param listener the listener to add
+     */
     public void addListener(Listener listener);
 
+    /**
+     * <p>Removes a listener of connection events.</p>
+     *
+     * @param listener the listener to remove
+     */
+    public void removeListener(Listener listener);
+
+    /**
+     * <p>Callback method invoked when this connection is opened.</p>
+     * <p>Creators of the connection implementation are responsible for calling this method.</p>
+     */
     public void onOpen();
 
     /**
-     * <p>Callback method invoked when this {@link Connection} is closed.</p>
+     * <p>Callback method invoked when this connection is closed.</p>
      * <p>Creators of the connection implementation are responsible for calling this method.</p>
      */
     public void onClose();
@@ -45,7 +63,7 @@
      * @return the {@link EndPoint} associated with this {@link Connection}
      */
     public EndPoint getEndPoint();
-    
+
     /**
      * <p>Performs a logical close of this connection.</p>
      * <p>For simple connections, this may just mean to delegate the close to the associated
@@ -55,37 +73,59 @@
     @Override
     public void close();
 
+    /**
+     * <p>Callback method invoked upon an idle timeout event.</p>
+     * <p>Implementations of this method may return true to indicate that the idle timeout
+     * handling should proceed normally, typically failing the EndPoint and causing it to
+     * be closed.</p>
+     * <p>When false is returned, the handling of the idle timeout event is halted
+     * immediately and the EndPoint left in the state it was before the idle timeout event.</p>
+     *
+     * @return true to let the EndPoint handle the idle timeout,
+     *         false to tell the EndPoint to halt the handling of the idle timeout.
+     */
+    public boolean onIdleExpired();
+
     public int getMessagesIn();
     public int getMessagesOut();
     public long getBytesIn();
     public long getBytesOut();
     public long getCreatedTimeStamp();
-    
+
     public interface UpgradeFrom extends Connection
     {
-        /* ------------------------------------------------------------ */
-        /** Take the input buffer from the connection on upgrade.
+        /**
+         * <p>Takes the input buffer from the connection on upgrade.</p>
          * <p>This method is used to take any unconsumed input from
-         * a connection during an upgrade.
+         * a connection during an upgrade.</p>
+         *
          * @return A buffer of unconsumed input. The caller must return the buffer
          * to the bufferpool when consumed and this connection must not.
          */
         ByteBuffer onUpgradeFrom();
     }
-    
+
     public interface UpgradeTo extends Connection
     {
         /**
-         * <p>Callback method invoked when this {@link Connection} is upgraded.</p>
+         * <p>Callback method invoked when this connection is upgraded.</p>
          * <p>This must be called before {@link #onOpen()}.</p>
-         * @param prefilledBuffer An optional buffer that can contain prefilled data. Typically this
+         * @param prefilled An optional buffer that can contain prefilled data. Typically this
          * results from an upgrade of one protocol to the other where the old connection has buffered
          * data destined for the new connection.  The new connection must take ownership of the buffer
          * and is responsible for returning it to the buffer pool
          */
         void onUpgradeTo(ByteBuffer prefilled);
     }
-    
+
+    /**
+     * <p>A Listener for connection events.</p>
+     * <p>Listeners can be added to a {@link Connection} to get open and close events.
+     * The AbstractConnectionFactory implements a pattern where objects implement
+     * this interface that have been added via {@link Container#addBean(Object)} to
+     * the Connector or ConnectionFactory are added as listeners to all new connections
+     * </p>
+     */
     public interface Listener
     {
         public void onOpened(Connection connection);
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
index c96dcb8..8f285c3 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/EndPoint.java
@@ -26,33 +26,35 @@
 import java.nio.channels.WritePendingException;
 
 import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FutureCallback;
+import org.eclipse.jetty.util.IteratingCallback;
 
 /**
  *
  * A transport EndPoint
- * 
+ *
  * <h3>Asynchronous Methods</h3>
- * <p>The asynchronous scheduling methods of {@link EndPoint} 
+ * <p>The asynchronous scheduling methods of {@link EndPoint}
  * has been influenced by NIO.2 Futures and Completion
  * handlers, but does not use those actual interfaces because they have
  * some inefficiencies.</p>
  * <p>This class will frequently be used in conjunction with some of the utility
  * implementations of {@link Callback}, such as {@link FutureCallback} and
- * {@link ExecutorCallback}. Examples are:</p>
+ * {@link IteratingCallback}. Examples are:</p>
  *
  * <h3>Blocking Read</h3>
  * <p>A FutureCallback can be used to block until an endpoint is ready to be filled
- * from:
+ * from:</p>
  * <blockquote><pre>
  * FutureCallback&lt;String&gt; future = new FutureCallback&lt;&gt;();
  * endpoint.fillInterested("ContextObj",future);
  * ...
  * String context = future.get(); // This blocks
  * int filled=endpoint.fill(mybuffer);
- * </pre></blockquote></p>
+ * </pre></blockquote>
  *
  * <h3>Dispatched Read</h3>
- * <p>By using a different callback, the read can be done asynchronously in its own dispatched thread:
+ * <p>By using a different callback, the read can be done asynchronously in its own dispatched thread:</p>
  * <blockquote><pre>
  * endpoint.fillInterested("ContextObj",new ExecutorCallback&lt;String&gt;(executor)
  * {
@@ -63,22 +65,22 @@
  *   }
  *   public void onFailed(String context,Throwable cause) {...}
  * });
- * </pre></blockquote></p>
+ * </pre></blockquote>
  * <p>The executor callback can also be customized to not dispatch in some circumstances when
  * it knows it can use the callback thread and does not need to dispatch.</p>
  *
  * <h3>Blocking Write</h3>
  * <p>The write contract is that the callback complete is not called until all data has been
- * written or there is a failure.  For blocking this looks like:
+ * written or there is a failure.  For blocking this looks like:</p>
  * <blockquote><pre>
  * FutureCallback&lt;String&gt; future = new FutureCallback&lt;&gt;();
  * endpoint.write("ContextObj",future,headerBuffer,contentBuffer);
  * String context = future.get(); // This blocks
- * </pre></blockquote></p>
+ * </pre></blockquote>
  *
  * <h3>Dispatched Write</h3>
  * <p>Note also that multiple buffers may be passed in write so that gather writes
- * can be done:
+ * can be done:</p>
  * <blockquote><pre>
  * endpoint.write("ContextObj",new ExecutorCallback&lt;String&gt;(executor)
  * {
@@ -89,7 +91,7 @@
  *   }
  *   public void onFailed(String context,Throwable cause) {...}
  * },headerBuffer,contentBuffer);
- * </pre></blockquote></p>
+ * </pre></blockquote>
  */
 public interface EndPoint extends Closeable
 {
@@ -158,7 +160,7 @@
      * operation, the position is unchanged and the limit is increased to reflect the new data filled.
      * @return an <code>int</code> value indicating the number of bytes
      * filled or -1 if EOF is read or the input is shutdown.
-     * @throws EofException If the endpoint is closed.
+     * @throws IOException if the endpoint is closed.
      */
     int fill(ByteBuffer buffer) throws IOException;
 
@@ -167,10 +169,10 @@
      * Flush data from the passed header/buffer to this endpoint.  As many bytes as can be consumed
      * are taken from the header/buffer position up until the buffer limit.  The header/buffers position
      * is updated to indicate how many bytes have been consumed.
-     * @return True IFF all the buffers have been consumed and the endpoint has flushed the data to its 
+     * @param buffer the buffers to flush
+     * @return True IFF all the buffers have been consumed and the endpoint has flushed the data to its
      * destination (ie is not buffering any data).
-     *
-     * @throws EofException If the endpoint is closed or output is shutdown.
+     * @throws IOException If the endpoint is closed or output is shutdown.
      */
     boolean flush(ByteBuffer... buffer) throws IOException;
 
@@ -184,13 +186,13 @@
     /** Get the max idle time in ms.
      * <p>The max idle time is the time the endpoint can be idle before
      * extraordinary handling takes place.
-     * @return the max idle time in ms or if ms <= 0 implies an infinite timeout
+     * @return the max idle time in ms or if ms &lt;= 0 implies an infinite timeout
      */
     long getIdleTimeout();
 
     /* ------------------------------------------------------------ */
     /** Set the idle timeout.
-     * @param idleTimeout the idle timeout in MS. Timeout <= 0 implies an infinite timeout
+     * @param idleTimeout the idle timeout in MS. Timeout &lt;= 0 implies an infinite timeout
      */
     void setIdleTimeout(long idleTimeout);
 
@@ -204,6 +206,12 @@
     void fillInterested(Callback callback) throws ReadPendingException;
 
     /**
+     * @return whether {@link #fillInterested(Callback)} has been called, but {@link #fill(ByteBuffer)} has not yet
+     * been called
+     */
+    boolean isFillInterested();
+
+    /**
      * <p>Writes the given buffers via {@link #flush(ByteBuffer...)} and invokes callback methods when either
      * all the data has been flushed or an error occurs.</p>
      *
@@ -238,6 +246,11 @@
      */
     void onClose();
 
+    /** Is the endpoint optimized for DirectBuffer usage
+     * @return True if direct buffers can be used optimally.
+     */
+    boolean isOptimizedForDirectBuffers();
+
 
     /** Upgrade connections.
      * Close the old connection, update the endpoint and open the new connection.
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
index a234397..a00a893 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
@@ -21,115 +21,138 @@
 import java.io.IOException;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.ReadPendingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-
-/* ------------------------------------------------------------ */
-/** 
+/**
  * A Utility class to help implement {@link EndPoint#fillInterested(Callback)}
  * by keeping state and calling the context and callback objects.
- * 
  */
 public abstract class FillInterest
 {
     private final static Logger LOG = Log.getLogger(FillInterest.class);
     private final AtomicReference<Callback> _interested = new AtomicReference<>(null);
+    private Throwable _lastSet;
 
-    /* ------------------------------------------------------------ */
     protected FillInterest()
     {
     }
 
-    /* ------------------------------------------------------------ */
-    /** Call to register interest in a callback when a read is possible.
-     * The callback will be called either immediately if {@link #needsFill()} 
+    /**
+     * Call to register interest in a callback when a read is possible.
+     * The callback will be called either immediately if {@link #needsFillInterest()}
      * returns true or eventually once {@link #fillable()} is called.
-     * @param callback
-     * @throws ReadPendingException
+     *
+     * @param callback the callback to register
+     * @throws ReadPendingException if unable to read due to pending read op
      */
-    public <C> void register(Callback callback) throws ReadPendingException
+    public void register(Callback callback) throws ReadPendingException
     {
-        if (callback==null)
+        if (callback == null)
             throw new IllegalArgumentException();
-        
-        if (!_interested.compareAndSet(null,callback))
+
+        if (_interested.compareAndSet(null, callback))
         {
-            LOG.warn("Read pending for "+_interested.get()+" prevented "+callback);
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("{} register {}",this,callback);
+                _lastSet=new Throwable(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + ":" + Thread.currentThread().getName());
+            }
+        }
+        else
+        {
+            LOG.warn("Read pending for {} prevented {}", _interested, callback);
+            if (LOG.isDebugEnabled())
+                LOG.warn("callback set at ",_lastSet);
             throw new ReadPendingException();
         }
         try
         {
-            if (needsFill())
-                fillable();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} register {}",this,callback);
+            needsFillInterest();
         }
-        catch(IOException e)
+        catch (Throwable e)
         {
             onFail(e);
         }
     }
 
-    /* ------------------------------------------------------------ */
-    /** Call to signal that a read is now possible.
+    /**
+     * Call to signal that a read is now possible.
      */
     public void fillable()
     {
-        Callback callback=_interested.get();
-        if (callback!=null && _interested.compareAndSet(callback,null))
+        Callback callback = _interested.get();
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} fillable {}",this,callback);
+        if (callback != null && _interested.compareAndSet(callback, null))
             callback.succeeded();
+        else if (LOG.isDebugEnabled())
+            LOG.debug("{} lost race {}",this,callback);
     }
 
-    /* ------------------------------------------------------------ */
     /**
      * @return True if a read callback has been registered
      */
     public boolean isInterested()
     {
-        return _interested.get()!=null;
+        return _interested.get() != null;
     }
     
-    /* ------------------------------------------------------------ */
-    /** Call to signal a failure to a registered interest
+    public boolean isCallbackNonBlocking()
+    {
+        Callback callback = _interested.get();
+        return callback!=null && callback.isNonBlocking();
+    }
+
+    /**
+     * Call to signal a failure to a registered interest
+     *
+     * @param cause the cause of the failure
      * @return true if the cause was passed to a {@link Callback} instance
      */
     public boolean onFail(Throwable cause)
     {
-        Callback callback=_interested.get();
-        if (callback!=null && _interested.compareAndSet(callback,null))
+        Callback callback = _interested.get();
+        if (callback != null && _interested.compareAndSet(callback, null))
         {
             callback.failed(cause);
             return true;
         }
         return false;
     }
-    
-    /* ------------------------------------------------------------ */
+
     public void onClose()
     {
-        Callback callback=_interested.get();
-        if (callback!=null && _interested.compareAndSet(callback,null))
+        Callback callback = _interested.get();
+        if (callback != null && _interested.compareAndSet(callback, null))
             callback.failed(new ClosedChannelException());
     }
-    
-    /* ------------------------------------------------------------ */
+
     @Override
     public String toString()
     {
-        return String.format("FillInterest@%x{%b,%s}",hashCode(),_interested.get(),_interested.get());
+        return String.format("FillInterest@%x{%b,%s}", hashCode(), _interested.get()!=null, _interested.get());
     }
+
     
-    /* ------------------------------------------------------------ */
-    /** Register the read interest 
+    public String toStateString()
+    {
+        return _interested.get()==null?"-":"FI";
+    }
+
+    /**
+     * Register the read interest
      * Abstract method to be implemented by the Specific ReadInterest to
-     * enquire if a read is immediately possible and if not to schedule a future
-     * call to {@link #fillable()} or {@link #onFail(Throwable)}
-     * @return true if a read is possible
-     * @throws IOException
+     * schedule a future call to {@link #fillable()} or {@link #onFail(Throwable)}
+     *
+     * @throws IOException if unable to fulfill interest in fill
      */
-    abstract protected boolean needsFill() throws IOException;
-    
-    
+    abstract protected void needsFillInterest() throws IOException;
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
index d8a6c27..563d0d6 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/IdleTimeout.java
@@ -28,7 +28,7 @@
 
 /**
  * An Abstract implementation of an Idle Timeout.
- * <p/>
+ * <p>
  * This implementation is optimised that timeout operations are not cancelled on
  * every operation. Rather timeout are allowed to expire and a check is then made
  * to see when the last operation took place.  If the idle timeout has not expired,
@@ -61,6 +61,11 @@
         _scheduler = scheduler;
     }
 
+    public Scheduler getScheduler()
+    {
+        return _scheduler;
+    }
+    
     public long getIdleTimestamp()
     {
         return _idleTimestamp;
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
new file mode 100644
index 0000000..546095c
--- /dev/null
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
@@ -0,0 +1,754 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.io;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ExecutionStrategy;
+import org.eclipse.jetty.util.thread.Locker;
+import org.eclipse.jetty.util.thread.Scheduler;
+
+/**
+ * <p>{@link ManagedSelector} wraps a {@link Selector} simplifying non-blocking operations on channels.</p>
+ * <p>{@link ManagedSelector} runs the select loop, which waits on {@link Selector#select()} until events
+ * happen for registered channels. When events happen, it notifies the {@link EndPoint} associated
+ * with the channel.</p>
+ */
+public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable
+{
+    private static final Logger LOG = Log.getLogger(ManagedSelector.class);
+
+    private final Locker _locker = new Locker();
+    private boolean _selecting = false;
+    private final Queue<Runnable> _actions = new ArrayDeque<>();
+    private final SelectorManager _selectorManager;
+    private final int _id;
+    private final ExecutionStrategy _strategy;
+    private Selector _selector;
+
+    public ManagedSelector(SelectorManager selectorManager, int id)
+    {
+        _selectorManager = selectorManager;
+        _id = id;
+        _strategy = ExecutionStrategy.Factory.instanceFor(new SelectorProducer(), selectorManager.getExecutor());
+        setStopTimeout(5000);
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+        _selector = newSelector();
+    }
+
+    protected Selector newSelector() throws IOException
+    {
+        return Selector.open();
+    }
+
+    public int size()
+    {
+        Selector s = _selector;
+        if (s == null)
+            return 0;
+        return s.keys().size();
+    }
+
+    @Override
+    protected void doStop() throws Exception
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Stopping {}", this);
+        CloseEndPoints close_endps = new CloseEndPoints();
+        submit(close_endps);
+        close_endps.await(getStopTimeout());
+        super.doStop();
+        CloseSelector close_selector = new CloseSelector();
+        submit(close_selector);
+        close_selector.await(getStopTimeout());
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Stopped {}", this);
+    }
+
+    public void submit(Runnable change)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Queued change {} on {}", change, this);
+
+        Selector selector = null;
+        try (Locker.Lock lock = _locker.lock())
+        {
+            _actions.offer(change);
+            if (_selecting)
+            {
+                selector = _selector;
+                // To avoid the extra select wakeup.
+                _selecting = false;
+            }
+        }
+        if (selector != null)
+            selector.wakeup();
+    }
+
+    @Override
+    public void run()
+    {
+        _strategy.execute();
+    }
+
+    /**
+     * A {@link SelectableEndPoint} is an {@link EndPoint} that wish to be
+     * notified of non-blocking events by the {@link ManagedSelector}.
+     */
+    public interface SelectableEndPoint extends EndPoint
+    {
+        /**
+         * Callback method invoked when a read or write events has been
+         * detected by the {@link ManagedSelector} for this endpoint.
+         *
+         * @return a job that may block or null
+         */
+        Runnable onSelected();
+
+        /**
+         * Callback method invoked when all the keys selected by the
+         * {@link ManagedSelector} for this endpoint have been processed.
+         */
+        void updateKey();
+    }
+
+    private class SelectorProducer implements ExecutionStrategy.Producer
+    {
+        private Set<SelectionKey> _keys = Collections.emptySet();
+        private Iterator<SelectionKey> _cursor = Collections.emptyIterator();
+
+        @Override
+        public Runnable produce()
+        {
+            while (true)
+            {
+                Runnable task = processSelected();
+                if (task != null)
+                    return task;
+
+                Runnable action = runActions();
+                if (action != null)
+                    return action;
+
+                update();
+
+                if (!select())
+                    return null;
+            }
+        }
+
+        private Runnable runActions()
+        {
+            while (true)
+            {
+                Runnable action;
+                try (Locker.Lock lock = _locker.lock())
+                {
+                    action = _actions.poll();
+                    if (action == null)
+                    {
+                        // No more actions, so we need to select
+                        _selecting = true;
+                        return null;
+                    }
+                }
+
+                if (action instanceof Product)
+                    return action;
+
+                // Running the change may queue another action.
+                runChange(action);
+            }
+        }
+
+        private void runChange(Runnable change)
+        {
+            try
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Running change {}", change);
+                change.run();
+            }
+            catch (Throwable x)
+            {
+                LOG.debug("Could not run change " + change, x);
+            }
+        }
+
+        private boolean select()
+        {
+            try
+            {
+                Selector selector = _selector;
+                if (selector != null && selector.isOpen())
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Selector loop waiting on select");
+                    int selected = selector.select();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Selector loop woken up from select, {}/{} selected", selected, selector.keys().size());
+
+                    try (Locker.Lock lock = _locker.lock())
+                    {
+                        // finished selecting
+                        _selecting = false;
+                    }
+
+                    _keys = selector.selectedKeys();
+                    _cursor = _keys.iterator();
+
+                    return true;
+                }
+            }
+            catch (Throwable x)
+            {
+                closeNoExceptions(_selector);
+                if (isRunning())
+                    LOG.warn(x);
+                else
+                    LOG.debug(x);
+            }
+            return false;
+        }
+
+        private Runnable processSelected()
+        {
+            while (_cursor.hasNext())
+            {
+                SelectionKey key = _cursor.next();
+                if (key.isValid())
+                {
+                    Object attachment = key.attachment();
+                    try
+                    {
+                        if (attachment instanceof SelectableEndPoint)
+                        {
+                            // Try to produce a task
+                            Runnable task = ((SelectableEndPoint)attachment).onSelected();
+                            if (task != null)
+                                return task;
+                        }
+                        else if (key.isConnectable())
+                        {
+                            Runnable task = processConnect(key, (Connect)attachment);
+                            if (task != null)
+                                return task;
+                        }
+                        else if (key.isAcceptable())
+                        {
+                            processAccept(key);
+                        }
+                        else
+                        {
+                            throw new IllegalStateException("key=" + key + ", att=" + attachment + ", iOps=" + key.interestOps() + ", rOps=" + key.readyOps());
+                        }
+                    }
+                    catch (CancelledKeyException x)
+                    {
+                        LOG.debug("Ignoring cancelled key for channel {}", key.channel());
+                        if (attachment instanceof EndPoint)
+                            closeNoExceptions((EndPoint)attachment);
+                    }
+                    catch (Throwable x)
+                    {
+                        LOG.warn("Could not process key for channel " + key.channel(), x);
+                        if (attachment instanceof EndPoint)
+                            closeNoExceptions((EndPoint)attachment);
+                    }
+                }
+                else
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Selector loop ignoring invalid key for channel {}", key.channel());
+                    Object attachment = key.attachment();
+                    if (attachment instanceof EndPoint)
+                        closeNoExceptions((EndPoint)attachment);
+                }
+            }
+            return null;
+        }
+
+        private void update()
+        {
+            for (SelectionKey key : _keys)
+                updateKey(key);
+            _keys.clear();
+        }
+
+        private void updateKey(SelectionKey key)
+        {
+            Object attachment = key.attachment();
+            if (attachment instanceof SelectableEndPoint)
+                ((SelectableEndPoint)attachment).updateKey();
+        }
+    }
+
+    private interface Product extends Runnable
+    {
+    }
+
+    private Runnable processConnect(SelectionKey key, final Connect connect)
+    {
+        SocketChannel channel = (SocketChannel)key.channel();
+        try
+        {
+            key.attach(connect.attachment);
+            boolean connected = _selectorManager.finishConnect(channel);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Connected {} {}", connected, channel);
+            if (connected)
+            {
+                if (connect.timeout.cancel())
+                {
+                    key.interestOps(0);
+                    return new CreateEndPoint(channel, key)
+                    {
+                        @Override
+                        protected void failed(Throwable failure)
+                        {
+                            super.failed(failure);
+                            connect.failed(failure);
+                        }
+                    };
+                }
+                else
+                {
+                    throw new SocketTimeoutException("Concurrent Connect Timeout");
+                }
+            }
+            else
+            {
+                throw new ConnectException();
+            }
+        }
+        catch (Throwable x)
+        {
+            connect.failed(x);
+            return null;
+        }
+    }
+
+    private void processAccept(SelectionKey key)
+    {
+        ServerSocketChannel server = (ServerSocketChannel)key.channel();
+        SocketChannel channel = null;
+        try
+        {
+            while ((channel = server.accept()) != null)
+            {
+                _selectorManager.accepted(channel);
+            }
+        }
+        catch (Throwable x)
+        {
+            closeNoExceptions(channel);
+            LOG.warn("Accept failed for channel " + channel, x);
+        }
+    }
+
+    private void closeNoExceptions(Closeable closeable)
+    {
+        try
+        {
+            if (closeable != null)
+                closeable.close();
+        }
+        catch (Throwable x)
+        {
+            LOG.ignore(x);
+        }
+    }
+
+    private EndPoint createEndPoint(SocketChannel channel, SelectionKey selectionKey) throws IOException
+    {
+        EndPoint endPoint = _selectorManager.newEndPoint(channel, this, selectionKey);
+        _selectorManager.endPointOpened(endPoint);
+        Connection connection = _selectorManager.newConnection(channel, endPoint, selectionKey.attachment());
+        endPoint.setConnection(connection);
+        selectionKey.attach(endPoint);
+        _selectorManager.connectionOpened(connection);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Created {}", endPoint);
+        return endPoint;
+    }
+
+    public void destroyEndPoint(final EndPoint endPoint)
+    {
+        final Connection connection = endPoint.getConnection();
+        submit(new Product()
+        {
+            @Override
+            public void run()
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Destroyed {}", endPoint);
+                if (connection != null)
+                    _selectorManager.connectionClosed(connection);
+                _selectorManager.endPointClosed(endPoint);
+            }
+        });
+    }
+
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_id)).append(System.lineSeparator());
+
+        Selector selector = _selector;
+        if (selector != null && selector.isOpen())
+        {
+            final ArrayList<Object> dump = new ArrayList<>(selector.keys().size() * 2);
+
+            DumpKeys dumpKeys = new DumpKeys(dump);
+            submit(dumpKeys);
+            dumpKeys.await(5, TimeUnit.SECONDS);
+
+            ContainerLifeCycle.dump(out, indent, dump);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        Selector selector = _selector;
+        return String.format("%s id=%s keys=%d selected=%d",
+                super.toString(),
+                _id,
+                selector != null && selector.isOpen() ? selector.keys().size() : -1,
+                selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1);
+    }
+
+    private class DumpKeys implements Runnable
+    {
+        private final CountDownLatch latch = new CountDownLatch(1);
+        private final List<Object> _dumps;
+
+        private DumpKeys(List<Object> dumps)
+        {
+            this._dumps = dumps;
+        }
+
+        @Override
+        public void run()
+        {
+            Selector selector = _selector;
+            if (selector != null && selector.isOpen())
+            {
+                Set<SelectionKey> keys = selector.keys();
+                _dumps.add(selector + " keys=" + keys.size());
+                for (SelectionKey key : keys)
+                {
+                    try
+                    {
+                        _dumps.add(String.format("SelectionKey@%x{i=%d}->%s", key.hashCode(), key.interestOps(), key.attachment()));
+                    }
+                    catch (Throwable x)
+                    {
+                        LOG.ignore(x);
+                    }
+                }
+            }
+            latch.countDown();
+        }
+
+        public boolean await(long timeout, TimeUnit unit)
+        {
+            try
+            {
+                return latch.await(timeout, unit);
+            }
+            catch (InterruptedException x)
+            {
+                return false;
+            }
+        }
+    }
+
+    class Acceptor implements Runnable
+    {
+        private final ServerSocketChannel _channel;
+
+        public Acceptor(ServerSocketChannel channel)
+        {
+            this._channel = channel;
+        }
+
+        @Override
+        public void run()
+        {
+            try
+            {
+                SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, null);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} acceptor={}", this, key);
+            }
+            catch (Throwable x)
+            {
+                closeNoExceptions(_channel);
+                LOG.warn(x);
+            }
+        }
+    }
+
+    class Accept implements Runnable
+    {
+        private final SocketChannel channel;
+        private final Object attachment;
+
+        Accept(SocketChannel channel, Object attachment)
+        {
+            this.channel = channel;
+            this.attachment = attachment;
+        }
+
+        @Override
+        public void run()
+        {
+            try
+            {
+                final SelectionKey key = channel.register(_selector, 0, attachment);
+                submit(new CreateEndPoint(channel, key));
+            }
+            catch (Throwable x)
+            {
+                closeNoExceptions(channel);
+                LOG.debug(x);
+            }
+        }
+    }
+
+    private class CreateEndPoint implements Product
+    {
+        private final SocketChannel channel;
+        private final SelectionKey key;
+
+        public CreateEndPoint(SocketChannel channel, SelectionKey key)
+        {
+            this.channel = channel;
+            this.key = key;
+        }
+
+        @Override
+        public void run()
+        {
+            try
+            {
+                createEndPoint(channel, key);
+            }
+            catch (Throwable x)
+            {
+                LOG.debug(x);
+                failed(x);
+            }
+        }
+
+        protected void failed(Throwable failure)
+        {
+            closeNoExceptions(channel);
+            LOG.debug(failure);
+        }
+    }
+
+    class Connect implements Runnable
+    {
+        private final AtomicBoolean failed = new AtomicBoolean();
+        private final SocketChannel channel;
+        private final Object attachment;
+        private final Scheduler.Task timeout;
+
+        Connect(SocketChannel channel, Object attachment)
+        {
+            this.channel = channel;
+            this.attachment = attachment;
+            this.timeout = ManagedSelector.this._selectorManager.getScheduler().schedule(new ConnectTimeout(this), ManagedSelector.this._selectorManager.getConnectTimeout(), TimeUnit.MILLISECONDS);
+        }
+
+        @Override
+        public void run()
+        {
+            try
+            {
+                channel.register(_selector, SelectionKey.OP_CONNECT, this);
+            }
+            catch (Throwable x)
+            {
+                failed(x);
+            }
+        }
+
+        private void failed(Throwable failure)
+        {
+            if (failed.compareAndSet(false, true))
+            {
+                timeout.cancel();
+                closeNoExceptions(channel);
+                ManagedSelector.this._selectorManager.connectionFailed(channel, failure, attachment);
+            }
+        }
+    }
+
+    private class ConnectTimeout implements Runnable
+    {
+        private final Connect connect;
+
+        private ConnectTimeout(Connect connect)
+        {
+            this.connect = connect;
+        }
+
+        @Override
+        public void run()
+        {
+            SocketChannel channel = connect.channel;
+            if (channel.isConnectionPending())
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Channel {} timed out while connecting, closing it", channel);
+                connect.failed(new SocketTimeoutException("Connect Timeout"));
+            }
+        }
+    }
+
+    private class CloseEndPoints implements Runnable
+    {
+        private final CountDownLatch _latch = new CountDownLatch(1);
+        private CountDownLatch _allClosed;
+
+        @Override
+        public void run()
+        {
+            List<EndPoint> end_points = new ArrayList<>();
+            for (SelectionKey key : _selector.keys())
+            {
+                if (key.isValid())
+                {
+                    Object attachment = key.attachment();
+                    if (attachment instanceof EndPoint)
+                        end_points.add((EndPoint)attachment);
+                }
+            }
+
+            int size = end_points.size();
+            if (LOG.isDebugEnabled())
+                LOG.debug("Closing {} endPoints on {}", size, ManagedSelector.this);
+
+            _allClosed = new CountDownLatch(size);
+            _latch.countDown();
+
+            for (EndPoint endp : end_points)
+                submit(new EndPointCloser(endp, _allClosed));
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Closed {} endPoints on {}", size, ManagedSelector.this);
+        }
+
+        public boolean await(long timeout)
+        {
+            try
+            {
+                return _latch.await(timeout, TimeUnit.MILLISECONDS) &&
+                        _allClosed.await(timeout, TimeUnit.MILLISECONDS);
+            }
+            catch (InterruptedException x)
+            {
+                return false;
+            }
+        }
+    }
+
+    private class EndPointCloser implements Product
+    {
+        private final EndPoint _endPoint;
+        private final CountDownLatch _latch;
+
+        private EndPointCloser(EndPoint endPoint, CountDownLatch latch)
+        {
+            _endPoint = endPoint;
+            _latch = latch;
+        }
+
+        @Override
+        public void run()
+        {
+            closeNoExceptions(_endPoint.getConnection());
+            _latch.countDown();
+        }
+    }
+
+    private class CloseSelector implements Runnable
+    {
+        private CountDownLatch _latch = new CountDownLatch(1);
+
+        @Override
+        public void run()
+        {
+            Selector selector = _selector;
+            _selector = null;
+            closeNoExceptions(selector);
+            _latch.countDown();
+        }
+
+        public boolean await(long timeout)
+        {
+            try
+            {
+                return _latch.await(timeout, TimeUnit.MILLISECONDS);
+            }
+            catch (InterruptedException x)
+            {
+                return false;
+            }
+        }
+    }
+}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java
index f0a8b1f..c6cfb30 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NegotiatingClientConnection.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.io;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.util.Map;
 import java.util.concurrent.Executor;
 
@@ -109,9 +108,7 @@
         EndPoint endPoint = getEndPoint();
         try
         {
-            Connection oldConnection = endPoint.getConnection();
-            Connection newConnection = connectionFactory.newConnection(endPoint, context);
-            ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection);
+            endPoint.upgrade(connectionFactory.newConnection(endPoint, context));
         }
         catch (Throwable x)
         {
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java
index 3a04207..288bb2d 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficListener.java
@@ -67,7 +67,7 @@
     /**
      * <p>Callback method invoked when a connection to a remote client has been closed.</p>
      * <p>The {@code socket} parameter is already closed when this method is called, so it
-     * cannot be queried for socket address information of the remote client.<br />
+     * cannot be queried for socket address information of the remote client.<br>
      * However, the {@code socket} parameter is the same object passed to {@link #opened(Socket)},
      * so it is possible to map socket information in {@link #opened(Socket)} and retrieve it
      * in this method.
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
index bf7606b..ef1ba33 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
@@ -35,7 +35,7 @@
 
     private final List<NetworkTrafficListener> listeners;
 
-    public NetworkTrafficSelectChannelEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selectSet, SelectionKey key, Scheduler scheduler, long idleTimeout, List<NetworkTrafficListener> listeners) throws IOException
+    public NetworkTrafficSelectChannelEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key, Scheduler scheduler, long idleTimeout, List<NetworkTrafficListener> listeners) throws IOException
     {
         super(channel, selectSet, key, scheduler, idleTimeout);
         this.listeners = listeners;
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
index 6eec73d..e7587bd 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java
@@ -22,144 +22,236 @@
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
 
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Locker;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 /**
  * An ChannelEndpoint that can be scheduled by {@link SelectorManager}.
  */
-public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorManager.SelectableEndPoint
+public class SelectChannelEndPoint extends ChannelEndPoint implements ManagedSelector.SelectableEndPoint
 {
     public static final Logger LOG = Log.getLogger(SelectChannelEndPoint.class);
 
-    private final Runnable _updateTask = new Runnable()
-    {
-        @Override
-        public void run()
-        {
-            try
-            {
-                if (getChannel().isOpen())
-                {
-                    int oldInterestOps = _key.interestOps();
-                    int newInterestOps = _interestOps.get();
-                    if (newInterestOps != oldInterestOps)
-                        setKeyInterests(oldInterestOps, newInterestOps);
-                }
-            }
-            catch (CancelledKeyException x)
-            {
-                LOG.debug("Ignoring key update for concurrently closed channel {}", this);
-                close();
-            }
-            catch (Exception x)
-            {
-                LOG.warn("Ignoring key update for " + this, x);
-                close();
-            }
-        }
-    };
+    private final Locker _locker = new Locker();
+    private boolean _updatePending;
 
     /**
      * true if {@link ManagedSelector#destroyEndPoint(EndPoint)} has not been called
      */
     private final AtomicBoolean _open = new AtomicBoolean();
-    private final SelectorManager.ManagedSelector _selector;
+    private final ManagedSelector _selector;
     private final SelectionKey _key;
     /**
-     * The desired value for {@link SelectionKey#interestOps()}
+     * The current value for {@link SelectionKey#interestOps()}.
      */
-    private final AtomicInteger _interestOps = new AtomicInteger();
+    private int _currentInterestOps;
+    /**
+     * The desired value for {@link SelectionKey#interestOps()}.
+     */
+    private int _desiredInterestOps;
+
+    private final Runnable _runUpdateKey = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            updateKey();
+        }
+
+        @Override
+        public String toString()
+        {
+            return SelectChannelEndPoint.this.toString()+":runUpdateKey";
+        }
+    };
+    private final Runnable _runFillable = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            getFillInterest().fillable();
+        }
+
+        @Override
+        public String toString()
+        {
+            return SelectChannelEndPoint.this.toString()+":runFillable";
+        }
+    };
+    private final Runnable _runCompleteWrite = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            getWriteFlusher().completeWrite();
+        }
+
+        @Override
+        public String toString()
+        {
+            return SelectChannelEndPoint.this.toString()+":runCompleteWrite";
+        }
+    };
+    private final Runnable _runFillableCompleteWrite = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            getFillInterest().fillable();
+            getWriteFlusher().completeWrite();
+        }
+
+        @Override
+        public String toString()
+        {
+            return SelectChannelEndPoint.this.toString()+":runFillableCompleteWrite";
+        }
+    };
 
     public SelectChannelEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey key, Scheduler scheduler, long idleTimeout)
     {
-        super(scheduler,channel);
+        super(scheduler, channel);
         _selector = selector;
         _key = key;
         setIdleTimeout(idleTimeout);
     }
 
     @Override
-    protected boolean needsFill()
+    protected void needsFillInterest()
     {
-        updateLocalInterests(SelectionKey.OP_READ, true);
-        return false;
+        changeInterests(SelectionKey.OP_READ);
     }
 
     @Override
     protected void onIncompleteFlush()
     {
-        updateLocalInterests(SelectionKey.OP_WRITE, true);
+        changeInterests(SelectionKey.OP_WRITE);
     }
 
     @Override
-    public void onSelected()
+    public Runnable onSelected()
     {
-        assert _selector.isSelectorThread();
-        int oldInterestOps = _key.interestOps();
+        /**
+         * This method may run concurrently with {@link #changeInterests(int)}.
+         */
+
         int readyOps = _key.readyOps();
-        int newInterestOps = oldInterestOps & ~readyOps;
-        setKeyInterests(oldInterestOps, newInterestOps);
-        updateLocalInterests(readyOps, false);
-        if (_key.isReadable())
-            getFillInterest().fillable();
-        if (_key.isWritable())
-            getWriteFlusher().completeWrite();
+        int oldInterestOps;
+        int newInterestOps;
+        try (Locker.Lock lock = _locker.lock())
+        {
+            _updatePending = true;
+            // Remove the readyOps, that here can only be OP_READ or OP_WRITE (or both).
+            oldInterestOps = _desiredInterestOps;
+            newInterestOps = oldInterestOps & ~readyOps;
+            _desiredInterestOps = newInterestOps;
+        }
+
+
+        boolean readable = (readyOps & SelectionKey.OP_READ) != 0;
+        boolean writable = (readyOps & SelectionKey.OP_WRITE) != 0;
+
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("onSelected {}->{} r={} w={} for {}", oldInterestOps, newInterestOps, readable, writable, this);
+        
+        // Run non-blocking code immediately.
+        // This producer knows that this non-blocking code is special
+        // and that it must be run in this thread and not fed to the
+        // ExecutionStrategy, which could not have any thread to run these
+        // tasks (or it may starve forever just after having run them).
+        if (readable && getFillInterest().isCallbackNonBlocking())
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Direct readable run {}",this);
+            _runFillable.run();
+            readable = false;
+        }
+        if (writable && getWriteFlusher().isCallbackNonBlocking())
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Direct writable run {}",this);
+            _runCompleteWrite.run();
+            writable = false;
+        }
+
+        // return task to complete the job
+        Runnable task= readable ? (writable ? _runFillableCompleteWrite : _runFillable)
+                : (writable ? _runCompleteWrite : null);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("task {}",task);
+        return task;
     }
 
-
-    private void updateLocalInterests(int operation, boolean add)
+    @Override
+    public void updateKey()
     {
-        while (true)
+        /**
+         * This method may run concurrently with {@link #changeInterests(int)}.
+         */
+
+        try
         {
-            int oldInterestOps = _interestOps.get();
+            int oldInterestOps;
             int newInterestOps;
-            if (add)
-                newInterestOps = oldInterestOps | operation;
-            else
-                newInterestOps = oldInterestOps & ~operation;
-
-            if (isInputShutdown())
-                newInterestOps &= ~SelectionKey.OP_READ;
-            if (isOutputShutdown())
-                newInterestOps &= ~SelectionKey.OP_WRITE;
-
-            if (newInterestOps != oldInterestOps)
+            try (Locker.Lock lock = _locker.lock())
             {
-                if (_interestOps.compareAndSet(oldInterestOps, newInterestOps))
+                _updatePending = false;
+                oldInterestOps = _currentInterestOps;
+                newInterestOps = _desiredInterestOps;
+                if (oldInterestOps != newInterestOps)
                 {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Local interests updating {} -> {} for {}", oldInterestOps, newInterestOps, this);
-                    _selector.updateKey(_updateTask);
-                }
-                else
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this);
-                    continue;
+                    _currentInterestOps = newInterestOps;
+                    _key.interestOps(newInterestOps);
                 }
             }
-            else
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this);
-            }
-            break;
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Key interests updated {} -> {} on {}", oldInterestOps, newInterestOps, this);
+        }
+        catch (CancelledKeyException x)
+        {
+            LOG.debug("Ignoring key update for concurrently closed channel {}", this);
+            close();
+        }
+        catch (Throwable x)
+        {
+            LOG.warn("Ignoring key update for " + this, x);
+            close();
         }
     }
 
-
-    private void setKeyInterests(int oldInterestOps, int newInterestOps)
+    private void changeInterests(int operation)
     {
-        _key.interestOps(newInterestOps);
+        /**
+         * This method may run concurrently with
+         * {@link #updateKey()} and {@link #onSelected()}.
+         */
+
+        int oldInterestOps;
+        int newInterestOps;
+        boolean pending;
+        try (Locker.Lock lock = _locker.lock())
+        {
+            pending = _updatePending;
+            oldInterestOps = _desiredInterestOps;
+            newInterestOps = oldInterestOps | operation;
+            if (newInterestOps != oldInterestOps)
+                _desiredInterestOps = newInterestOps;
+        }
+
         if (LOG.isDebugEnabled())
-            LOG.debug("Key interests updated {} -> {} on {}", oldInterestOps, newInterestOps, this);
+            LOG.debug("changeInterests p={} {}->{} for {}", pending, oldInterestOps, newInterestOps, this);
+
+        if (!pending)
+            _selector.submit(_runUpdateKey);
     }
 
+
     @Override
     public void close()
     {
@@ -189,23 +281,22 @@
     @Override
     public String toString()
     {
-        // Do NOT use synchronized (this)
-        // because it's very easy to deadlock when debugging is enabled.
         // We do a best effort to print the right toString() and that's it.
         try
         {
-            boolean valid = _key!=null && _key.isValid();
+            boolean valid = _key != null && _key.isValid();
             int keyInterests = valid ? _key.interestOps() : -1;
             int keyReadiness = valid ? _key.readyOps() : -1;
-            return String.format("%s{io=%d,kio=%d,kro=%d}",
+            return String.format("%s{io=%d/%d,kio=%d,kro=%d}",
                     super.toString(),
-                    _interestOps.get(),
+                    _currentInterestOps,
+                    _desiredInterestOps,
                     keyInterests,
                     keyReadiness);
         }
-        catch (CancelledKeyException x)
+        catch (Throwable x)
         {
-            return String.format("%s{io=%s,kio=-2,kro=-2}", super.toString(), _interestOps.get());
+            return String.format("%s{io=%s,kio=-2,kro=-2}", super.toString(), _desiredInterestOps);
         }
     }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
index 47f188a..d13b8ac 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java
@@ -18,36 +18,21 @@
 
 package org.eclipse.jetty.io;
 
-import java.io.Closeable;
 import java.io.IOException;
-import java.net.ConnectException;
+import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
-import java.net.SocketTimeoutException;
-import java.nio.channels.CancelledKeyException;
 import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
 
-import org.eclipse.jetty.util.ConcurrentArrayQueue;
 import org.eclipse.jetty.util.TypeUtil;
-import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.NonBlockingThread;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 /**
@@ -58,18 +43,15 @@
  */
 public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
 {
-    public static final String SUBMIT_KEY_UPDATES = "org.eclipse.jetty.io.SelectorManager.submitKeyUpdates";
     public static final int DEFAULT_CONNECT_TIMEOUT = 15000;
     protected static final Logger LOG = Log.getLogger(SelectorManager.class);
-    private final static boolean __submitKeyUpdates = Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES, "true"));
-    
+
     private final Executor executor;
     private final Scheduler scheduler;
     private final ManagedSelector[] _selectors;
     private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT;
     private long _selectorIndex;
-    private int _priorityDelta;
-    
+
     protected SelectorManager(Executor executor, Scheduler scheduler)
     {
         this(executor, scheduler, (Runtime.getRuntime().availableProcessors() + 1) / 2);
@@ -77,7 +59,7 @@
 
     protected SelectorManager(Executor executor, Scheduler scheduler, int selectors)
     {
-        if (selectors<=0)
+        if (selectors <= 0)
             throw new IllegalArgumentException("No selectors");
         this.executor = executor;
         this.scheduler = scheduler;
@@ -114,42 +96,25 @@
         _connectTimeout = milliseconds;
     }
 
-
-    @ManagedAttribute("The priority delta to apply to selector threads")
+    /**
+     * @return the selector priority delta
+     * @deprecated not implemented
+     */
+    @Deprecated
     public int getSelectorPriorityDelta()
     {
-        return _priorityDelta;
+        return 0;
     }
 
     /**
-     * Sets the selector thread priority delta to the given amount.
-     * <p>This allows the selector threads to run at a different priority.
-     * Typically this would be used to lower the priority to give preference
-     * to handling previously accepted connections rather than accepting
-     * new connections.</p>
-     *
-     * @param selectorPriorityDelta the amount to change the thread priority
-     *                              delta to (may be negative)
-     * @see Thread#getPriority()
+     * @param selectorPriorityDelta the selector priority delta
+     * @deprecated not implemented
      */
+    @Deprecated
     public void setSelectorPriorityDelta(int selectorPriorityDelta)
     {
-        int oldDelta = _priorityDelta;
-        _priorityDelta = selectorPriorityDelta;
-        if (oldDelta != selectorPriorityDelta && isStarted())
-        {
-            for (ManagedSelector selector : _selectors)
-            {
-                Thread thread = selector._thread;
-                if (thread != null)
-                {
-                    int deltaDiff = selectorPriorityDelta - oldDelta;
-                    thread.setPriority(Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY, thread.getPriority() - deltaDiff)));
-                }
-            }
-        }
     }
-    
+
     /**
      * Executes the given task in a different thread.
      *
@@ -168,14 +133,45 @@
         return _selectors.length;
     }
 
-    private ManagedSelector chooseSelector()
+    private ManagedSelector chooseSelector(SocketChannel channel)
     {
+        // Ideally we would like to have all connections from the same client end
+        // up on the same selector (to try to avoid smearing the data from a single 
+        // client over all cores), but because of proxies, the remote address may not
+        // really be the client - so we have to hedge our bets to ensure that all
+        // channels don't end up on the one selector for a proxy.
+        ManagedSelector candidate1 = null;
+        if (channel != null)
+        {
+            try
+            {
+                SocketAddress remote = channel.getRemoteAddress();
+                if (remote instanceof InetSocketAddress)
+                {
+                    byte[] addr = ((InetSocketAddress)remote).getAddress().getAddress();
+                    if (addr != null)
+                    {
+                        int s = addr[addr.length - 1] & 0xFF;
+                        candidate1 = _selectors[s % getSelectorCount()];
+                    }
+                }
+            }
+            catch (IOException x)
+            {
+                LOG.ignore(x);
+            }
+        }
+
         // The ++ increment here is not atomic, but it does not matter,
         // so long as the value changes sometimes, then connections will
         // be distributed over the available selectors.
         long s = _selectorIndex++;
         int index = (int)(s % getSelectorCount());
-        return _selectors[index];
+        ManagedSelector candidate2 = _selectors[index];
+
+        if (candidate1 == null || candidate1.size() >= candidate2.size() * 2)
+            return candidate2;
+        return candidate1;
     }
 
     /**
@@ -190,11 +186,12 @@
      */
     public void connect(SocketChannel channel, Object attachment)
     {
-        ManagedSelector set = chooseSelector();
+        ManagedSelector set = chooseSelector(channel);
         set.submit(set.new Connect(channel, attachment));
     }
 
     /**
+     * @param channel the channel to accept
      * @see #accept(SocketChannel, Object)
      */
     public void accept(SocketChannel channel)
@@ -209,29 +206,29 @@
      * just after a non-blocking connect via {@link SocketChannel#connect(SocketAddress)} that completed
      * successfully.</p>
      *
-     * @param channel the channel to register
+     * @param channel    the channel to register
      * @param attachment the attachment object
      */
     public void accept(SocketChannel channel, Object attachment)
     {
-        final ManagedSelector selector = chooseSelector();
+        final ManagedSelector selector = chooseSelector(channel);
         selector.submit(selector.new Accept(channel, attachment));
     }
-    
+
     /**
      * <p>Registers a server channel for accept operations.
      * When a {@link SocketChannel} is accepted from the given {@link ServerSocketChannel}
      * then the {@link #accepted(SocketChannel)} method is called, which must be
      * overridden by a derivation of this class to handle the accepted channel
-     * 
+     *
      * @param server the server channel to register
      */
     public void acceptor(ServerSocketChannel server)
     {
-        final ManagedSelector selector = chooseSelector();
+        final ManagedSelector selector = chooseSelector(null);
         selector.submit(selector.new Acceptor(server));
     }
-    
+
     /**
      * Callback method when a channel is accepted from the {@link ServerSocketChannel}
      * passed to {@link #acceptor(ServerSocketChannel)}.
@@ -239,7 +236,7 @@
      * be overridden by subclasses if a server channel is provided.
      *
      * @param channel the
-     * @throws IOException
+     * @throws IOException if unable to accept channel
      */
     protected void accepted(SocketChannel channel) throws IOException
     {
@@ -255,7 +252,7 @@
             ManagedSelector selector = newSelector(i);
             _selectors[i] = selector;
             selector.start();
-            execute(new NonBlockingThread(selector));
+            execute(selector);
         }
     }
 
@@ -267,7 +264,7 @@
      */
     protected ManagedSelector newSelector(int id)
     {
-        return new ManagedSelector(id);
+        return new ManagedSelector(this, id);
     }
 
     @Override
@@ -344,8 +341,8 @@
      * <p>Callback method invoked when a non-blocking connect cannot be completed.</p>
      * <p>By default it just logs with level warning.</p>
      *
-     * @param channel the channel that attempted the connect
-     * @param ex the exception that caused the connect to fail
+     * @param channel    the channel that attempted the connect
+     * @param ex         the exception that caused the connect to fail
      * @param attachment the attachment object associated at registration
      */
     protected void connectionFailed(SocketChannel channel, Throwable ex, Object attachment)
@@ -358,14 +355,14 @@
      * <p>This method is invoked as a result of the registration of a channel via {@link #connect(SocketChannel, Object)}
      * or {@link #accept(SocketChannel)}.</p>
      *
-     * @param channel   the channel associated to the endpoint
-     * @param selector the selector the channel is registered to
-     * @param selectionKey      the selection key
+     * @param channel      the channel associated to the endpoint
+     * @param selector     the selector the channel is registered to
+     * @param selectionKey the selection key
      * @return a new endpoint
      * @throws IOException if the endPoint cannot be created
      * @see #newConnection(SocketChannel, EndPoint, Object)
      */
-    protected abstract EndPoint newEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selector, SelectionKey selectionKey) throws IOException;
+    protected abstract EndPoint newEndPoint(SocketChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException;
 
     /**
      * <p>Factory method to create {@link Connection}.</p>
@@ -374,7 +371,7 @@
      * @param endpoint   the endpoint
      * @param attachment the attachment
      * @return a new connection
-     * @throws IOException
+     * @throws IOException if unable to create new connection
      * @see #newEndPoint(SocketChannel, ManagedSelector, SelectionKey)
      */
     public abstract Connection newConnection(SocketChannel channel, EndPoint endpoint, Object attachment) throws IOException;
@@ -391,674 +388,4 @@
         ContainerLifeCycle.dumpObject(out, this);
         ContainerLifeCycle.dump(out, indent, TypeUtil.asList(_selectors));
     }
-
-    private enum State
-    {
-        CHANGES, MORE_CHANGES, SELECT, WAKEUP, PROCESS
-    }
-
-    /**
-     * <p>{@link ManagedSelector} wraps a {@link Selector} simplifying non-blocking operations on channels.</p>
-     * <p>{@link ManagedSelector} runs the select loop, which waits on {@link Selector#select()} until events
-     * happen for registered channels. When events happen, it notifies the {@link EndPoint} associated
-     * with the channel.</p>
-     */
-    public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable
-    {
-        private final AtomicReference<State> _state= new AtomicReference<>(State.PROCESS);
-        private final Queue<Runnable> _changes = new ConcurrentArrayQueue<>();
-        private final int _id;
-        private Selector _selector;
-        private volatile Thread _thread;
-
-        public ManagedSelector(int id)
-        {
-            _id = id;
-            setStopTimeout(5000);
-        }
-
-        @Override
-        protected void doStart() throws Exception
-        {
-            super.doStart();
-            _selector = Selector.open();
-            _state.set(State.PROCESS);
-        }
-
-        @Override
-        protected void doStop() throws Exception
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Stopping {}", this);
-            Stop stop = new Stop();
-            submit(stop);
-            stop.await(getStopTimeout());
-            if (LOG.isDebugEnabled())
-                LOG.debug("Stopped {}", this);
-        }
-
-        /**
-         * Submit a task to update a selector key.  If the System property {@link SelectorManager#SUBMIT_KEY_UPDATES}
-         * is set true (default is false), the task is passed to {@link #submit(Runnable)}.   Otherwise it is run immediately and the selector 
-         * woken up if need be.   
-         * @param update the update to a key
-         */
-        public void updateKey(Runnable update)
-        {
-            if (__submitKeyUpdates)
-            {
-                submit(update);
-            }
-            else
-            {
-                // Run only 1 change at once
-                synchronized (this)
-                {
-                    runChange(update);
-                }
-                if (_state.compareAndSet(State.SELECT, State.WAKEUP))
-                   wakeup();
-            }
-        }
-        
-        /**
-         * <p>Submits a change to be executed in the selector thread.</p>
-         * <p>Changes may be submitted from any thread, and the selector thread woken up
-         * (if necessary) to execute the change.</p>
-         *
-         * @param change the change to submit
-         */
-        public void submit(Runnable change)
-        {
-            // This method may be called from the selector thread, and therefore
-            // we could directly run the change without queueing, but this may
-            // lead to stack overflows on a busy server, so we always offer the
-            // change to the queue and process the state.
-
-            _changes.offer(change);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Queued change {}", change);
-
-            out: while (true)
-            {
-                switch (_state.get())
-                {
-                    case SELECT:
-                        // Avoid multiple wakeup() calls if we the CAS fails
-                        if (!_state.compareAndSet(State.SELECT, State.WAKEUP))
-                            continue;
-                        wakeup();
-                        break out;
-                    case CHANGES:
-                        // Tell the selector thread that we have more changes.
-                        // If we fail to CAS, we possibly need to wakeup(), so loop.
-                        if (_state.compareAndSet(State.CHANGES, State.MORE_CHANGES))
-                            break out;
-                        continue;
-                    case WAKEUP:
-                        // Do nothing, we have already a wakeup scheduled
-                        break out;
-                    case MORE_CHANGES:
-                        // Do nothing, we already notified the selector thread of more changes
-                        break out;
-                    case PROCESS:
-                        // Do nothing, the changes will be run after the processing
-                        break out;
-                    default:
-                        throw new IllegalStateException();
-                }
-            }
-        }
-
-        private void runChanges()
-        {
-            Runnable change;
-            while ((change = _changes.poll()) != null)
-                runChange(change);
-        }
-
-        protected void runChange(Runnable change)
-        {
-            try
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Running change {}", change);
-                change.run();
-            }
-            catch (Throwable x)
-            {
-                LOG.debug("Could not run change " + change, x);
-            }
-        }
-
-        @Override
-        public void run()
-        {
-            _thread = Thread.currentThread();
-            String name = _thread.getName();
-            int priority = _thread.getPriority();
-            try
-            {
-                if (_priorityDelta != 0)
-                    _thread.setPriority(Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY, priority + _priorityDelta)));
-
-                _thread.setName(String.format("%s-selector-%s@%h/%d", name, SelectorManager.this.getClass().getSimpleName(), SelectorManager.this.hashCode(), _id));
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Starting {} on {}", _thread, this);
-                while (isRunning())
-                    select();
-                while(isStopping())
-                    runChanges();
-            }
-            finally
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Stopped {} on {}", _thread, this);
-                _thread.setName(name);
-                if (_priorityDelta != 0)
-                    _thread.setPriority(priority);
-            }
-        }
-
-        /**
-         * <p>Process changes and waits on {@link Selector#select()}.</p>
-         *
-         * @see #submit(Runnable)
-         */
-        public void select()
-        {
-            boolean debug = LOG.isDebugEnabled();
-            try
-            {
-                _state.set(State.CHANGES);
-
-                // Run the changes, and only exit if we ran all changes
-                out: while(true)
-                {
-                    switch (_state.get())
-                    {
-                        case CHANGES:
-                            runChanges();
-                            if (_state.compareAndSet(State.CHANGES, State.SELECT))
-                                break out;
-                            continue;
-                        case MORE_CHANGES:
-                            runChanges();
-                            _state.set(State.CHANGES);
-                            continue;
-                        default:
-                            throw new IllegalStateException();    
-                    }
-                }
-                // Must check first for SELECT and *then* for WAKEUP
-                // because we read the state twice in the assert, and
-                // it could change from SELECT to WAKEUP in between.
-                assert _state.get() == State.SELECT || _state.get() == State.WAKEUP;
-
-                if (debug)
-                    LOG.debug("Selector loop waiting on select");
-                int selected = _selector.select();
-                if (debug)
-                    LOG.debug("Selector loop woken up from select, {}/{} selected", selected, _selector.keys().size());
-
-                _state.set(State.PROCESS);
-
-                Set<SelectionKey> selectedKeys = _selector.selectedKeys();
-                for (SelectionKey key : selectedKeys)
-                {
-                    if (key.isValid())
-                    {
-                        processKey(key);
-                    }
-                    else
-                    {
-                        if (debug)
-                            LOG.debug("Selector loop ignoring invalid key for channel {}", key.channel());
-                        Object attachment = key.attachment();
-                        if (attachment instanceof EndPoint)
-                            ((EndPoint)attachment).close();
-                    }
-                }
-                selectedKeys.clear();
-            }
-            catch (Throwable x)
-            {
-                if (isRunning())
-                    LOG.warn(x);
-                else
-                    LOG.ignore(x);
-            }
-        }
-
-        private void processKey(SelectionKey key)
-        {
-            Object attachment = key.attachment();
-            try
-            {
-                if (attachment instanceof SelectableEndPoint)
-                {
-                    ((SelectableEndPoint)attachment).onSelected();
-                }
-                else if (key.isConnectable())
-                {
-                    processConnect(key, (Connect)attachment);
-                }
-                else if (key.isAcceptable())
-                {
-                    processAccept(key);
-                }
-                else
-                {
-                    throw new IllegalStateException();
-                }
-            }
-            catch (CancelledKeyException x)
-            {
-                LOG.debug("Ignoring cancelled key for channel {}", key.channel());
-                if (attachment instanceof EndPoint)
-                    closeNoExceptions((EndPoint)attachment);
-            }
-            catch (Throwable x)
-            {
-                LOG.warn("Could not process key for channel " + key.channel(), x);
-                if (attachment instanceof EndPoint)
-                    closeNoExceptions((EndPoint)attachment);
-            }
-        }
-
-        private void processConnect(SelectionKey key, Connect connect)
-        {
-            SocketChannel channel = (SocketChannel)key.channel();
-            try
-            {
-                key.attach(connect.attachment);
-                boolean connected = finishConnect(channel);
-                if (connected)
-                {
-                    if (connect.timeout.cancel())
-                    {
-                        key.interestOps(0);
-                        EndPoint endpoint = createEndPoint(channel, key);
-                        key.attach(endpoint);
-                    }
-                    else
-                    {
-                        throw new SocketTimeoutException("Concurrent Connect Timeout");
-                    }
-                }
-                else
-                {
-                    throw new ConnectException();
-                }
-            }
-            catch (Throwable x)
-            {
-                connect.failed(x);
-            }
-        }
-        
-        private void processAccept(SelectionKey key)
-        {
-            ServerSocketChannel server = (ServerSocketChannel)key.channel();
-            SocketChannel channel = null;
-            try
-            {
-                while ((channel = server.accept()) != null)
-                {
-                    accepted(channel);
-                }
-            }
-            catch (Throwable x)
-            {
-                closeNoExceptions(channel);
-                LOG.warn("Accept failed for channel " + channel, x);
-            }
-        }
-
-        private void closeNoExceptions(Closeable closeable)
-        {
-            try
-            {
-                if (closeable != null)
-                    closeable.close();
-            }
-            catch (Throwable x)
-            {
-                LOG.ignore(x);
-            }
-        }
-
-        public void wakeup()
-        {
-            _selector.wakeup();
-        }
-
-        public boolean isSelectorThread()
-        {
-            return Thread.currentThread() == _thread;
-        }
-
-        private EndPoint createEndPoint(SocketChannel channel, SelectionKey selectionKey) throws IOException
-        {
-            EndPoint endPoint = newEndPoint(channel, this, selectionKey);
-            endPointOpened(endPoint);
-            Connection connection = newConnection(channel, endPoint, selectionKey.attachment());
-            endPoint.setConnection(connection);
-            connectionOpened(connection);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Created {}", endPoint);
-            return endPoint;
-        }
-
-        public void destroyEndPoint(EndPoint endPoint)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Destroyed {}", endPoint);
-            Connection connection = endPoint.getConnection();
-            if (connection != null)
-                connectionClosed(connection);
-            endPointClosed(endPoint);
-        }
-
-        @Override
-        public String dump()
-        {
-            return ContainerLifeCycle.dump(this);
-        }
-
-        @Override
-        public void dump(Appendable out, String indent) throws IOException
-        {
-            out.append(String.valueOf(this)).append(" id=").append(String.valueOf(_id)).append("\n");
-
-            Thread selecting = _thread;
-
-            Object where = "not selecting";
-            StackTraceElement[] trace = selecting == null ? null : selecting.getStackTrace();
-            if (trace != null)
-            {
-                for (StackTraceElement t : trace)
-                    if (t.getClassName().startsWith("org.eclipse.jetty."))
-                    {
-                        where = t;
-                        break;
-                    }
-            }
-
-            Selector selector = _selector;
-            if (selector != null && selector.isOpen())
-            {
-                final ArrayList<Object> dump = new ArrayList<>(selector.keys().size() * 2);
-                dump.add(where);
-
-                DumpKeys dumpKeys = new DumpKeys(dump);
-                submit(dumpKeys);
-                dumpKeys.await(5, TimeUnit.SECONDS);
-
-                ContainerLifeCycle.dump(out, indent, dump);
-            }
-        }
-
-        public void dumpKeysState(List<Object> dumps)
-        {
-            Selector selector = _selector;
-            Set<SelectionKey> keys = selector.keys();
-            dumps.add(selector + " keys=" + keys.size());
-            for (SelectionKey key : keys)
-            {
-                if (key.isValid())
-                    dumps.add(key.attachment() + " iOps=" + key.interestOps() + " rOps=" + key.readyOps());
-                else
-                    dumps.add(key.attachment() + " iOps=-1 rOps=-1");
-            }
-        }
-
-        @Override
-        public String toString()
-        {
-            Selector selector = _selector;
-            return String.format("%s keys=%d selected=%d",
-                    super.toString(),
-                    selector != null && selector.isOpen() ? selector.keys().size() : -1,
-                    selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1);
-        }
-
-        private class DumpKeys implements Runnable
-        {
-            private final CountDownLatch latch = new CountDownLatch(1);
-            private final List<Object> _dumps;
-
-            private DumpKeys(List<Object> dumps)
-            {
-                this._dumps = dumps;
-            }
-
-            @Override
-            public void run()
-            {
-                dumpKeysState(_dumps);
-                latch.countDown();
-            }
-
-            public boolean await(long timeout, TimeUnit unit)
-            {
-                try
-                {
-                    return latch.await(timeout, unit);
-                }
-                catch (InterruptedException x)
-                {
-                    return false;
-                }
-            }
-        }
-
-        private class Acceptor implements Runnable
-        {
-            private final ServerSocketChannel _channel;
-
-            public Acceptor(ServerSocketChannel channel)
-            {
-                this._channel = channel;
-            }
-
-            @Override
-            public void run()
-            {
-                try
-                {
-                    SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, null);
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("{} acceptor={}", this, key);
-                }
-                catch (Throwable x)
-                {
-                    closeNoExceptions(_channel);
-                    LOG.warn(x);
-                }
-            }
-        }
-
-        private class Accept implements Runnable
-        {
-            private final SocketChannel channel;
-            private final Object attachment;
-
-            private Accept(SocketChannel channel, Object attachment)
-            {
-                this.channel = channel;
-                this.attachment = attachment;
-            }
-
-            @Override
-            public void run()
-            {
-                try
-                {
-                    SelectionKey key = channel.register(_selector, 0, attachment);
-                    EndPoint endpoint = createEndPoint(channel, key);
-                    key.attach(endpoint);
-                }
-                catch (Throwable x)
-                {
-                    closeNoExceptions(channel);
-                    LOG.debug(x);
-                }
-            }
-        }
-
-        private class Connect implements Runnable
-        {
-            private final AtomicBoolean failed = new AtomicBoolean();
-            private final SocketChannel channel;
-            private final Object attachment;
-            private final Scheduler.Task timeout;
-
-            private Connect(SocketChannel channel, Object attachment)
-            {
-                this.channel = channel;
-                this.attachment = attachment;
-                this.timeout = scheduler.schedule(new ConnectTimeout(this), getConnectTimeout(), TimeUnit.MILLISECONDS);
-            }
-
-            @Override
-            public void run()
-            {
-                try
-                {
-                    channel.register(_selector, SelectionKey.OP_CONNECT, this);
-                }
-                catch (Throwable x)
-                {
-                    failed(x);
-                }
-            }
-
-            private void failed(Throwable failure)
-            {
-                if (failed.compareAndSet(false, true))
-                {
-                    timeout.cancel();
-                    closeNoExceptions(channel);
-                    connectionFailed(channel, failure, attachment);
-                }
-            }
-        }
-
-        private class ConnectTimeout implements Runnable
-        {
-            private final Connect connect;
-
-            private ConnectTimeout(Connect connect)
-            {
-                this.connect = connect;
-            }
-
-            @Override
-            public void run()
-            {
-                SocketChannel channel = connect.channel;
-                if (channel.isConnectionPending())
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Channel {} timed out while connecting, closing it", channel);
-                    connect.failed(new SocketTimeoutException("Connect Timeout"));
-                }
-            }
-        }
-
-        private class Stop implements Runnable
-        {
-            private final CountDownLatch latch = new CountDownLatch(1);
-
-            @Override
-            public void run()
-            {
-                try
-                {
-                    for (SelectionKey key : _selector.keys())
-                    {
-                        Object attachment = key.attachment();
-                        if (attachment instanceof EndPoint)
-                        {
-                            EndPointCloser closer = new EndPointCloser((EndPoint)attachment);
-                            execute(closer);
-                            // We are closing the SelectorManager, so we want to block the
-                            // selector thread here until we have closed all EndPoints.
-                            // This is different than calling close() directly, because close()
-                            // can wait forever, while here we are limited by the stop timeout.
-                            closer.await(getStopTimeout());
-                        }
-                    }
-
-                    closeNoExceptions(_selector);
-                }
-                finally
-                {
-                    latch.countDown();
-                }
-            }
-
-            public boolean await(long timeout)
-            {
-                try
-                {
-                    return latch.await(timeout, TimeUnit.MILLISECONDS);
-                }
-                catch (InterruptedException x)
-                {
-                    return false;
-                }
-            }
-        }
-
-        private class EndPointCloser implements Runnable
-        {
-            private final CountDownLatch latch = new CountDownLatch(1);
-            private final EndPoint endPoint;
-
-            private EndPointCloser(EndPoint endPoint)
-            {
-                this.endPoint = endPoint;
-            }
-
-            @Override
-            public void run()
-            {
-                try
-                {
-                    closeNoExceptions(endPoint.getConnection());
-                }
-                finally
-                {
-                    latch.countDown();
-                }
-            }
-
-            private boolean await(long timeout)
-            {
-                try
-                {
-                    return latch.await(timeout, TimeUnit.MILLISECONDS);
-                }
-                catch (InterruptedException x)
-                {
-                    return false;
-                }
-            }
-        }
-    }
-
-    /**
-     * A {@link SelectableEndPoint} is an {@link EndPoint} that wish to be notified of
-     * non-blocking events by the {@link ManagedSelector}.
-     */
-    public interface SelectableEndPoint extends EndPoint
-    {
-        /**
-         * <p>Callback method invoked when a read or write events has been detected by the {@link ManagedSelector}
-         * for this endpoint.</p>
-         */
-        void onSelected();
-    }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java
deleted file mode 100644
index 928605e..0000000
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedPrintWriter.java
+++ /dev/null
@@ -1,683 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.io;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Writer;
-
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/* ------------------------------------------------------------ */
-/**
- * A wrapper for the {@link java.io.PrintWriter} that re-throws the instances of
- * {@link java.io.IOException} thrown by the underlying implementation of
- * {@link java.io.Writer} as {@link RuntimeIOException} instances.
- */
-public class UncheckedPrintWriter extends PrintWriter
-{
-    private static final Logger LOG = Log.getLogger(UncheckedPrintWriter.class);
-
-    private boolean _autoFlush = false;
-    private IOException _ioException;
-    private boolean _isClosed = false;
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Line separator string. This is the value of the line.separator property
-     * at the moment that the stream was created.
-     */
-    private String _lineSeparator;
-
-    public UncheckedPrintWriter(Writer out)
-    {
-        this(out,false);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Create a new PrintWriter.
-     * 
-     * @param out
-     *            A character-output stream
-     * @param autoFlush
-     *            A boolean; if true, the println() methods will flush the
-     *            output buffer
-     */
-    public UncheckedPrintWriter(Writer out, boolean autoFlush)
-    {
-        super(out,autoFlush);
-        this._autoFlush = autoFlush;
-        this._lineSeparator = System.getProperty("line.separator");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Create a new PrintWriter, without automatic line flushing, from an
-     * existing OutputStream. This convenience constructor creates the necessary
-     * intermediate OutputStreamWriter, which will convert characters into bytes
-     * using the default character encoding.
-     * 
-     * @param out
-     *            An output stream
-     * 
-     * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
-     */
-    public UncheckedPrintWriter(OutputStream out)
-    {
-        this(out,false);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Create a new PrintWriter from an existing OutputStream. This convenience
-     * constructor creates the necessary intermediate OutputStreamWriter, which
-     * will convert characters into bytes using the default character encoding.
-     * 
-     * @param out
-     *            An output stream
-     * @param autoFlush
-     *            A boolean; if true, the println() methods will flush the
-     *            output buffer
-     * 
-     * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
-     */
-    public UncheckedPrintWriter(OutputStream out, boolean autoFlush)
-    {
-        this(new BufferedWriter(new OutputStreamWriter(out)),autoFlush);
-    }
-    
-    
-    /* ------------------------------------------------------------ */
-    public boolean checkError()
-    {
-        return _ioException!=null || super.checkError();
-    }
-    
-    /* ------------------------------------------------------------ */
-    private void setError(Throwable th)
-    {
-      
-        super.setError();
-
-        if (th instanceof IOException)
-            _ioException=(IOException)th;
-        else
-        {
-            _ioException=new IOException(String.valueOf(th));
-            _ioException.initCause(th);
-        }
-
-        if (LOG.isDebugEnabled())
-            LOG.debug(th);
-    }
-
-
-    @Override
-    protected void setError()
-    {
-        setError(new IOException());
-    }
-
-    /* ------------------------------------------------------------ */
-    /** Check to make sure that the stream has not been closed */
-    private void isOpen() throws IOException
-    {       
-        if (_ioException!=null)
-            throw new RuntimeIOException(_ioException); 
-        
-        if (_isClosed)
-            throw new IOException("Stream closed");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Flush the stream.
-     */
-    @Override
-    public void flush()
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                isOpen();
-                out.flush();
-            }
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Close the stream.
-     */
-    @Override
-    public void close()
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                out.close();
-                _isClosed = true;
-            }
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Write a single character.
-     * 
-     * @param c
-     *            int specifying a character to be written.
-     */
-    @Override
-    public void write(int c)
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                isOpen();
-                out.write(c);
-            }
-        }
-        catch (InterruptedIOException x)
-        {
-            Thread.currentThread().interrupt();
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Write a portion of an array of characters.
-     * 
-     * @param buf
-     *            Array of characters
-     * @param off
-     *            Offset from which to start writing characters
-     * @param len
-     *            Number of characters to write
-     */
-    @Override
-    public void write(char buf[], int off, int len)
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                isOpen();
-                out.write(buf,off,len);
-            }
-        }
-        catch (InterruptedIOException x)
-        {
-            Thread.currentThread().interrupt();
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Write an array of characters. This method cannot be inherited from the
-     * Writer class because it must suppress I/O exceptions.
-     * 
-     * @param buf
-     *            Array of characters to be written
-     */
-    @Override
-    public void write(char buf[])
-    { 
-        this.write(buf,0,buf.length);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Write a portion of a string.
-     * 
-     * @param s
-     *            A String
-     * @param off
-     *            Offset from which to start writing characters
-     * @param len
-     *            Number of characters to write
-     */
-    @Override
-    public void write(String s, int off, int len)
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                isOpen();
-                out.write(s,off,len);
-            }
-        }
-        catch (InterruptedIOException x)
-        {
-            Thread.currentThread().interrupt();
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Write a string. This method cannot be inherited from the Writer class
-     * because it must suppress I/O exceptions.
-     * 
-     * @param s
-     *            String to be written
-     */
-    @Override
-    public void write(String s)
-    {
-        this.write(s,0,s.length());
-    }
-
-    private void newLine()
-    {
-        try
-        {
-            synchronized (lock)
-            {
-                isOpen();
-                out.write(_lineSeparator);
-                if (_autoFlush)
-                    out.flush();
-            }
-        }
-        catch (InterruptedIOException x)
-        {
-            Thread.currentThread().interrupt();
-        }
-        catch (IOException ex)
-        {
-            setError(ex);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a boolean value. The string produced by <code>{@link
-     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
-     * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
-     * 
-     * @param b
-     *            The <code>boolean</code> to be printed
-     */
-    @Override
-    public void print(boolean b)
-    {
-        this.write(b?"true":"false");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a character. The character is translated into one or more bytes
-     * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
-     * 
-     * @param c
-     *            The <code>char</code> to be printed
-     */
-    @Override
-    public void print(char c)
-    {
-        this.write(c);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an integer. The string produced by <code>{@link
-     * java.lang.String#valueOf(int)}</code> is translated into bytes according
-     * to the platform's default character encoding, and these bytes are written
-     * in exactly the manner of the <code>{@link #write(int)}</code> method.
-     * 
-     * @param i
-     *            The <code>int</code> to be printed
-     * @see java.lang.Integer#toString(int)
-     */
-    @Override
-    public void print(int i)
-    {
-        this.write(String.valueOf(i));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a long integer. The string produced by <code>{@link
-     * java.lang.String#valueOf(long)}</code> is translated into bytes according
-     * to the platform's default character encoding, and these bytes are written
-     * in exactly the manner of the <code>{@link #write(int)}</code> method.
-     * 
-     * @param l
-     *            The <code>long</code> to be printed
-     * @see java.lang.Long#toString(long)
-     */
-    @Override
-    public void print(long l)
-    {
-        this.write(String.valueOf(l));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a floating-point number. The string produced by <code>{@link
-     * java.lang.String#valueOf(float)}</code> is translated into bytes
-     * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
-     * method.
-     * 
-     * @param f
-     *            The <code>float</code> to be printed
-     * @see java.lang.Float#toString(float)
-     */
-    @Override
-    public void print(float f)
-    {
-        this.write(String.valueOf(f));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a double-precision floating-point number. The string produced by
-     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
-     * bytes according to the platform's default character encoding, and these
-     * bytes are written in exactly the manner of the <code>{@link
-     * #write(int)}</code> method.
-     * 
-     * @param d
-     *            The <code>double</code> to be printed
-     * @see java.lang.Double#toString(double)
-     */
-    @Override
-    public void print(double d)
-    {
-        this.write(String.valueOf(d));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an array of characters. The characters are converted into bytes
-     * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
-     * method.
-     * 
-     * @param s
-     *            The array of chars to be printed
-     * 
-     * @throws NullPointerException
-     *             If <code>s</code> is <code>null</code>
-     */
-    @Override
-    public void print(char s[])
-    {
-        this.write(s);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a string. If the argument is <code>null</code> then the string
-     * <code>"null"</code> is printed. Otherwise, the string's characters are
-     * converted into bytes according to the platform's default character
-     * encoding, and these bytes are written in exactly the manner of the
-     * <code>{@link #write(int)}</code> method.
-     * 
-     * @param s
-     *            The <code>String</code> to be printed
-     */
-    @Override
-    public void print(String s)
-    {
-        if (s == null)
-        {
-            s = "null";
-        }
-        this.write(s);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an object. The string produced by the <code>{@link
-     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
-     * according to the platform's default character encoding, and these bytes
-     * are written in exactly the manner of the <code>{@link #write(int)}</code>
-     * method.
-     * 
-     * @param obj
-     *            The <code>Object</code> to be printed
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public void print(Object obj)
-    {
-        this.write(String.valueOf(obj));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Terminate the current line by writing the line separator string. The line
-     * separator string is defined by the system property
-     * <code>line.separator</code>, and is not necessarily a single newline
-     * character (<code>'\n'</code>).
-     */
-    @Override
-    public void println()
-    {
-        this.newLine();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a boolean value and then terminate the line. This method behaves as
-     * though it invokes <code>{@link #print(boolean)}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>boolean</code> value to be printed
-     */
-    @Override
-    public void println(boolean x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a character and then terminate the line. This method behaves as
-     * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
-     * #println()}</code>.
-     * 
-     * @param x
-     *            the <code>char</code> value to be printed
-     */
-    @Override
-    public void println(char x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an integer and then terminate the line. This method behaves as
-     * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
-     * #println()}</code>.
-     * 
-     * @param x
-     *            the <code>int</code> value to be printed
-     */
-    @Override
-    public void println(int x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a long integer and then terminate the line. This method behaves as
-     * though it invokes <code>{@link #print(long)}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>long</code> value to be printed
-     */
-    @Override
-    public void println(long x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a floating-point number and then terminate the line. This method
-     * behaves as though it invokes <code>{@link #print(float)}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>float</code> value to be printed
-     */
-    @Override
-    public void println(float x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a double-precision floating-point number and then terminate the
-     * line. This method behaves as though it invokes <code>{@link
-     * #print(double)}</code> and then <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>double</code> value to be printed
-     */
-    /* ------------------------------------------------------------ */
-    @Override
-    public void println(double x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an array of characters and then terminate the line. This method
-     * behaves as though it invokes <code>{@link #print(char[])}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the array of <code>char</code> values to be printed
-     */
-    @Override
-    public void println(char x[])
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print a String and then terminate the line. This method behaves as though
-     * it invokes <code>{@link #print(String)}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>String</code> value to be printed
-     */
-    @Override
-    public void println(String x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Print an Object and then terminate the line. This method behaves as
-     * though it invokes <code>{@link #print(Object)}</code> and then
-     * <code>{@link #println()}</code>.
-     * 
-     * @param x
-     *            the <code>Object</code> value to be printed
-     */
-    @Override
-    public void println(Object x)
-    {
-        synchronized (lock)
-        {
-            this.print(x);
-            this.println();
-        }
-    }
-}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
index ed594c1..f6adcfb 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
@@ -37,10 +37,9 @@
 /**
  * A Utility class to help implement {@link EndPoint#write(Callback, ByteBuffer...)} by calling
  * {@link EndPoint#flush(ByteBuffer...)} until all content is written.
- * The abstract method {@link #onIncompleteFlushed()} is called when not all content has been written after a call to
- * flush and should organise for the {@link #completeWrite()} method to be called when a subsequent call to flush
+ * The abstract method {@link #onIncompleteFlush()} is called when not all content has been written after a call to
+ * flush and should organize for the {@link #completeWrite()} method to be called when a subsequent call to flush
  * should  be able to make more progress.
- * <p>
  */
 abstract public class WriteFlusher
 {
@@ -269,25 +268,37 @@
             if (_callback!=null)
                 _callback.succeeded();
         }
+        
+        boolean isCallbackNonBlocking()
+        {
+            return _callback!=null && _callback.isNonBlocking();
+        }
     }
 
+    public boolean isCallbackNonBlocking()
+    {
+        State s = _state.get();
+        return (s instanceof PendingState) && ((PendingState)s).isCallbackNonBlocking();
+    }
+    
     /**
      * Abstract call to be implemented by specific WriteFlushers. It should schedule a call to {@link #completeWrite()}
      * or {@link #onFail(Throwable)} when appropriate.
      */
-    abstract protected void onIncompleteFlushed();
+    abstract protected void onIncompleteFlush();
 
     /**
      * Tries to switch state to WRITING. If successful it writes the given buffers to the EndPoint. If state transition
      * fails it'll fail the callback.
      *
      * If not all buffers can be written in one go it creates a new <code>PendingState</code> object to preserve the state
-     * and then calls {@link #onIncompleteFlushed()}. The remaining buffers will be written in {@link #completeWrite()}.
+     * and then calls {@link #onIncompleteFlush()}. The remaining buffers will be written in {@link #completeWrite()}.
      *
      * If all buffers have been written it calls callback.complete().
      *
      * @param callback the callback to call on either failed or complete
      * @param buffers the buffers to flush to the endpoint
+     * @throws WritePendingException if unable to write due to prior pending write
      */
     public void write(Callback callback, ByteBuffer... buffers) throws WritePendingException
     {
@@ -308,7 +319,7 @@
                     LOG.debug("flushed incomplete");
                 PendingState pending=new PendingState(buffers, callback);
                 if (updateState(__WRITING,pending))
-                    onIncompleteFlushed();
+                    onIncompleteFlush();
                 else
                     fail(pending);
                 return;
@@ -336,7 +347,7 @@
 
 
     /**
-     * Complete a write that has not completed and that called {@link #onIncompleteFlushed()} to request a call to this
+     * Complete a write that has not completed and that called {@link #onIncompleteFlush()} to request a call to this
      * method when a call to {@link EndPoint#flush(ByteBuffer...)} is likely to be able to progress.
      *
      * It tries to switch from PENDING to COMPLETING. If state transition fails, then it does nothing as the callback
@@ -371,7 +382,7 @@
                 if (buffers!=pending.getBuffers())
                     pending=new PendingState(buffers, pending._callback);
                 if (updateState(__COMPLETING,pending))
-                    onIncompleteFlushed();
+                    onIncompleteFlush();
                 else
                     fail(pending);
                 return;
@@ -397,7 +408,7 @@
     /** Flush the buffers iteratively until no progress is made
      * @param buffers The buffers to flush
      * @return The unflushed buffers, or null if all flushed
-     * @throws IOException
+     * @throws IOException if unable to flush
      */
     protected ByteBuffer[] flush(ByteBuffer[] buffers) throws IOException
     {
@@ -408,6 +419,9 @@
             boolean flushed=_endPoint.flush(buffers);
             int r=buffers.length==0?0:buffers[0].remaining();
             
+            if (LOG.isDebugEnabled())
+                LOG.debug("Flushed={} {}/{}+{} {}",flushed,before-r,before,buffers.length-1,this);
+            
             if (flushed)
                 return null;
             
@@ -429,6 +443,9 @@
             if (not_empty>0)
                 buffers=Arrays.copyOfRange(buffers,not_empty,buffers.length);
         }        
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("!fully flushed {}",this);
         
         // If buffers is null, then flush has returned false but has consumed all the data!
         // This is probably SSL being unable to flush the encrypted buffer, so return EMPTY_BUFFERS
@@ -505,4 +522,23 @@
     {
         return String.format("WriteFlusher@%x{%s}", hashCode(), _state.get());
     }
+    
+    public String toStateString()
+    {
+        switch(_state.get().getType())
+        {
+            case WRITING:
+                return "W";
+            case PENDING:
+                return "P";
+            case COMPLETING:
+                return "C";
+            case IDLE:
+                return "-";
+            case FAILED:
+                return "F";
+            default:
+                return "?";
+        }
+    }
 }
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java
index c1ec55f..77e3409 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java
@@ -31,6 +31,7 @@
 
 public class SslClientConnectionFactory implements ClientConnectionFactory
 {
+    public static final String SSL_CONTEXT_FACTORY_CONTEXT_KEY = "ssl.context.factory";
     public static final String SSL_PEER_HOST_CONTEXT_KEY = "ssl.peer.host";
     public static final String SSL_PEER_PORT_CONTEXT_KEY = "ssl.peer.port";
     public static final String SSL_ENGINE_CONTEXT_KEY = "ssl.engine";
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
index dc20bf7..50cfa92 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
@@ -21,8 +21,8 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedChannelException;
-import java.util.Arrays;
 import java.util.concurrent.Executor;
+
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@@ -35,7 +35,6 @@
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.EofException;
-import org.eclipse.jetty.io.FillInterest;
 import org.eclipse.jetty.io.RuntimeIOException;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.WriteFlusher;
@@ -78,7 +77,6 @@
 public class SslConnection extends AbstractConnection
 {
     private static final Logger LOG = Log.getLogger(SslConnection.class);
-    private static final boolean DEBUG = LOG.isDebugEnabled(); // Easy for the compiler to remove the code if DEBUG==false
     private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0);
     private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0);
     private final ByteBufferPool _bufferPool;
@@ -87,8 +85,9 @@
     private ByteBuffer _decryptedInput;
     private ByteBuffer _encryptedInput;
     private ByteBuffer _encryptedOutput;
-    private final boolean _encryptedDirectBuffers = false;
+    private final boolean _encryptedDirectBuffers = true;
     private final boolean _decryptedDirectBuffers = false;
+    private boolean _renegotiationAllowed;
     private final Runnable _runCompletWrite = new Runnable()
     {
         @Override
@@ -97,13 +96,20 @@
             _decryptedEndPoint.getWriteFlusher().completeWrite();
         }
     };
-    private boolean _renegotiationAllowed;
+    private final Runnable _runFillable = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+            _decryptedEndPoint.getFillInterest().fillable();
+        }
+    };
 
     public SslConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, SSLEngine sslEngine)
     {
-        // This connection does not execute calls to onfillable, so they will be called by the selector thread.
-        // onfillable does not block and will only wakeup another thread to do the actual reading and handling.
-        super(endPoint, executor, !EXECUTE_ONFILLABLE);
+        // This connection does not execute calls to onFillable(), so they will be called by the selector thread.
+        // onFillable() does not block and will only wakeup another thread to do the actual reading and handling.
+        super(endPoint, executor);
         this._bufferPool = byteBufferPool;
         this._sslEngine = sslEngine;
         this._decryptedEndPoint = newDecryptedEndPoint();
@@ -165,6 +171,12 @@
     }
 
     @Override
+    public boolean onIdleExpired()
+    {
+        return getDecryptedEndPoint().getConnection().onIdleExpired();
+    }
+
+    @Override
     public void onFillable()
     {
         // onFillable means that there are encrypted bytes ready to be filled.
@@ -173,7 +185,7 @@
         // to do the fill and/or flush again and these calls will do the actually
         // filling.
 
-        if (DEBUG)
+        if (LOG.isDebugEnabled())
             LOG.debug("onFillable enter {}", _decryptedEndPoint);
 
         // We have received a close handshake, close the end point to send FIN.
@@ -190,11 +202,11 @@
             if (_decryptedEndPoint._flushRequiresFillToProgress)
             {
                 _decryptedEndPoint._flushRequiresFillToProgress = false;
-                getExecutor().execute(_runCompletWrite);
+                _runCompletWrite.run();
             }
         }
 
-        if (DEBUG)
+        if (LOG.isDebugEnabled())
             LOG.debug("onFillable exit {}", _decryptedEndPoint);
     }
 
@@ -257,7 +269,7 @@
                 boolean fillable = false;
                 synchronized (DecryptedEndPoint.this)
                 {
-                    if (DEBUG)
+                    if (LOG.isDebugEnabled())
                         LOG.debug("write.complete {}", SslConnection.this.getEndPoint());
 
                     releaseEncryptedOutputBuffer();
@@ -272,7 +284,7 @@
                 }
                 if (fillable)
                     getFillInterest().fillable();
-                getExecutor().execute(_runCompletWrite);
+                _runCompletWrite.run();
             }
 
             @Override
@@ -284,7 +296,7 @@
                 boolean fail_filler = false;
                 synchronized (DecryptedEndPoint.this)
                 {
-                    if (DEBUG)
+                    if (LOG.isDebugEnabled())
                         LOG.debug("{} write.failed", SslConnection.this, x);
                     BufferUtil.clear(_encryptedOutput);
                     releaseEncryptedOutputBuffer();
@@ -321,24 +333,30 @@
 
         public DecryptedEndPoint()
         {
-            super(null,getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
-            setIdleTimeout(getEndPoint().getIdleTimeout());
+            // Disable idle timeout checking: no scheduler and -1 timeout for this instance.
+            super(null, getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
+            super.setIdleTimeout(-1);
         }
 
         @Override
-        protected FillInterest getFillInterest()
+        public long getIdleTimeout()
         {
-            return super.getFillInterest();
+            return getEndPoint().getIdleTimeout();
         }
 
         @Override
         public void setIdleTimeout(long idleTimeout)
         {
-            super.setIdleTimeout(idleTimeout);
             getEndPoint().setIdleTimeout(idleTimeout);
         }
 
         @Override
+        public boolean isOpen()
+        {
+            return getEndPoint().isOpen();
+        }
+
+        @Override
         protected WriteFlusher getWriteFlusher()
         {
             return super.getWriteFlusher();
@@ -354,8 +372,8 @@
             boolean try_again = false;
             synchronized (DecryptedEndPoint.this)
             {
-                if (DEBUG)
-                    LOG.debug("onIncompleteFlush {}", getEndPoint());
+                if (LOG.isDebugEnabled())
+                    LOG.debug("onIncompleteFlush {}", SslConnection.this);
                 // If we have pending output data,
                 if (BufferUtil.hasContent(_encryptedOutput))
                 {
@@ -368,7 +386,8 @@
                 {
                     // check if we are actually read blocked in order to write
                     _flushRequiresFillToProgress = true;
-                    SslConnection.this.fillInterested();
+
+                    ensureFillInterested();
                 }
                 else
                 {
@@ -394,15 +413,14 @@
                 else
                 {
                     // try to flush what is pending
-                    // because this is a special case (see above) we could probably
-                    // avoid the dispatch, but best to be sure
+                    // execute to avoid recursion
                     getExecutor().execute(_runCompletWrite);
                 }
             }
         }
 
         @Override
-        protected boolean needsFill() throws IOException
+        protected void needsFillInterest() throws IOException
         {
             // This means that the decrypted data consumer has called the fillInterested
             // method on the DecryptedEndPoint, so we have to work out if there is
@@ -412,11 +430,12 @@
             synchronized (DecryptedEndPoint.this)
             {
                 // Do we already have some app data, then app can fill now so return true
-                if (BufferUtil.hasContent(_decryptedInput))
-                    return true;
+                boolean fillable = (BufferUtil.hasContent(_decryptedInput))
+                        // or if we have encryptedInput and have not underflowed yet, the it is worth trying a fill
+                        || BufferUtil.hasContent(_encryptedInput) && !_underFlown;
 
                 // If we have no encrypted data to decrypt OR we have some, but it is not enough
-                if (BufferUtil.isEmpty(_encryptedInput) || _underFlown)
+                if (!fillable)
                 {
                     // We are not ready to read data
 
@@ -437,23 +456,15 @@
                             // we have already written the net data
                             // pretend we are readable so the wrap is done by next readable callback
                             _fillRequiresFlushToProgress = false;
-                            return true;
+                            fillable=true;
                         }
                     }
-                    else
-                    {
-                        // Normal readable callback
-                        // Get called back on onfillable when then is more data to fill
-                        SslConnection.this.fillInterested();
-                    }
+                }
 
-                    return false;
-                }
+                if (fillable)
+                    getExecutor().execute(_runFillable);
                 else
-                {
-                    // We are ready to read data
-                    return true;
-                }
+                    ensureFillInterested();
             }
         }
 
@@ -477,8 +488,6 @@
         @Override
         public synchronized int fill(ByteBuffer buffer) throws IOException
         {
-            if (DEBUG)
-                LOG.debug("{} fill enter", SslConnection.this);
             try
             {
                 // Do we already have some decrypted data?
@@ -505,8 +514,6 @@
                 {
                     // Let's try reading some encrypted data... even if we have some already.
                     int net_filled = getEndPoint().fill(_encryptedInput);
-                    if (DEBUG)
-                        LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled);
 
                     decryption: while (true)
                     {
@@ -522,8 +529,11 @@
                         {
                             BufferUtil.flipToFlush(app_in, pos);
                         }
-                        if (DEBUG)
-                            LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
+                        if (LOG.isDebugEnabled())
+                        {
+                            LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' '));
+                            LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer));
+                        }
 
                         HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
                         HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
@@ -582,15 +592,16 @@
                                 if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
                                 {
                                     _handshaken = true;
-                                    if (DEBUG)
-                                        LOG.debug("{} {} handshake completed", SslConnection.this,
-                                                _sslEngine.getUseClientMode() ? "client-side" : "resumed session server-side");
+                                    if (LOG.isDebugEnabled())
+                                        LOG.debug("{} {} handshook {}/{}", SslConnection.this,
+                                                _sslEngine.getUseClientMode() ? "client" : "resumed server",
+                                                _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
                                 }
 
                                 // Check whether renegotiation is allowed
                                 if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
                                 {
-                                    if (DEBUG)
+                                    if (LOG.isDebugEnabled())
                                         LOG.debug("{} renegotiation denied", SslConnection.this);
                                     closeInbound();
                                     return -1;
@@ -661,6 +672,13 @@
                     }
                 }
             }
+            catch (IllegalStateException e)
+            {
+                // Some internal error in SSLEngine
+                LOG.debug(e);
+                getEndPoint().close();
+                throw new EofException(e);
+            }
             catch (Exception e)
             {
                 getEndPoint().close();
@@ -685,8 +703,6 @@
                     _bufferPool.release(_decryptedInput);
                     _decryptedInput = null;
                 }
-                if (DEBUG)
-                    LOG.debug("{} fill exit", SslConnection.this);
             }
         }
 
@@ -712,9 +728,12 @@
             // it is the applications responsibility to call flush again - either in a busy loop
             // or better yet by using EndPoint#write to do the flushing.
 
-            if (DEBUG)
-                LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts));
-            int consumed=0;
+            if (LOG.isDebugEnabled())
+            {
+                for (ByteBuffer b : appOuts)
+                    LOG.debug("{} flush {}", SslConnection.this, BufferUtil.toHexSummary(b));
+            }
+
             try
             {
                 if (_cannotAcceptMoreAppDataToFlush)
@@ -736,17 +755,15 @@
                     SSLEngineResult wrapResult;
                     try
                     {
-                        wrapResult=_sslEngine.wrap(appOuts, _encryptedOutput);
+                        wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
                     }
                     finally
                     {
                         BufferUtil.flipToFlush(_encryptedOutput, pos);
                     }
-                    
-                    if (DEBUG)
-                        LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
-                    if (wrapResult.bytesConsumed()>0)
-                        consumed+=wrapResult.bytesConsumed();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' '));
+
                     Status wrapResultStatus = wrapResult.getStatus();
 
                     boolean allConsumed=true;
@@ -782,14 +799,14 @@
                             throw new IllegalStateException();
 
                         default:
-                            if (DEBUG)
-                                LOG.debug("{} {} {}", this, wrapResultStatus, BufferUtil.toDetailString(_encryptedOutput));
+                            if (LOG.isDebugEnabled())
+                                LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
 
                             if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
                             {
                                 _handshaken = true;
-                                if (DEBUG)
-                                    LOG.debug("{} {} handshake completed", SslConnection.this, "server-side");
+                                if (LOG.isDebugEnabled())
+                                    LOG.debug("{} server handshook complete {}/{}", SslConnection.this, _sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
                             }
 
                             HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
@@ -797,7 +814,7 @@
                             // Check whether renegotiation is allowed
                             if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
                             {
-                                if (DEBUG)
+                                if (LOG.isDebugEnabled())
                                     LOG.debug("{} renegotiation denied", SslConnection.this);
                                 getEndPoint().shutdownOutput();
                                 return allConsumed;
@@ -852,8 +869,6 @@
             }
             finally
             {
-                if (DEBUG)
-                    LOG.debug("{} flush exit, consumed {}", SslConnection.this, consumed);
                 releaseEncryptedOutputBuffer();
             }
         }
@@ -874,7 +889,7 @@
         {
             boolean ishut = isInputShutdown();
             boolean oshut = isOutputShutdown();
-            if (DEBUG)
+            if (LOG.isDebugEnabled())
                 LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, oshut, ishut);
             if (ishut)
             {
@@ -888,9 +903,12 @@
             {
                 try
                 {
-                    _sslEngine.closeOutbound();
-                    flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
-                    SslConnection.this.fillInterested(); // seek reply FIN or RST or close handshake
+                    synchronized (this) // TODO review synchronized boundary
+                    {
+                        _sslEngine.closeOutbound();
+                        flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
+                        ensureFillInterested();
+                    }
                 }
                 catch (Exception e)
                 {
@@ -900,6 +918,12 @@
             }
         }
 
+        private void ensureFillInterested()
+        {
+            if (!SslConnection.this.isFillInterested())
+                SslConnection.this.fillInterested();
+        }
+
         @Override
         public boolean isOutputShutdown()
         {
@@ -909,16 +933,10 @@
         @Override
         public void close()
         {
-            super.close();
             // First send the TLS Close Alert, then the FIN
             shutdownOutput();
             getEndPoint().close();
-        }
-
-        @Override
-        public boolean isOpen()
-        {
-            return getEndPoint().isOpen();
+            super.close();
         }
 
         @Override
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java
index 0f702bf..2a49e8b 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java
@@ -18,8 +18,10 @@
 
 package org.eclipse.jetty.io;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -29,6 +31,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import org.eclipse.jetty.toolchain.test.AdvancedRunner;
@@ -64,7 +67,7 @@
     public void testFill() throws Exception
     {
         ByteArrayEndPoint endp = new ByteArrayEndPoint();
-        endp.setInput("test input");
+        endp.addInput("test input");
 
         ByteBuffer buffer = BufferUtil.allocate(1024);
 
@@ -73,13 +76,13 @@
 
         assertEquals(0,endp.fill(buffer));
 
-        endp.setInput(" more");
+        endp.addInput(" more");
         assertEquals(5,endp.fill(buffer));
         assertEquals("test input more",BufferUtil.toString(buffer));
 
         assertEquals(0,endp.fill(buffer));
 
-        endp.setInput((ByteBuffer)null);
+        endp.addInput((ByteBuffer)null);
 
         assertEquals(-1,endp.fill(buffer));
 
@@ -96,7 +99,7 @@
         }
 
         endp.reset();
-        endp.setInput("and more");
+        endp.addInput("and more");
         buffer = BufferUtil.allocate(4);
 
         assertEquals(4,endp.fill(buffer));
@@ -105,7 +108,6 @@
         BufferUtil.clear(buffer);
         assertEquals(4,endp.fill(buffer));
         assertEquals("more",BufferUtil.toString(buffer));
-
     }
 
     @Test
@@ -155,12 +157,13 @@
     public void testReadable() throws Exception
     {
         ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000);
-        endp.setInput("test input");
+        endp.addInput("test input");
 
         ByteBuffer buffer = BufferUtil.allocate(1024);
         FutureCallback fcb = new FutureCallback();
 
         endp.fillInterested(fcb);
+        fcb.get(100,TimeUnit.MILLISECONDS);
         assertTrue(fcb.isDone());
         assertEquals(null, fcb.get());
         assertEquals(10, endp.fill(buffer));
@@ -168,10 +171,12 @@
 
         fcb = new FutureCallback();
         endp.fillInterested(fcb);
+        Thread.sleep(100);
         assertFalse(fcb.isDone());
         assertEquals(0, endp.fill(buffer));
 
-        endp.setInput(" more");
+        endp.addInput(" more");
+        fcb.get(1000,TimeUnit.MILLISECONDS);
         assertTrue(fcb.isDone());
         assertEquals(null, fcb.get());
         assertEquals(5, endp.fill(buffer));
@@ -179,16 +184,18 @@
 
         fcb = new FutureCallback();
         endp.fillInterested(fcb);
+        Thread.sleep(100);
         assertFalse(fcb.isDone());
         assertEquals(0, endp.fill(buffer));
 
-        endp.setInput((ByteBuffer)null);
+        endp.addInput((ByteBuffer)null);
         assertTrue(fcb.isDone());
         assertEquals(null, fcb.get());
         assertEquals(-1, endp.fill(buffer));
 
         fcb = new FutureCallback();
         endp.fillInterested(fcb);
+        fcb.get(1000,TimeUnit.MILLISECONDS);
         assertTrue(fcb.isDone());
         assertEquals(null, fcb.get());
         assertEquals(-1, endp.fill(buffer));
@@ -197,10 +204,9 @@
 
         fcb = new FutureCallback();
         endp.fillInterested(fcb);
-        assertTrue(fcb.isDone());
         try
         {
-            fcb.get();
+            fcb.get(1000,TimeUnit.MILLISECONDS);
             fail();
         }
         catch (ExecutionException e)
@@ -264,7 +270,7 @@
     {
         long idleTimeout = 500;
         ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, idleTimeout);
-        endp.setInput("test");
+        endp.addInput("test");
         endp.setGrowOutput(false);
         endp.setOutput(BufferUtil.allocate(5));
 
@@ -278,6 +284,7 @@
         FutureCallback fcb = new FutureCallback();
 
         endp.fillInterested(fcb);
+        fcb.get(100,TimeUnit.MILLISECONDS);
         assertTrue(fcb.isDone());
         assertEquals(null, fcb.get());
         assertEquals(4, endp.fill(buffer));
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java
index 553a14f..7aec534 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java
@@ -18,11 +18,6 @@
 
 package org.eclipse.jetty.io;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -43,7 +38,6 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-import org.eclipse.jetty.io.ClientConnectionFactory.Helper;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.toolchain.test.OS;
 import org.eclipse.jetty.util.BufferUtil;
@@ -51,6 +45,11 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 public class IOTest
 {
     @Test
@@ -437,9 +436,9 @@
         connector.bind(null);
         InetSocketAddress addr=(InetSocketAddress)connector.getLocalAddress();
         Future<AsynchronousSocketChannel> acceptor = connector.accept();
-        
+
         AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
-        
+
         client.connect(new InetSocketAddress("127.0.0.1",addr.getPort())).get(5, TimeUnit.SECONDS);
 
         AsynchronousSocketChannel server = acceptor.get(5, TimeUnit.SECONDS);
@@ -457,14 +456,14 @@
 
         Assert.assertEquals(ByteBuffer.wrap(data), read);
     }
-    
+
     @Test
     public void testGatherWrite() throws Exception
     {
         File dir = MavenTestingUtils.getTargetTestingDir();
         if (!dir.exists())
             dir.mkdir();
-        
+
         File file = File.createTempFile("test",".txt",dir);
         file.deleteOnExit();
         FileChannel out = FileChannel.open(file.toPath(),
@@ -472,7 +471,7 @@
                 StandardOpenOption.READ,
                 StandardOpenOption.WRITE,
                 StandardOpenOption.DELETE_ON_CLOSE);
-        
+
         ByteBuffer[] buffers = new ByteBuffer[4096];
         long expected=0;
         for (int i=0;i<buffers.length;i++)
@@ -480,9 +479,9 @@
             buffers[i]=BufferUtil.toBuffer(i);
             expected+=buffers[i].remaining();
         }
-        
+
         long wrote = IO.write(out,buffers,0,buffers.length);
-        
+
         assertEquals(expected,wrote);
 
         for (int i=0;i<buffers.length;i++)
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java
index e623317..a3815a8 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/MappedByteBufferPoolTest.java
@@ -32,7 +32,6 @@
 
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.StringUtil;
-import org.hamcrest.Matchers;
 import org.junit.Test;
 
 public class MappedByteBufferPoolTest
@@ -91,6 +90,7 @@
     /**
      * In a scenario where MappedByteBufferPool is being used improperly, such as releasing a buffer that wasn't created/acquired by the MappedByteBufferPool,
      * an assertion is tested for.
+     * @throws Exception test failure
      */
     @Test
     public void testReleaseAssertion() throws Exception
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
index c4d8986..08f1630 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointTest.java
@@ -41,6 +41,7 @@
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.FutureCallback;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -116,6 +117,7 @@
 
     public class TestConnection extends AbstractConnection
     {
+        volatile FutureCallback _blockingRead;
         ByteBuffer _in = BufferUtil.allocate(32 * 1024);
         ByteBuffer _out = BufferUtil.allocate(32 * 1024);
         long _last = -1;
@@ -133,8 +135,29 @@
         }
 
         @Override
-        public synchronized void onFillable()
+        public void onFillInterestedFailed(Throwable cause)
         {
+            Callback blocking = _blockingRead;
+            if (blocking!=null)
+            {
+                _blockingRead=null;
+                blocking.failed(cause);
+                return;
+            }
+            super.onFillInterestedFailed(cause);
+        }
+        
+        @Override
+        public void onFillable()
+        {
+            Callback blocking = _blockingRead;
+            if (blocking!=null)
+            {
+                _blockingRead=null;
+                blocking.succeeded();
+                return;
+            }
+            
             EndPoint _endp = getEndPoint();
             try
             {
@@ -145,6 +168,7 @@
                     progress = false;
 
                     // Fill the input buffer with everything available
+                    BufferUtil.compact(_in);
                     if (BufferUtil.isFull(_in))
                         throw new IllegalStateException("FULL " + BufferUtil.toDetailString(_in));
                     int filled = _endp.fill(_in);
@@ -154,9 +178,9 @@
                     // If the tests wants to block, then block
                     while (_blockAt > 0 && _endp.isOpen() && _in.remaining() < _blockAt)
                     {
-                        FutureCallback blockingRead = new FutureCallback();
-                        fillInterested(blockingRead);
-                        blockingRead.get();
+                        FutureCallback future = _blockingRead = new FutureCallback();
+                        fillInterested();
+                        future.get();
                         filled = _endp.fill(_in);
                         progress |= filled > 0;
                     }
@@ -183,6 +207,9 @@
                     if (_endp.isInputShutdown())
                         _endp.shutdownOutput();
                 }
+
+                if (_endp.isOpen())
+                    fillInterested();
             }
             catch (ExecutionException e)
             {
@@ -209,8 +236,6 @@
             }
             finally
             {
-                if (_endp.isOpen())
-                    fillInterested();
             }
         }
     }
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java
index ace72a8..f2c8d3c 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectorManagerTest.java
@@ -120,7 +120,7 @@
             long timeout = connectTimeout * 2;
             timeoutConnection.set(timeout);
             final CountDownLatch latch1 = new CountDownLatch(1);
-            selectorManager.connect(client1, new Callback.Adapter()
+            selectorManager.connect(client1, new Callback()
             {
                 @Override
                 public void failed(Throwable x)
@@ -141,7 +141,7 @@
                 client2.connect(address);
                 timeoutConnection.set(0);
                 final CountDownLatch latch2 = new CountDownLatch(1);
-                selectorManager.connect(client2, new Callback.Adapter()
+                selectorManager.connect(client2, new Callback()
                 {
                     @Override
                     public void succeeded()
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java
index a65526e..890bbe8 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java
@@ -35,7 +35,6 @@
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLSocket;
 
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
 import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.util.BufferUtil;
@@ -170,7 +169,7 @@
 
         public TestConnection(EndPoint endp)
         {
-            super(endp, _threadPool,true);
+            super(endp, _threadPool);
         }
 
         @Override
@@ -277,7 +276,6 @@
         len=5;
         while(len>0)
             len-=client.getInputStream().read(buffer);
-        Assert.assertEquals(1, _dispatches.get());
 
         client.close();
     }
@@ -309,7 +307,7 @@
     public void testBlockedWrite() throws Exception
     {
         Socket client = newClient();
-        client.setSoTimeout(60000);
+        client.setSoTimeout(5000);
 
         SocketChannel server = _connector.accept();
         server.configureBlocking(false);
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java
index 89cd958..342a49c 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/WriteFlusherTest.java
@@ -77,7 +77,7 @@
         _flusher = new WriteFlusher(_endp)
         {
             @Override
-            protected void onIncompleteFlushed()
+            protected void onIncompleteFlush()
             {
                 _flushIncomplete.set(true);
             }
@@ -275,7 +275,7 @@
         }
 
         @Override
-        protected void onIncompleteFlushed()
+        protected void onIncompleteFlush()
         {
             _scheduler.schedule(this, 1 + _random.nextInt(9), TimeUnit.MILLISECONDS);
         }
@@ -368,7 +368,7 @@
             }
 
             @Override
-            protected void onIncompleteFlushed()
+            protected void onIncompleteFlush()
             {
             }
         };
@@ -469,7 +469,7 @@
         final WriteFlusher writeFlusher = new WriteFlusher(_endPointMock)
         {
             @Override
-            protected void onIncompleteFlushed()
+            protected void onIncompleteFlush()
             {
             }
         };
@@ -529,7 +529,7 @@
         final WriteFlusher writeFlusher = new WriteFlusher(new EndPointConcurrentAccessToIncompleteWriteAndOnFailMock(writeCalledLatch, failedCalledLatch))
         {
             @Override
-            protected void onIncompleteFlushed()
+            protected void onIncompleteFlush()
             {
                 onIncompleteFlushedCalledLatch.countDown();
                 try
@@ -622,7 +622,7 @@
         final WriteFlusher writeFlusher = new WriteFlusher(endp)
         {
             @Override
-            protected void onIncompleteFlushed()
+            protected void onIncompleteFlush()
             {
                 executor.submit(new Runnable() 
                 { 
diff --git a/jetty-io/src/test/resources/jetty-logging.properties b/jetty-io/src/test/resources/jetty-logging.properties
index d4922ad..257743e 100644
--- a/jetty-io/src/test/resources/jetty-logging.properties
+++ b/jetty-io/src/test/resources/jetty-logging.properties
@@ -1,2 +1,5 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
 org.eclipse.jetty.LEVEL=INFO
+#org.eclipse.jetty.io.AbstractConnection.LEVEL=DEBUG
+#org.eclipse.jetty.io.ManagedSelector.LEVEL=DEBUG
+#org.eclipse.jetty.io.ssl.SslConnection.LEVEL=DEBUG
diff --git a/jetty-jaas/pom.xml b/jetty-jaas/pom.xml
index 60e9d78..6f42e0e 100644
--- a/jetty-jaas/pom.xml
+++ b/jetty-jaas/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jaas</artifactId>
@@ -13,52 +13,6 @@
   </properties>
   <build>
     <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-               <_versionpolicy> </_versionpolicy>
-               <Import-Package>javax.sql.*,javax.security.*,javax.naming.*,
-               javax.servlet.*;version="[2.6.0,3.2)",
-               *</Import-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
       <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
       with a snapshot. -->
       <plugin>
diff --git a/jetty-jaas/src/main/config/etc/jetty-jaas.xml b/jetty-jaas/src/main/config/etc/jetty-jaas.xml
index 9381d10..4e42594 100644
--- a/jetty-jaas/src/main/config/etc/jetty-jaas.xml
+++ b/jetty-jaas/src/main/config/etc/jetty-jaas.xml
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
-
     <!-- ======================================================== -->
     <!-- java.security.auth.login.config System property          -->
     <!-- This is usually a runtime parameter to the jvm, but      -->
@@ -11,7 +10,7 @@
     <!-- ======================================================== -->
     <Call class="java.lang.System" name="setProperty">
       <Arg>java.security.auth.login.config</Arg>
-      <Arg><Property name="jetty.base" default="." />/<Property name="jaas.login.conf" default="etc/login.conf"/></Arg>
+      <Arg><Property name="jetty.base" default="." />/<Property name="jetty.jaas.login.conf" deprecated="jaas.login.conf" default="etc/login.conf"/></Arg>
     </Call>
 
 </Configure>
diff --git a/jetty-jaas/src/main/config/modules/jaas.mod b/jetty-jaas/src/main/config/modules/jaas.mod
index 4932140..fee3f59 100644
--- a/jetty-jaas/src/main/config/modules/jaas.mod
+++ b/jetty-jaas/src/main/config/modules/jaas.mod
@@ -12,5 +12,6 @@
 etc/jetty-jaas.xml
 
 [ini-template]
-## JAAS Configuration
-jaas.login.conf=etc/login.conf
+## The file location (relative to $jetty.base) for the
+## JAAS "java.security.auth.login.config" system property
+# jetty.jaas.login.conf=etc/login.conf
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java
index bf509bf..5ad8b18 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASGroup.java
@@ -24,15 +24,12 @@
 import java.util.HashSet;
 import java.util.Iterator;
 
-
 public class JAASGroup implements Group 
 {
     public static final String ROLES = "__roles__";
     
     private String _name = null;
     private HashSet<Principal> _members = null;
-    
-    
    
     public JAASGroup(String n)
     {
@@ -41,42 +38,21 @@
     }
    
     /* ------------------------------------------------------------ */
-    /**
-     *
-     * @param principal <description>
-     * @return <description>
-     */
     public synchronized boolean addMember(Principal principal)
     {
         return _members.add(principal);
     }
 
-    /**
-     *
-     * @param principal <description>
-     * @return <description>
-     */
     public synchronized boolean removeMember(Principal principal)
     {
         return _members.remove(principal);
     }
 
-    /**
-     *
-     * @param principal <description>
-     * @return <description>
-     */
     public boolean isMember(Principal principal)
     {
         return _members.contains(principal);
     }
 
-
-    
-    /**
-     *
-     * @return <description>
-     */
     public Enumeration<? extends Principal> members()
     {
 
@@ -105,23 +81,11 @@
         return new MembersEnumeration (_members.iterator());
     }
 
-
-    /**
-     *
-     * @return <description>
-     */
     public int hashCode()
     {
         return getName().hashCode();
     }
 
-
-    
-    /**
-     *
-     * @param object <description>
-          * @return <description>
-     */
     public boolean equals(Object object)
     {
         if (! (object instanceof JAASGroup))
@@ -130,23 +94,14 @@
         return ((JAASGroup)object).getName().equals(getName());
     }
 
-    /**
-     *
-     * @return <description>
-     */
     public String toString()
     {
         return getName();
     }
 
-    /**
-     *
-     * @return <description>
-     */
     public String getName()
     {
         
         return _name;
     }
-
 }
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
index c641029..cda28e6 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASLoginService.java
@@ -34,14 +34,13 @@
 import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
+import javax.servlet.ServletRequest;
 
 import org.eclipse.jetty.jaas.callback.ObjectCallback;
 import org.eclipse.jetty.jaas.callback.RequestParameterCallback;
 import org.eclipse.jetty.security.DefaultIdentityService;
 import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.LoginService;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -49,9 +48,9 @@
 import org.eclipse.jetty.util.log.Logger;
 
 /* ---------------------------------------------------- */
-/** JAASLoginService
+/** 
+ * JAASLoginService
  *
- * @org.apache.xbean.XBean element="jaasUserRealm" description="Creates a UserRealm suitable for use with JAAS"
  */
 public class JAASLoginService extends AbstractLifeCycle implements LoginService
 {
@@ -181,7 +180,8 @@
     }
 
     /* ------------------------------------------------------------ */
-    public UserIdentity login(final String username,final Object credentials)
+    @Override
+    public UserIdentity login(final String username,final Object credentials, final ServletRequest request)
     {
         try
         {
@@ -210,17 +210,9 @@
                             }
                             else if (callback instanceof RequestParameterCallback)
                             {
-                                HttpChannel channel = HttpChannel.getCurrentHttpChannel();
-
-                                if (channel == null)
-                                    return;
-                                Request request = channel.getRequest();
-
-                                if (request != null)
-                                {
-                                    RequestParameterCallback rpc = (RequestParameterCallback)callback;
+                                RequestParameterCallback rpc = (RequestParameterCallback)callback;
+                                if (request!=null)
                                     rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName())));
-                                }
                             }
                             else
                                 throw new UnsupportedCallbackException(callback);
@@ -230,7 +222,7 @@
             }
             else
             {
-                Class clazz = Loader.loadClass(getClass(), _callbackHandlerClass);
+                Class<?> clazz = Loader.loadClass(getClass(), _callbackHandlerClass);
                 callbackHandler = (CallbackHandler)clazz.newInstance();
             }
             //set up the login context
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java
index 896a38e..87b947e 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASPrincipal.java
@@ -21,41 +21,22 @@
 import java.io.Serializable;
 import java.security.Principal;
 
-
-
-/* ---------------------------------------------------- */
-/** JAASPrincipal
- * <p>Impl class of Principal interface.
- *
- * <p><h4>Notes</h4>
+/** 
+ * JAASPrincipal
  * <p>
- *
- * <p><h4>Usage</h4>
- * <pre>
- */
-/*
- * </pre>
- *
- * @see
- * @version 1.0 Tue Apr 15 2003
- * 
+ * Impl class of Principal interface.
  */
 public class JAASPrincipal implements Principal, Serializable
 {
-    /**
-     * 
-     */
     private static final long serialVersionUID = -5538962177019315479L;
     
     private String _name = null;
     
-    
     public JAASPrincipal(String userName)
     {
         this._name = userName;
     }
 
-
     public boolean equals (Object p)
     {
         if (! (p instanceof JAASPrincipal))
@@ -64,26 +45,20 @@
         return getName().equals(((JAASPrincipal)p).getName());
     }
 
-
     public int hashCode ()
     {
         return getName().hashCode();
     }
 
-
     public String getName ()
     {
         return this._name;
     }
 
-
     public String toString ()
     {
         return getName();
     }
-    
-
-    
 }
 
     
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java
index 0835228..ed5cf00 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASRole.java
@@ -18,13 +18,8 @@
 
 package org.eclipse.jetty.jaas;
 
-
 public class JAASRole extends JAASPrincipal
 {
-    
-    /**
-     * 
-     */
     private static final long serialVersionUID = 3465114254970134526L;
 
     public JAASRole(String name)
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java
index aba4b9c..51d2b80 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/JAASUserPrincipal.java
@@ -23,15 +23,11 @@
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 
-
-
-/* ---------------------------------------------------- */
-/** JAASUserPrincipal
- * <p>Implements the JAAS version of the
+/** 
+ * JAASUserPrincipal
+ * <p>
+ * Implements the JAAS version of the
  *  org.eclipse.jetty.http.UserPrincipal interface.
- *
- * @version $Id: JAASUserPrincipal.java 4780 2009-03-17 15:36:08Z jesse $
- *
  */
 public class JAASUserPrincipal implements Principal
 {
@@ -40,7 +36,6 @@
     private final LoginContext _loginContext;
 
     /* ------------------------------------------------ */
-
     public JAASUserPrincipal(String name, Subject subject, LoginContext loginContext)
     {
         this._name = name;
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java
index 6aab02e..d3cc25b 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/RoleCheckPolicy.java
@@ -21,7 +21,6 @@
 import java.security.Principal;
 import java.security.acl.Group;
 
-
 public interface RoleCheckPolicy 
 {
     /* ------------------------------------------------ */
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java
index 88b5331..b3f4ccd 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/StrictRoleCheckPolicy.java
@@ -31,7 +31,6 @@
  * 
  *
  * 
- * @org.apache.xbean.XBean description ="Check only topmost role in stack of roles for user"
  */
 public class StrictRoleCheckPolicy implements RoleCheckPolicy
 {
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java
index b354203..c06038b 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/DefaultCallbackHandler.java
@@ -29,28 +29,11 @@
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.security.Password;
 
-
-
-/* ---------------------------------------------------- */
-/** DefaultUsernameCredentialCallbackHandler
- * <p>
- *
- * <p><h4>Notes</h4>
- * <p>
- *
- * <p><h4>Usage</h4>
- * <pre>
- */
-/*
- * </pre>
- *
- * @see
- * @version 1.0 Tue Apr 15 2003
- *
+/** 
+ * DefaultUsernameCredentialCallbackHandler
  */
 public class DefaultCallbackHandler extends AbstractCallbackHandler
 {
-
     private Request _request;
 
     public void setRequest (Request request)
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java
index db836ea..670766d 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/ObjectCallback.java
@@ -20,31 +20,16 @@
 
 import javax.security.auth.callback.Callback;
 
-
-/* ---------------------------------------------------- */
-/** ObjectCallback
- *
- * <p>Can be used as a LoginModule Callback to
+/** 
+ * ObjectCallback
+ * <p>
+ * Can be used as a LoginModule Callback to
  * obtain a user's credential as an Object, rather than
  * a char[], to which some credentials may not be able
  * to be converted
- *
- * <p><h4>Notes</h4>
- * <p>
- *
- * <p><h4>Usage</h4>
- * <pre>
- */
-/*
- * </pre>
- *
- * @see
- * @version 1.0 Tue Apr 15 2003
- * 
  */
 public class ObjectCallback implements Callback
 {
-
     protected Object _object;
     
     public void setObject(Object o)
@@ -57,11 +42,8 @@
         return _object;
     }
 
-
     public void clearObject ()
     {
         _object = null;
     }
-    
-    
 }
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java
index f1e3d26..84169fd 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java
@@ -22,18 +22,12 @@
 
 import javax.security.auth.callback.Callback;
 
-
 /**
- *
  * RequestParameterCallback
- *
+ * <p>
  * Allows a JAAS callback handler to access any parameter from the j_security_check FORM.
  * This means that a LoginModule can access form fields other than the j_username and j_password
  * fields, and use it, for example, to authenticate a user.
- *
- *
- * @version $Revision: 4780 $ $Date: 2009-03-17 16:36:08 +0100 (Tue, 17 Mar 2009) $
- *
  */
 public class RequestParameterCallback implements Callback
 {
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java
index 4e8c60f..6c009af 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractDatabaseLoginModule.java
@@ -21,7 +21,6 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
-import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -54,21 +53,36 @@
     private String dbUserRoleTableUserField;
     private String dbUserRoleTableRoleField;
 
-
-
-
     /**
      * @return a java.sql.Connection from the database
-     * @throws Exception
+     * @throws Exception if unable to get the connection
      */
     public abstract Connection getConnection () throws Exception;
+    
+    
+    public class JDBCUserInfo extends UserInfo
+    {
+        public JDBCUserInfo (String userName, Credential credential)
+        {
+            super(userName, credential);
+        }
+        
+        
+        
+        @Override
+        public List<String> doFetchRoles ()
+        throws Exception
+        {
+           return getRoles(getUserName());
+        }
+    }
 
 
 
     /* ------------------------------------------------ */
     /** Load info from database
      * @param userName user info to load
-     * @exception SQLException
+     * @exception Exception if unable to get the user info
      */
     public UserInfo getUserInfo (String userName)
         throws Exception
@@ -95,8 +109,22 @@
                 return null;
             }
 
+          
+
+            return new JDBCUserInfo (userName, Credential.getCredential(dbCredential));
+        }
+    }
+    
+    
+    public List<String>  getRoles (String userName)
+    throws Exception
+    {
+        List<String> roles = new ArrayList<String>();
+        
+        try (Connection connection = getConnection())
+        {
             //query for role names
-            List<String> roles = new ArrayList<String>();
+
             try (PreparedStatement statement = connection.prepareStatement (rolesQuery))
             {
                 statement.setString (1, userName);
@@ -109,10 +137,13 @@
                     }
                 }
             }
-
-            return new UserInfo (userName, Credential.getCredential(dbCredential), roles);
+          
         }
+
+        return roles;
     }
+    
+    
 
 
     public void initialize(Subject subject,
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java
index e504bb3..5bd9123 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/AbstractLoginModule.java
@@ -44,7 +44,6 @@
  *
  * Abstract base class for all LoginModules. Subclasses should
  * just need to implement getUserInfo method.
- *
  */
 public abstract class AbstractLoginModule implements LoginModule
 {
@@ -55,6 +54,12 @@
     private JAASUserInfo currentUser;
     private Subject subject;
 
+    /**
+     * JAASUserInfo
+     *
+     * This class unites the UserInfo data with jaas concepts
+     * such as Subject and Principals
+     */
     public class JAASUserInfo
     {
         private UserInfo user;
@@ -63,7 +68,8 @@
 
         public JAASUserInfo (UserInfo u)
         {
-            setUserInfo(u);
+            this.user = u;
+            this.principal = new JAASPrincipal(u.getUserName());
         }
 
         public String getUserName ()
@@ -76,19 +82,7 @@
             return this.principal;
         }
 
-        public void setUserInfo (UserInfo u)
-        {
-            this.user = u;
-            this.principal = new JAASPrincipal(u.getUserName());
-            this.roles = new ArrayList<JAASRole>();
-            if (u.getRoleNames() != null)
-            {
-                Iterator<String> itor = u.getRoleNames().iterator();
-                while (itor.hasNext())
-                    this.roles.add(new JAASRole((String)itor.next()));
-            }
-        }
-
+ 
         public void setJAASInfo (Subject subject)
         {
             subject.getPrincipals().add(this.principal);
@@ -107,10 +101,20 @@
         {
             return this.user.checkCredential(suppliedCredential);
         }
+        
+        public void fetchRoles() throws Exception
+        {
+            this.user.fetchRoles();
+            this.roles = new ArrayList<JAASRole>();
+            if (this.user.getRoleNames() != null)
+            {
+                Iterator<String> itor = this.user.getRoleNames().iterator();
+                while (itor.hasNext())
+                    this.roles.add(new JAASRole((String)itor.next()));
+            }
+        }
     }
 
-
-
     public Subject getSubject ()
     {
         return this.subject;
@@ -162,7 +166,7 @@
     }
     /**
      * @see javax.security.auth.spi.LoginModule#abort()
-     * @throws LoginException
+     * @throws LoginException if unable to abort
      */
     public boolean abort() throws LoginException
     {
@@ -173,11 +177,10 @@
     /**
      * @see javax.security.auth.spi.LoginModule#commit()
      * @return true if committed, false if not (likely not authenticated)
-     * @throws LoginException
+     * @throws LoginException if unable to commit
      */
     public boolean commit() throws LoginException
     {
-
         if (!isAuthenticated())
         {
             currentUser = null;
@@ -215,7 +218,7 @@
     /**
      * @see javax.security.auth.spi.LoginModule#login()
      * @return true if is authenticated, false otherwise
-     * @throws LoginException
+     * @throws LoginException if unable to login
      */
     public boolean login() throws LoginException
     {
@@ -255,7 +258,10 @@
             setAuthenticated(currentUser.checkCredential(webCredential));
           
             if (isAuthenticated())
+            {
+                currentUser.fetchRoles();
                 return true;
+            }
             else
                 throw new FailedLoginException();
         }
@@ -278,7 +284,7 @@
     /**
      * @see javax.security.auth.spi.LoginModule#logout()
      * @return true always
-     * @throws LoginException
+     * @throws LoginException if unable to logout
      */
     public boolean logout() throws LoginException
     {
@@ -288,10 +294,10 @@
 
     /**
      * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
-     * @param subject
-     * @param callbackHandler
-     * @param sharedState
-     * @param options
+     * @param subject the subject
+     * @param callbackHandler the callback handler
+     * @param sharedState the shared state map
+     * @param options the option map
      */
     public void initialize(Subject subject, CallbackHandler callbackHandler,
             Map<String,?> sharedState, Map<String,?> options)
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java
index d829418..a935462 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.java
@@ -42,12 +42,15 @@
     private DataSource dataSource;
 
     /* ------------------------------------------------ */
-    /** Init LoginModule.
+    /** 
+     * Init LoginModule.
+     * <p>
      * Called once by JAAS after new instance created.
-     * @param subject
-     * @param callbackHandler
-     * @param sharedState
-     * @param options
+     * 
+     * @param subject the subject
+     * @param callbackHandler the callback handler
+     * @param sharedState the shared state map
+     * @param options the option map
      */
     public void initialize(Subject subject,
                            CallbackHandler callbackHandler,
@@ -70,21 +73,15 @@
         }
     }
 
-
     /**
      * Get a connection from the DataSource
      * @see AbstractDatabaseLoginModule#getConnection()
      * @return the connection for the datasource
-     * @throws Exception
+     * @throws Exception if unable to get the connection
      */
     public Connection getConnection ()
     throws Exception
     {
         return dataSource.getConnection();
     }
-
-
-
-
-
 }
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java
index 5a82030..9ee7a01 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/JDBCLoginModule.java
@@ -29,22 +29,14 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-
-
-/* ---------------------------------------------------- */
-/** JDBCLoginModule
- * <p>JAAS LoginModule to retrieve user information from
- *  a database and authenticate the user.
- *
- * <p><h4>Notes</h4>
+/** 
+ * JDBCLoginModule
+ * <p>
+ * JAAS LoginModule to retrieve user information from
+ * a database and authenticate the user.
+ * <h1>Notes</h1>
  * <p>This version uses plain old JDBC connections NOT
  * Datasources.
- *
- * <p><h4>Usage</h4>
- * <pre>
- * </pre>
- *
- * @version 1.0 Tue Apr 15 2003
  */
 public class JDBCLoginModule extends AbstractDatabaseLoginModule
 {
@@ -55,12 +47,11 @@
     private String dbUserName;
     private String dbPassword;
 
-
     /**
      * Get a connection from the DriverManager
      * @see AbstractDatabaseLoginModule#getConnection()
      * @return the connection for this datasource
-     * @throws Exception
+     * @throws Exception if unable to get the connection
      */
     public Connection getConnection ()
     throws Exception
@@ -80,12 +71,15 @@
 
 
     /* ------------------------------------------------ */
-    /** Init LoginModule.
+    /** 
+     * Init LoginModule.
+     * <p>
      * Called once by JAAS after new instance created.
-     * @param subject
-     * @param callbackHandler
-     * @param sharedState
-     * @param options
+     * 
+     * @param subject the subject
+     * @param callbackHandler the callback handler
+     * @param sharedState the shared state map
+     * @param options the options map
      */
     public void initialize(Subject subject,
                            CallbackHandler callbackHandler,
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java
index f18f8fb..48c0e64 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/LdapLoginModule.java
@@ -49,15 +49,12 @@
 
 /**
  * A LdapLoginModule for use with JAAS setups
- * <p/>
+ * <p>
  * The jvm should be started with the following parameter:
- * <br><br>
- * <code>
+ * <pre>
  * -Djava.security.auth.login.config=etc/ldap-loginModule.conf
- * </code>
- * <br><br>
+ * </pre>
  * and an example of the ldap-loginModule.conf would be:
- * <br><br>
  * <pre>
  * ldaploginmodule {
  *    org.eclipse.jetty.server.server.plus.jaas.spi.LdapLoginModule required
@@ -80,11 +77,7 @@
  *    roleMemberAttribute="uniqueMember"
  *    roleObjectClass="groupOfUniqueNames";
  *    };
- *  </pre>
- *
- *
- *
- *
+ * </pre>
  */
 public class LdapLoginModule extends AbstractLoginModule
 {
@@ -137,7 +130,7 @@
 
     /**
      * name of the attribute that a users password is stored under
-     * <p/>
+     * <p>
      * NOTE: not always accessible, see force binding login
      */
     private String _userPasswordAttribute = "userPassword";
@@ -183,17 +176,39 @@
 
     private DirContext _rootContext;
 
+    
+    public class LDAPUserInfo extends UserInfo
+    {
+
+        /**
+         * @param userName
+         * @param credential
+         */
+        public LDAPUserInfo(String userName, Credential credential)
+        {
+            super(userName, credential);
+        }
+
+        @Override
+        public List<String> doFetchRoles() throws Exception
+        {
+            return getUserRoles(_rootContext, getUserName());
+        }
+        
+    }
+    
+    
     /**
      * get the available information about the user
-     * <p/>
+     * <p>
      * for this LoginModule, the credential can be null which will result in a
      * binding ldap authentication scenario
-     * <p/>
+     * <p>
      * roles are also an optional concept if required
      *
-     * @param username
+     * @param username the user name
      * @return the userinfo for the username
-     * @throws Exception
+     * @throws Exception if unable to get the user info
      */
     public UserInfo getUserInfo(String username) throws Exception
     {
@@ -206,9 +221,7 @@
 
         pwdCredential = convertCredentialLdapToJetty(pwdCredential);
         Credential credential = Credential.getCredential(pwdCredential);
-        List<String> roles = getUserRoles(_rootContext, username);
-
-        return new UserInfo(username, credential, roles);
+        return new LDAPUserInfo(username, credential);
     }
 
     protected String doRFC2254Encoding(String inputString)
@@ -244,7 +257,7 @@
 
     /**
      * attempts to get the users credentials from the users context
-     * <p/>
+     * <p>
      * NOTE: this is not an user authenticated operation
      *
      * @param username
@@ -307,7 +320,7 @@
 
     /**
      * attempts to get the users roles from the root context
-     * <p/>
+     * <p>
      * NOTE: this is not an user authenticated operation
      *
      * @param dirContext
@@ -373,13 +386,13 @@
 
     /**
      * since ldap uses a context bind for valid authentication checking, we override login()
-     * <p/>
+     * <p>
      * if credentials are not available from the users context or if we are forcing the binding check
      * then we try a binding authentication check, otherwise if we have the users encoded password then
      * we can try authentication via that mechanic
      *
      * @return true if authenticated, false otherwise
-     * @throws LoginException
+     * @throws LoginException if unable to login
      */
     public boolean login() throws LoginException
     {
@@ -418,12 +431,17 @@
 
             setCurrentUser(new JAASUserInfo(userInfo));
 
+            boolean authed = false;            
             if (webCredential instanceof String)
-            {
-                return credentialLogin(Credential.getCredential((String) webCredential));
-            }
-
-            return credentialLogin(webCredential);
+                authed = credentialLogin(Credential.getCredential((String) webCredential));
+            else
+                authed = credentialLogin(webCredential);
+            
+            //only fetch roles if authenticated
+            if (authed)
+                getCurrentUser().fetchRoles();
+            
+            return authed;
         }
         catch (UnsupportedCallbackException e)
         {
@@ -450,9 +468,9 @@
     /**
      * password supplied authentication check
      *
-     * @param webCredential
+     * @param webCredential the web credential
      * @return true if authenticated
-     * @throws LoginException
+     * @throws LoginException if unable to login
      */
     protected boolean credentialLogin(Object webCredential) throws LoginException
     {
@@ -466,10 +484,11 @@
      * has an ACI (access control instruction) that allow the access to any user or at least
      * for the user that logs in.
      *
-     * @param username
-     * @param password
+     * @param username the user name
+     * @param password the password
      * @return true always
-     * @throws LoginException
+     * @throws LoginException if unable to bind the login
+     * @throws NamingException if failure to bind login
      */
     public boolean bindingLogin(String username, Object password) throws LoginException, NamingException
     {
@@ -502,16 +521,18 @@
 
         String filter = "(&(objectClass={0})({1}={2}))";
 
-        LOG.info("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Searching for users with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
 
         Object[] filterArguments = new Object[]{
-            _userObjectClass,
-            _userIdAttribute,
-            username
+                                                _userObjectClass,
+                                                _userIdAttribute,
+                                                username
         };
         NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
 
-        LOG.info("Found user?: " + results.hasMoreElements());
+        if (LOG.isDebugEnabled())
+            LOG.debug("Found user?: " + results.hasMoreElements());
 
         if (!results.hasMoreElements())
         {
@@ -524,12 +545,13 @@
 
     /**
      * Init LoginModule.
+     * <p>
      * Called once by JAAS after new instance is created.
      *
-     * @param subject
-     * @param callbackHandler
-     * @param sharedState
-     * @param options
+     * @param subject the subect
+     * @param callbackHandler the callback handler
+     * @param sharedState the shared state map
+     * @param options the option map
      */
     public void initialize(Subject subject,
                            CallbackHandler callbackHandler,
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java
index c91c548..14de803 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.java
@@ -36,8 +36,6 @@
 
 /**
  * PropertyFileLoginModule
- *
- *
  */
 public class PropertyFileLoginModule extends AbstractLoginModule
 {
@@ -55,10 +53,11 @@
      *
      * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map,
      *      java.util.Map)
-     * @param subject
-     * @param callbackHandler
-     * @param sharedState
-     * @param options
+     *      
+     * @param subject the subject
+     * @param callbackHandler the callback handler
+     * @param sharedState the shared state map
+     * @param options the options map
      */
     public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)
     {
@@ -102,10 +101,10 @@
     }
 
     /**
-     * Don't implement this as we want to pre-fetch all of the users.
+     * 
      *
-     * @param userName
-     * @throws Exception
+     * @param userName the user name
+     * @throws Exception if unable to get the user information
      */
     public UserInfo getUserInfo(String userName) throws Exception
     {
@@ -118,6 +117,8 @@
         if (userIdentity==null)
             return null;
 
+        //TODO in future versions change the impl of PropertyUserStore so its not
+        //storing Subjects etc, just UserInfo
         Set<Principal> principals = userIdentity.getSubject().getPrincipals();
 
         List<String> roles = new ArrayList<String>();
diff --git a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java
index 4b0d02a..f2656c2 100644
--- a/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java
+++ b/jetty-jaas/src/main/java/org/eclipse/jetty/jaas/spi/UserInfo.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.jaas.spi;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.jetty.util.security.Credential;
@@ -29,24 +30,70 @@
  * This is the information read from the external source
  * about a user.
  * 
- * Can be cached by a UserInfoCache implementation
+ * Can be cached.
  */
 public class UserInfo
 {
     
     private String _userName;
     private Credential _credential;
-    private List<String> _roleNames;
+    protected List<String> _roleNames = new ArrayList<>();
+    protected boolean _rolesLoaded = false;
     
     
+    /**
+     * @param userName
+     * @param credential
+     * @param roleNames
+     */
     public UserInfo (String userName, Credential credential, List<String> roleNames)
     {
         _userName = userName;
         _credential = credential;
-        _roleNames = new ArrayList<String>();
         if (roleNames != null)
         {
-            _roleNames.addAll(roleNames);
+            synchronized (_roleNames)
+            {
+                _roleNames.addAll(roleNames);
+                _rolesLoaded = true;
+            }
+        }
+    }
+    
+    
+    /**
+     * @param userName
+     * @param credential
+     */
+    public UserInfo (String userName, Credential credential)
+    {
+        this (userName, credential, null);
+    }
+    
+    
+    
+    /**
+     * Should be overridden by subclasses to obtain
+     * role info
+     * 
+     * @return
+     * @throws Exception
+     */
+    public List<String> doFetchRoles ()
+    throws Exception
+    {
+        return Collections.emptyList();
+    }
+    
+    public void fetchRoles () throws Exception
+    {
+        synchronized (_roleNames)
+        {
+            if (!_rolesLoaded)
+            {
+                _roleNames.addAll(doFetchRoles());
+                _rolesLoaded = true;
+            }
         }
     }
     
@@ -56,8 +103,8 @@
     }
     
     public List<String> getRoleNames ()
-    {
-        return new ArrayList<String>(_roleNames);
+    {   
+        return Collections.unmodifiableList(_roleNames);
     }
     
     public boolean checkCredential (Object suppliedCredential)
diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml
index 84ffab4..fc83e23 100644
--- a/jetty-jaspi/pom.xml
+++ b/jetty-jaspi/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jaspi</artifactId>
@@ -10,57 +10,10 @@
   <description>Jetty security infrastructure</description>
   <url>http://www.eclipse.org/jetty</url>
   <properties>
-    <bundle-symbolic-name>${project.groupId}.jaspi</bundle-symbolic-name>
+    <bundle-symbolic-name>${project.groupId}.security.jaspi</bundle-symbolic-name>
   </properties>
   <build>
     <plugins>
-     <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package>
-                <Export-Package>org.eclipse.jetty.security.jaspi.*;version="${parsedVersion.osgiVersion}"</Export-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>               
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java
index cf41bc3..d138f2a 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticator.java
@@ -121,7 +121,7 @@
     @Override
     public UserIdentity login(String username, Object password, ServletRequest request)
     { 
-        UserIdentity user = _loginService.login(username, password);
+        UserIdentity user = _loginService.login(username, password, request);
         if (user != null)
         {
             renewSession((HttpServletRequest)request, null);
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java
index 987b726..e95f1af 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiAuthenticatorFactory.java
@@ -135,6 +135,8 @@
      * If {@link #setServiceSubject(Subject)} has not been used to 
      * set a subject, then the {@link Server#getBeans(Class)} method is
      * used to look for a Subject.
+     * @param server the server to pull the Subject from
+     * @return the subject
      */
     protected Subject findServiceSubject(Server server)
     {
@@ -151,6 +153,9 @@
      * If {@link #setServerName(String)} has not been called, then
      * use the name of the a principal in the service subject.
      * If not found, return "server".
+     * @param server not used
+     * @param subject the subject to use
+     * @return the server name from the subject (or default value if not found in subject or principals)
      */
     protected String findServerName(Server server, Subject subject)
     {
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java
index 536750f..a46efe3 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/JaspiMessageInfo.java
@@ -27,11 +27,8 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
-
 /**
  * Almost an implementation of jaspi MessageInfo.
- *
- * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
  */
 public class JaspiMessageInfo implements MessageInfo
 {
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java
index 2d09218..2c56251 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/ServletCallbackHandler.java
@@ -39,10 +39,7 @@
 import org.eclipse.jetty.server.UserIdentity;
 
 /**
- * 
  * Idiot class required by jaspi stupidity
- * 
- * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
  */
 public class ServletCallbackHandler implements CallbackHandler
 {
@@ -74,7 +71,7 @@
                 PasswordValidationCallback passwordValidationCallback = (PasswordValidationCallback) callback;
                 Subject subject = passwordValidationCallback.getSubject();
 
-                UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(),passwordValidationCallback.getPassword());
+                UserIdentity user = _loginService.login(passwordValidationCallback.getUsername(),passwordValidationCallback.getPassword(), null);
                 
                 if (user!=null)
                 {
@@ -91,7 +88,7 @@
                         credentialValidationCallback.getUsername(),
                         credentialValidationCallback.getCredential());
 
-                UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(),credentialValidationCallback.getCredential());
+                UserIdentity user = _loginService.login(credentialValidationCallback.getUsername(),credentialValidationCallback.getCredential(), null);
 
                 if (user!=null)
                 {
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java
index 204a282..712a4f3 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java
@@ -26,9 +26,6 @@
 import javax.security.auth.message.config.ServerAuthConfig;
 import javax.security.auth.message.config.ServerAuthContext;
 
-/**
- * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
- */
 public class SimpleAuthConfig implements ServerAuthConfig
 {
     public static final String HTTP_SERVLET = "HttpServlet";
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java
index 4a58eaa..e732d67 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BaseAuthModule.java
@@ -45,9 +45,6 @@
 import org.eclipse.jetty.util.security.Credential;
 import org.eclipse.jetty.util.security.Password;
 
-/**
- * @version $Rev: 4792 $ $Date: 2009-03-18 22:55:52 +0100 (Wed, 18 Mar 2009) $
- */
 public class BaseAuthModule implements ServerAuthModule, ServerAuthContext
 {
     private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] { HttpServletRequest.class, HttpServletResponse.class };
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java
index ddae380..1edc073 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/BasicAuthModule.java
@@ -36,10 +36,7 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.security.Constraint;
 
-/**
- * @deprecated use *ServerAuthentication
- * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
- */
+@Deprecated
 public class BasicAuthModule extends BaseAuthModule
 {
     private static final Logger LOG = Log.getLogger(BasicAuthModule.class);
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java
index e73b083..bd9476f 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/ClientCertAuthModule.java
@@ -34,10 +34,7 @@
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.security.Password;
 
-/**
- * @deprecated use *ServerAuthentication
- * @version $Rev: 4530 $ $Date: 2009-02-13 00:47:44 +0100 (Fri, 13 Feb 2009) $
- */
+@Deprecated
 public class ClientCertAuthModule extends BaseAuthModule
 {
 
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java
index 34376c2..a6a39c3 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/DigestAuthModule.java
@@ -42,15 +42,11 @@
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.security.Credential;
 
-/**
- * @deprecated use *ServerAuthentication
- * @version $Rev: 4627 $ $Date: 2009-02-20 00:07:19 +0100 (Fri, 20 Feb 2009) $
- */
+@Deprecated
 public class DigestAuthModule extends BaseAuthModule
 {
     private static final Logger LOG = Log.getLogger(DigestAuthModule.class);
 
-
     protected long maxNonceAge = 0;
 
     protected long nonceSecret = this.hashCode() ^ System.currentTimeMillis();
@@ -213,11 +209,10 @@
     }
 
     /**
-     * @param nonce
+     * @param nonce the nonce
      * @param timestamp should be timestamp of request.
      * @return -1 for a bad nonce, 0 for a stale none, 1 for a good nonce
      */
-    /* ------------------------------------------------------------ */
     public int checkNonce(String nonce, long timestamp)
     {
         try
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
index 970de7c..d8e5b33 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java
@@ -33,7 +33,6 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-import org.eclipse.jetty.security.CrossContextPsuedoSession;
 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
 import org.eclipse.jetty.security.authentication.LoginCallbackImpl;
 import org.eclipse.jetty.security.authentication.SessionAuthentication;
@@ -45,10 +44,7 @@
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.security.Password;
 
-/**
- * @deprecated use *ServerAuthentication
- * @version $Rev: 4792 $ $Date: 2009-03-18 22:55:52 +0100 (Wed, 18 Mar 2009) $
- */
+@Deprecated
 public class FormAuthModule extends BaseAuthModule
 {
     private static final Logger LOG = Log.getLogger(FormAuthModule.class);
@@ -79,7 +75,6 @@
 
     private String _formLoginPath;
 
-    private CrossContextPsuedoSession<UserInfo> ssoSource;
 
     public FormAuthModule()
     {
@@ -92,17 +87,6 @@
         setErrorPage(errorPage);
     }
 
-    /**
-     * @deprecated
-     */
-    public FormAuthModule(CallbackHandler callbackHandler, CrossContextPsuedoSession<UserInfo> ssoSource, 
-                          String loginPage, String errorPage)
-    {
-        super(callbackHandler);
-        this.ssoSource = ssoSource;
-        setLoginPage(loginPage);
-        setErrorPage(errorPage);
-    }
 
     @Override
     public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, 
@@ -112,7 +96,6 @@
         super.initialize(requestPolicy, responsePolicy, handler, options);
         setLoginPage((String) options.get(LOGIN_PAGE_KEY));
         setErrorPage((String) options.get(ERROR_PAGE_KEY));
-        ssoSource = (CrossContextPsuedoSession<UserInfo>) options.get(SSO_SOURCE_KEY);
     }
 
     private void setLoginPage(String path)
@@ -232,17 +215,7 @@
 
                 return AuthStatus.SUCCESS;  
             }
-            else if (ssoSource != null)
-            {
-                UserInfo userInfo = ssoSource.fetch(request);
-                if (userInfo != null)
-                {
-                    boolean success = tryLogin(messageInfo, clientSubject, response, session, userInfo.getUserName(), new Password(new String(userInfo.getPassword())));
-                    if (success) { return AuthStatus.SUCCESS; }
-                }
-            }
             
-           
 
             // if we can't send challenge
             if (DeferredAuthentication.isDeferred(response))
@@ -311,12 +284,6 @@
                 }
             }
 
-            // Sign-on to SSO mechanism
-            if (ssoSource != null)
-            {
-                UserInfo userInfo = new UserInfo(username, pwdChars);
-                ssoSource.store(userInfo, response);
-            }
             return true;
         }
         return false;
diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java
index eca6e9e..71cf12e 100644
--- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java
+++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/UserInfo.java
@@ -20,9 +20,6 @@
 
 import java.util.Arrays;
 
-/**
- * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
- */
 public class UserInfo
 {
     private final String userName;
diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml
index 216371f..b8cd6fd 100644
--- a/jetty-jmx/pom.xml
+++ b/jetty-jmx/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jmx</artifactId>
@@ -15,52 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.management.*,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml b/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
index 3527d8b..bd6cbc6 100644
--- a/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
+++ b/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
@@ -1,28 +1,39 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
+  <!-- =========================================================== -->
+  <!-- Set the java.rmi.server.hostname property in case you've    -->
+  <!-- got a misconfigured /etc/hosts entry or the like.           -->
+  <!-- =========================================================== -->
+  <!--
+  <Call class="java.lang.System" name="setProperty">
+    <Arg>java.rmi.server.hostname</Arg>
+    <Arg>127.0.0.1</Arg>
+  </Call>
+  -->
+
   <!-- Add a remote JMX connector. The parameters of the constructor
-       below specify the JMX service URL, and the object name string for the
-       connector server bean. The parameters of the JMXServiceURL constructor
-       specify the protocol that clients will use to connect to the remote JMX
-       connector (RMI), the hostname of the server (local hostname), port number
-       (automatically assigned), and the URL path. Note that URL path contains
-       the RMI registry hostname and port number, that may need to be modified
-       in order to comply with the firewall requirements.
+  below specify the JMX service URL, and the object name string for the
+  connector server bean. The parameters of the JMXServiceURL constructor
+  specify the protocol that clients will use to connect to the remote JMX
+  connector (RMI), the hostname of the server (local hostname), port number
+  (automatically assigned), and the URL path. Note that URL path contains
+  the RMI registry hostname and port number, that may need to be modified
+  in order to comply with the firewall requirements.
   -->
   <Call name="addBean">
     <Arg>
       <New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
-	<Arg>
-	  <New class="javax.management.remote.JMXServiceURL">
-	    <Arg type="java.lang.String">rmi</Arg>
-	    <Arg type="java.lang.String" />
-	    <Arg type="java.lang.Integer"><Property name="jetty.jmxrmiport" default="1099"/></Arg>
-	    <Arg type="java.lang.String">/jndi/rmi://<Property name="jetty.jmxrmihost" default="localhost"/>:<Property name="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
-	  </New>
-	</Arg>
-	<Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
+        <Arg>
+          <New class="javax.management.remote.JMXServiceURL">
+            <Arg type="java.lang.String">rmi</Arg>
+            <Arg type="java.lang.String"><Property name="jetty.jmxremote.rmihost" deprecated="jetty.jmxrmihost" default="localhost"/></Arg>
+            <Arg type="java.lang.Integer"><Property name="jetty.jmxremote.rmiport" deprecated="jetty.jmxrmiport" default="1099"/></Arg>
+            <Arg type="java.lang.String">/jndi/rmi://<Property name="jetty.jmxremote.rmihost" deprecated="jetty.jmxrmihost" default="localhost"/>:<Property name="jetty.jmxremote.rmiport" deprecated="jetty.jmxrmiport" default="1099"/>/jmxrmi</Arg>
+          </New>
+        </Arg>
+        <Arg>org.eclipse.jetty.jmx:name=rmiconnectorserver</Arg>
       </New>
     </Arg>
   </Call>
diff --git a/jetty-jmx/src/main/config/etc/jetty-jmx.xml b/jetty-jmx/src/main/config/etc/jetty-jmx.xml
index aca96f7..e07ea74 100644
--- a/jetty-jmx/src/main/config/etc/jetty-jmx.xml
+++ b/jetty-jmx/src/main/config/etc/jetty-jmx.xml
@@ -1,20 +1,9 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
   <!-- =========================================================== -->
-  <!-- Set the java.rmi.server.hostname property in case you've    -->
-  <!-- got a misconfigured /etc/hosts entry or the like.           -->
-  <!-- =========================================================== -->
-  <!--
-  <Call class="java.lang.System" name="setProperty">
-    <Arg>java.rmi.server.hostname</Arg>
-    <Arg>127.0.0.1</Arg>
-  </Call>
-  -->
-
-  <!-- =========================================================== -->
   <!-- Get the platform mbean server                               -->
   <!-- =========================================================== -->
   <Call id="MBeanServer" class="java.lang.management.ManagementFactory"
diff --git a/jetty-jmx/src/main/config/modules/jmx-remote.mod b/jetty-jmx/src/main/config/modules/jmx-remote.mod
index b6be74a..f8a5111 100644
--- a/jetty-jmx/src/main/config/modules/jmx-remote.mod
+++ b/jetty-jmx/src/main/config/modules/jmx-remote.mod
@@ -9,10 +9,8 @@
 etc/jetty-jmx-remote.xml
 
 [ini-template]
-## JMX Configuration
-## Enable for an open port accessible by remote machines
-# jetty.jmxrmihost=localhost
-# jetty.jmxrmiport=1099
-## Strictly speaking you shouldn't need --exec to use this in most environments.
-## If this isn't working, make sure you enable --exec as well
-# -Dcom.sun.management.jmxremote
+## The host/address to bind RMI to
+# jetty.jmxremote.rmihost=localhost
+
+## The port RMI listens to
+# jetty.jmxremote.rmiport=1099
diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
index 612a1c1..5320c06 100644
--- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
+++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java
@@ -57,7 +57,7 @@
      * The actual address of the new connector server, as returned
      * by its getAddress method, will not necessarily be exactly the same.
      * @param name object name string to be assigned to connector server bean
-     * @throws Exception
+     * @throws Exception if unable to setup connector server
      */
     public ConnectorServer(JMXServiceURL serviceURL, String name)
         throws Exception
@@ -77,7 +77,7 @@
      * be Strings. The appropriate type of each associated value depends on
      * the attribute. The contents of environment are not changed by this call.
      * @param name object name string to be assigned to connector server bean
-     * @throws Exception
+     * @throws Exception if unable to create connector server
      */
     public ConnectorServer(JMXServiceURL svcUrl, Map<String,?> environment, String name)
          throws Exception
diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
index 08aa43c..38cf6f8 100644
--- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
+++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ObjectMBean.java
@@ -59,18 +59,18 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* ------------------------------------------------------------ */
-/** ObjectMBean.
+/** 
+ * ObjectMBean.
+ * <p>
  * A dynamic MBean that can wrap an arbitary Object instance.
  * the attributes and methods exposed by this bean are controlled by
  * the merge of property bundles discovered by names related to all
  * superclasses and all superinterfaces.
- *
+ * <p>
  * Attributes and methods exported may be "Object" and must exist on the
  * wrapped object, or "MBean" and must exist on a subclass of OBjectMBean
  * or "MObject" which exists on the wrapped object, but whose values are
  * converted to MBean object names.
- *
  */
 public class ObjectMBean implements DynamicMBean
 {
@@ -592,7 +592,7 @@
      * getter and setter methods. Descriptions are obtained with a call to findDescription with the
      * attribute name.
      *
-     * @param method
+     * @param method the method to define
      * @param attributeAnnotation "description" or "access:description" or "type:access:description"  where type is
      * one of: <ul>
      * <li>"Object" The field/method is on the managed object.
@@ -601,6 +601,7 @@
      * <li>"MMBean" The field/method is on the mbean proxy object and value should be converted to MBean reference
      * </ul>
      * the access is either "RW" or "RO".
+     * @return the mbean attribute info for the method
      */
     public MBeanAttributeInfo defineAttribute(Method method, ManagedAttribute attributeAnnotation)
     {
diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml
index 2bd43d0..0ef15da 100644
--- a/jetty-jndi/pom.xml
+++ b/jetty-jndi/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jndi</artifactId>
@@ -15,52 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.naming.*,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
index cc17e7d..c482e4a 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/BindingEnumeration.java
@@ -25,14 +25,8 @@
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 
-/** BindingEnumeration
- * <p>Implementation of NamingEnumeration
- *
- * <p><h4>Notes</h4>
- * <p>Used to return results of Context.listBindings();
- *
- * <p><h4>Usage</h4>
- *
+/** 
+ * BindingEnumeration
  */
 public class BindingEnumeration implements NamingEnumeration<Binding>
 {
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
index 9bb0611..aad1b2c 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/ContextFactory.java
@@ -37,30 +37,25 @@
 
 
 /**
- * ContextFactory.java
- *
+ * ContextFactory
+ * <p>
  * This is an object factory that produces a jndi naming
  * context based on a classloader.
- *
- *  It is used for the java:comp context.
- *
- *  This object factory is bound at java:comp. When a
- *  lookup arrives for java:comp,  this object factory
- *  is invoked and will return a context specific to
- *  the caller's environment (so producing the java:comp/env
- *  specific to a webapp).
- *
- *  The context selected is based on classloaders. First
- *  we try looking at the thread context classloader if it is set, and walk its
- *  hierarchy, creating a context if none is found. If the thread context classloader
- *  is not set, then we use the classloader associated with the current Context.
- *  
- *  If there is no current context, or no classloader, we return null.
- *
- * Created: Fri Jun 27 09:26:40 2003
- *
- *
- *
+ * <p>
+ * It is used for the <code>java:comp</code> context.
+ * <p>
+ * This object factory is bound at <code>java:comp</code>. When a
+ * lookup arrives for java:comp,  this object factory
+ * is invoked and will return a context specific to
+ * the caller's environment (so producing the <code>java:comp/env</code>
+ * specific to a webapp).
+ * <p>
+ * The context selected is based on classloaders. First
+ * we try looking at the thread context classloader if it is set, and walk its
+ * hierarchy, creating a context if none is found. If the thread context classloader
+ * is not set, then we use the classloader associated with the current Context.
+ * <p> 
+ * If there is no current context, or no classloader, we return null.
  */
 public class ContextFactory implements ObjectFactory
 {
@@ -87,15 +82,15 @@
 
     /**
      * Find or create a context which pertains to a classloader.
-     *
+     * <p>
      * If the thread context classloader is set, we try to find an already-created naming context
      * for it. If one does not exist, we walk its classloader hierarchy until one is found, or we 
      * run out of parent classloaders. In the latter case, we will create a new naming context associated
      * with the original thread context classloader.
-     * 
+     * <p>
      * If the thread context classloader is not set, we obtain the classloader from the current 
      * jetty Context, and look for an already-created naming context. 
-     * 
+     * <p>
      * If there is no current jetty Context, or it has no associated classloader, we 
      * return null.
      * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable)
@@ -177,12 +172,13 @@
 
     /**
      * Create a new NamingContext.
-     * @param obj
-     * @param loader
-     * @param env
-     * @param name
-     * @param parentCtx
-     * @throws Exception
+     * @param obj the object to create
+     * @param loader the classloader for the naming context
+     * @param env the jndi env for the entry
+     * @param name the name of the entry
+     * @param parentCtx the parent context of the entry
+     * @return the newly created naming context
+     * @throws Exception if unable to create a new naming context
      */
     public NamingContext newNamingContext(Object obj, ClassLoader loader, Hashtable env, Name name, Context parentCtx)
     throws Exception
@@ -201,7 +197,8 @@
   
     /**
      * Find the naming Context for the given classloader
-     * @param loader
+     * @param loader the classloader for the context
+     * @return the context for the classloader
      */
     public Context getContextForClassLoader(ClassLoader loader)
     {
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java
index 6fd0e07..f928408 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/DataSourceCloser.java
@@ -24,6 +24,7 @@
 
 import javax.sql.DataSource;
 
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Destroyable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java
index 41923a2..9699a0d 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NameEnumeration.java
@@ -25,14 +25,8 @@
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 
-/** NameEnumeration
- * <p>Implementation of NamingEnumeration interface.
- *
- * <p><h4>Notes</h4>
- * <p>Used for returning results of Context.list();
- *
- * <p><h4>Usage</h4>
- *
+/** 
+ * NameEnumeration
  */
 public class NameEnumeration implements NamingEnumeration<NameClassPair>
 {
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
index e2add90..bf7b27a 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingContext.java
@@ -18,7 +18,6 @@
 
 package org.eclipse.jetty.jndi;
 
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -48,13 +47,13 @@
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Logger;
 
-
-/*------------------------------------------------*/
-/** NamingContext
- * <p>Implementation of Context interface.
- *
- * <p><h4>Notes</h4>
- * <p>All Names are expected to be Compound, not Composite.
+/** 
+ * NamingContext
+ * <p>
+ * Implementation of Context interface.
+ * <p>
+ * <b>Notes:</b>
+ * All Names are expected to be Compound, not Composite.
  */
 @SuppressWarnings("unchecked")
 public class NamingContext implements Context, Cloneable, Dumpable
@@ -178,11 +177,6 @@
     }
 
     /*------------------------------------------------*/
-    /**
-     * Setter for _parser
-     *
-     *
-     */
     public void setNameParser (NameParser parser)
     {
         _parser = parser;
@@ -1261,6 +1255,7 @@
      *
      * @param name a <code>Name</code> value
      * @param obj an <code>Object</code> value
+     * @throws NameAlreadyBoundException if name already bound
      */
     public void addBinding (Name name, Object obj) throws NameAlreadyBoundException
     {
@@ -1337,7 +1332,7 @@
     /*------------------------------------------------*/
     /**
      * Remove leading or trailing empty components from
-     * name. Eg "/comp/env/" -> "comp/env"
+     * name. Eg "/comp/env/" -&gt; "comp/env"
      *
      * @param name the name to normalize
      * @return normalized name
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java
index 7a62a5d..40e8097 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/NamingUtil.java
@@ -33,13 +33,7 @@
 
 
 /**
- * Util.java
- *
- *
- * Created: Tue Jul  1 18:26:17 2003
- *
- *
- * @version 1.0
+ * Naming Utility Methods
  */
 public class NamingUtil
 {
@@ -53,6 +47,7 @@
      * @param ctx the context into which to bind
      * @param nameStr the name relative to context to bind
      * @param obj the object to be bound
+     * @return the bound context
      * @exception NamingException if an error occurs
      */
     public static Context bind (Context ctx, String nameStr, Object obj)
@@ -112,7 +107,7 @@
      * @param ctx the context containing the name for which to list the bindings
      * @param name the name in the context to list
      * @return map: key is fully qualified name, value is the bound object
-     * @throws NamingException
+     * @throws NamingException if unable to flatten bindings
      */
     public static Map flattenBindings (Context ctx, String name)
     throws NamingException
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java
index 1898678..023d24d 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/factories/MailSessionReference.java
@@ -92,17 +92,8 @@
         {
             this.password = password;
         }
-
-
     };
 
-
-
-
-
-    /**
-     *
-     */
     public MailSessionReference()
     {
        super ("javax.mail.Session", MailSessionReference.class.getName(), null);
@@ -117,7 +108,7 @@
      * @param arg2 not used
      * @param arg3 not used
      * @return the object found
-     * @throws Exception
+     * @throws Exception if unable to get object instance
      */
     public Object getObjectInstance(Object ref, Name arg1, Context arg2, Hashtable arg3) throws Exception
     {
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
index c417c9b..8b86633 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaRootURLContext.java
@@ -37,14 +37,12 @@
 
 
 
-/** javaRootURLContext
- * <p>This is the root of the java: url namespace
- *
- * <p><h4>Notes</h4>
- * <p>Thanks to Rickard Oberg for the idea of binding an ObjectFactory at "comp".
- *
- * <p><h4>Usage</h4>
- * <pre>
+/** 
+ * javaRootURLContext
+ * <p>
+ * This is the root of the <code>java:</code> url namespace
+ * <p>
+ * (Thanks to Rickard Oberg for the idea of binding an ObjectFactory at "comp")
  */
 public class javaRootURLContext implements Context
 {
diff --git a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java
index 56ec433..97aa67f 100644
--- a/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java
+++ b/jetty-jndi/src/main/java/org/eclipse/jetty/jndi/java/javaURLContextFactory.java
@@ -29,14 +29,10 @@
 import org.eclipse.jetty.util.log.Logger;
 
 
-/** javaURLContextFactory
- * <p>This is the URL context factory for the java: URL.
- *
- * <p><h4>Notes</h4>
+/** 
+ * javaURLContextFactory
  * <p>
- *
- * <p><h4>Usage</h4>
- * <pre>
+ * This is the URL context factory for the <code>java:</code> URL.
  */
 public class javaURLContextFactory implements ObjectFactory
 {
diff --git a/jetty-jsp/pom.xml b/jetty-jsp/pom.xml
deleted file mode 100644
index d9c998c..0000000
--- a/jetty-jsp/pom.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty</groupId>
-    <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>jetty-jsp</artifactId>
-  <name>Jetty :: Glassfish JSP Implementation</name>
-  <url>http://www.eclipse.org/jetty</url>
-  <packaging>jar</packaging>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-  <dependencies>
-
-    <dependency>
-        <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-util</artifactId>
-        <version>${project.version}</version>
-        <scope>provided</scope>
-    </dependency>
-    <dependency>
-        <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-server</artifactId>
-        <version>${project.version}</version>
-        <scope>provided</scope>
-    </dependency>
-
-    <!-- Schemas -->
-    <dependency>
-      <groupId>org.eclipse.jetty.toolchain</groupId>
-      <artifactId>jetty-schemas</artifactId>
-    </dependency>
-
-    <!-- servlet api -->
-    <dependency>
-       <groupId>javax.servlet</groupId>
-       <artifactId>javax.servlet-api</artifactId>
-    </dependency>
-
-    <!-- JSP Api -->
-    <dependency>
-      <groupId>javax.servlet.jsp</groupId>
-      <artifactId>javax.servlet.jsp-api</artifactId>
-    </dependency>
-    <!-- JSP Impl -->
-    <dependency>
-      <groupId>org.glassfish.web</groupId>
-      <artifactId>javax.servlet.jsp</artifactId>
-    </dependency>
-
-    <!-- JSTL Api -->
-    <dependency>
-       <groupId>org.eclipse.jetty.orbit</groupId>
-       <artifactId>javax.servlet.jsp.jstl</artifactId>
-    </dependency>
-    <!-- JSTL Impl -->
-    <dependency>
-       <groupId>org.glassfish.web</groupId>
-       <artifactId>javax.servlet.jsp.jstl</artifactId>
-    </dependency>
-
-    <!-- EL Api -->
-    <!-- Not needed as glassfish impl jars contain also the api classes
-    <dependency>
-      <groupId>javax.el</groupId>
-      <artifactId>javax.el-api</artifactId>
-    </dependency>
-    -->
-
-    <!-- EL Impl -->
-    <dependency>
-        <groupId>org.glassfish</groupId>
-        <artifactId>javax.el</artifactId>
-    </dependency>
-
-
-    <!-- Eclipse Java Compiler (for JSP Compilation) -->
-    <dependency>
-      <groupId>org.eclipse.jetty.orbit</groupId>
-      <artifactId>org.eclipse.jdt.core</artifactId>
-    </dependency>
-  </dependencies>
-</project>
diff --git a/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jsp.mod b/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jsp.mod
deleted file mode 100644
index 130d2b3..0000000
--- a/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jsp.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Glassfish JSP Module
-#
-[name]
-jsp-impl
-
-[lib]
-lib/jsp/*.jar
diff --git a/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jstl.mod b/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jstl.mod
deleted file mode 100644
index 4b8e6f3..0000000
--- a/jetty-jsp/src/main/config/modules/jsp-impl/glassfish-jstl.mod
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Glassfish JSTL
-[name]
-jstl-impl
-
-# This file is empty as glassfish jstl is provided by glassfish jsp
diff --git a/jetty-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java b/jetty-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java
deleted file mode 100644
index a97df83..0000000
--- a/jetty-jsp/src/main/java/org/eclipse/jetty/jsp/JettyJspServlet.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.jsp;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.jasper.servlet.JspServlet;
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.resource.Resource;
-
-
-/**
- * JettyJspServlet
- *
- * Wrapper for the jsp servlet that handles receiving requests mapped from 
- * jsp-property-groups. Mappings could be wildcard urls like "/*", which would
- * include welcome files, but we need those to be handled by the DefaultServlet.
- */
-public class JettyJspServlet extends JspServlet
-{
-
-    /**
-     * 
-     */
-    private static final long serialVersionUID = -5387857473125086791L;
-
-    @Override
-    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-    {
-        
-        
-        HttpServletRequest request = null;
-        if (req instanceof HttpServletRequest)
-            request = (HttpServletRequest)req;
-        else
-            throw new ServletException("Request not HttpServletRequest");
-
-        String servletPath=null;
-        String pathInfo=null;
-        if (request.getAttribute("javax.servlet.include.request_uri")!=null)
-        {
-            servletPath=(String)request.getAttribute("javax.servlet.include.servlet_path");
-            pathInfo=(String)request.getAttribute("javax.servlet.include.path_info");
-            if (servletPath==null)
-            {
-                servletPath=request.getServletPath();
-                pathInfo=request.getPathInfo();
-            }
-        }
-        else
-        {
-            servletPath = request.getServletPath();
-            pathInfo = request.getPathInfo();
-        }
-        
-        String pathInContext = URIUtil.addPaths(servletPath,pathInfo);
-        String jspFile = getInitParameter("jspFile");
-        
-        //if the request is for a jsp file then fall through to the jsp servlet
-        if (jspFile == null)
-        {
-            if (pathInContext.endsWith("/"))
-            {
-                //dispatch via forward to the default servlet
-                getServletContext().getNamedDispatcher("default").forward(req, resp);
-                return;
-            }
-            else
-            {      
-                //check if it resolves to a directory
-                Resource resource = ((ContextHandler.Context)getServletContext()).getContextHandler().getResource(pathInContext);           
-                if (resource!=null && resource.isDirectory())
-                {
-                    //dispatch via forward to the default servlet
-                    getServletContext().getNamedDispatcher("default").forward(req, resp);
-                    return;
-                }
-            }
-        }
-
-        //fall through to the normal jsp servlet handling
-        super.service(req, resp);
-    }
-
-    
-}
diff --git a/jetty-jsp/src/main/resources/readme.txt b/jetty-jsp/src/main/resources/readme.txt
deleted file mode 100644
index 39d448b..0000000
--- a/jetty-jsp/src/main/resources/readme.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This jar file is purely to work around a problem with the Maven Dependency plugin.
-Several modules in jetty use the Dependency plugin to copy or unpack the dependencies of  other modules.
-However, the Dependency plugin is not capable of unpacking or copying a dependency of type 'pom', which
-this module is, as it consists purely of external dependencies needed to run jsp.
diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml
index 81cd6d9..893502f 100644
--- a/jetty-jspc-maven-plugin/pom.xml
+++ b/jetty-jspc-maven-plugin/pom.xml
@@ -2,31 +2,34 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-jspc-maven-plugin</artifactId>
   <packaging>maven-plugin</packaging>
   <name>Jetty :: Jetty JSPC Maven Plugin</name>
   <properties>
+    <bundle-symbolic-name>${project.groupId}.jspc.plugin</bundle-symbolic-name>
   </properties>
   <build>
     <plugins>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <skip>true</skip>
         </configuration>
       </plugin>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-plugin-plugin</artifactId>
-        <version>2.9</version>
+        <version>3.4</version>
         <executions>
           <execution>
             <id>exec-plugin-doc</id>
             <phase>generate-sources</phase>
             <goals>
-              <goal>xdoc</goal>
+              <goal>descriptor</goal>
               <goal>helpmojo</goal>
             </goals>
           </execution>
diff --git a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java
index d7db6fb..482006e 100644
--- a/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java
+++ b/jetty-jspc-maven-plugin/src/main/java/org/eclipse/jetty/jspc/plugin/JspcMojo.java
@@ -25,55 +25,48 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.net.URI;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 import org.apache.jasper.JspC;
+import org.apache.jasper.servlet.JspCServletContext;
+import org.apache.jasper.servlet.TldScanner;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.project.MavenProject;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.util.scan.StandardJarScanner;
 import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.PatternMatcher;
 import org.eclipse.jetty.util.resource.Resource;
 
 /**
- * <p>
  * This goal will compile jsps for a webapp so that they can be included in a
  * war.
- * </p>
  * <p>
- * At runtime, the plugin will use the jsp2.0 jspc compiler if you are running
- * on a 1.4 or lower jvm. If you are using a 1.5 jvm, then the jsp2.1 compiler
- * will be selected. (this is the same behaviour as the <a
- * href="http://jetty.mortbay.org/maven-plugin">jetty plugin</a> for executing
- * webapps).
+ * At runtime, the plugin will use the jspc compiler to precompile jsps and tags.
  * </p>
  * <p>
  * Note that the same java compiler will be used as for on-the-fly compiled
  * jsps, which will be the Eclipse java compiler.
- * </p>
- * 
  * <p>
  * See <a
- * href="http://docs.codehaus.org/display/JETTY/Maven+Jetty+Jspc+Plugin">Usage
+ * href="https://www.eclipse.org/jetty/documentation/current/jetty-jspc-maven-plugin.html">Usage
  * Guide</a> for instructions on using this plugin.
  * </p>
- * 
- * @author janb
- * 
  * @goal jspc
  * @phase process-classes
- * @requiresDependencyResolution compile
+ * @requiresDependencyResolution compile+runtime
  * @description Runs jspc compiler to produce .java and .class files
  */
 public class JspcMojo extends AbstractMojo
@@ -87,13 +80,42 @@
      *
      * Add some extra setters to standard JspC class to help configure it
      * for running in maven.
+     * 
+     * TODO move all setters on the plugin onto this jspc class instead.
      */
     public static class JettyJspC extends JspC
     {
+   
+        private boolean scanAll;
+        
         public void setClassLoader (ClassLoader loader)
         {
             this.loader = loader;
         }
+        
+       public void setScanAllDirectories (boolean scanAll)
+       {
+           this.scanAll = scanAll;
+       }
+       
+       public boolean getScanAllDirectories ()
+       {
+           return this.scanAll;
+       }
+       
+
+        @Override
+        protected TldScanner newTldScanner(JspCServletContext context, boolean namespaceAware, boolean validate, boolean blockExternal)
+        {            
+            if (context != null && context.getAttribute(JarScanner.class.getName()) == null) 
+            {
+                StandardJarScanner jarScanner = new StandardJarScanner();             
+                jarScanner.setScanAllDirectories(getScanAllDirectories());
+                context.setAttribute(JarScanner.class.getName(), jarScanner);
+            }
+                
+            return super.newTldScanner(context, namespaceAware, validate, blockExternal);
+        }      
     }
     
     
@@ -110,7 +132,7 @@
      * The artifacts for the project.
      * 
      * @since jetty-7.6.3
-     * @parameter expression="${project.artifacts}"
+     * @parameter default-value="${project.artifacts}"
      * @readonly
      */
     private Set projectArtifacts;
@@ -119,7 +141,7 @@
     /**
      * The maven project.
      * 
-     * @parameter expression="${project}"
+     * @parameter default-value="${project}"
      * @required
      * @readonly
      */
@@ -130,7 +152,7 @@
     /**
      * The artifacts for the plugin itself.
      * 
-     * @parameter expression="${plugin.artifacts}"
+     * @parameter default-value="${plugin.artifacts}"
      * @readonly
      */
     private List pluginArtifacts;
@@ -215,7 +237,7 @@
     /**
      * The location of the compiled classes for the webapp
      * 
-     * @parameter expression="${project.build.outputDirectory}"
+     * @parameter default-value="${project.build.outputDirectory}"
      */
     private File classesDirectory;
 
@@ -229,6 +251,19 @@
     
     
     /**
+     * Source version - if not set defaults to jsp default (currently 1.7)
+     * @parameter 
+     */
+    private String sourceVersion;
+    
+    
+    /**
+     * Target version - if not set defaults to jsp default (currently 1.7)
+     * @parameter 
+     */
+    private String targetVersion;
+    
+    /**
      * 
      * The JspC instance being used to compile the jsps.
      * 
@@ -237,7 +272,14 @@
     private JettyJspC jspc;
 
 
-
+    /**
+     * Whether dirs on the classpath should be scanned as well as jars.
+     * True by default. This allows for scanning for tlds of dependent projects that
+     * are in the reactor as unassembled jars.
+     * 
+     * @parameter default-value=true
+     */
+    private boolean scanAllDirectories;
     
 
     public void execute() throws MojoExecutionException, MojoFailureException
@@ -251,7 +293,11 @@
             getLog().info("webXml="+webXml);
             getLog().info("insertionMarker="+ (insertionMarker == null || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker));
             getLog().info("keepSources=" + keepSources);
-            getLog().info("mergeFragment=" + mergeFragment);            
+            getLog().info("mergeFragment=" + mergeFragment);  
+            if (sourceVersion != null)
+                getLog().info("sourceVersion="+sourceVersion);
+            if (targetVersion != null)
+                getLog().info("targetVersion="+targetVersion);
         }
         try
         {
@@ -274,21 +320,17 @@
         List<URL> webAppUrls = setUpWebAppClassPath();
         
         //set up the classpath of the container (ie jetty and jsp jars)
-        String sysClassPath = setUpSysClassPath();
-        
-        //get the list of system classpath jars that contain tlds
-        List<URL> tldJarUrls = getSystemJarsWithTlds();
-        
-        for (URL u:tldJarUrls)
-        {
-            if (getLog().isDebugEnabled())
-                getLog().debug(" sys jar with tlds: "+u);
-            webAppUrls.add(u);
-        }
+        Set<URL> pluginJars = getPluginJars();
+        Set<URL> providedJars = getProvidedScopeJars(pluginJars);
+ 
 
+        //Make a classloader so provided jars will be on the classpath
+        List<URL> sysUrls = new ArrayList<URL>();      
+        sysUrls.addAll(providedJars);     
+        URLClassLoader sysClassLoader = new URLClassLoader((URL[])sysUrls.toArray(new URL[0]), currentClassLoader);
       
-        //use the classpaths as the classloader
-        URLClassLoader webAppClassLoader = new URLClassLoader((URL[]) webAppUrls.toArray(new URL[0]), currentClassLoader);
+        //make a classloader with the webapp classpath
+        URLClassLoader webAppClassLoader = new URLClassLoader((URL[]) webAppUrls.toArray(new URL[0]), sysClassLoader);
         StringBuffer webAppClassPath = new StringBuffer();
 
         for (int i = 0; i < webAppUrls.size(); i++)
@@ -311,26 +353,40 @@
         if (jspc == null)
             jspc = new JettyJspC();
         
+
         jspc.setWebXmlFragment(webXmlFragment);
         jspc.setUriroot(webAppSourceDirectory);     
         jspc.setOutputDir(generatedClasses);
-        jspc.setClassPath(sysClassPath+System.getProperty("path.separator")+webAppClassPath.toString());
         jspc.setClassLoader(fakeWebAppClassLoader);
+        jspc.setScanAllDirectories(scanAllDirectories);
         jspc.setCompile(true);
+        if (sourceVersion != null)
+            jspc.setCompilerSourceVM(sourceVersion);
+        if (targetVersion != null)
+            jspc.setCompilerTargetVM(targetVersion);
 
         // JspC#setExtensions() does not exist, so 
         // always set concrete list of files that will be processed.
         String jspFiles = getJspFiles(webAppSourceDirectory);
-        getLog().info("Compiling "+jspFiles);
-        getLog().info("Includes="+includes);
-        getLog().info("Excludes="+excludes);
-        jspc.setJspFiles(jspFiles);
+       
+        try
+        {
+            if (jspFiles == null | jspFiles.equals(""))
+            {
+                getLog().info("No files selected to precompile");
+            }
+            else
+            {
+                getLog().info("Compiling "+jspFiles+" from includes="+includes+" excludes="+excludes);
+                jspc.setJspFiles(jspFiles);
+                jspc.execute();
+            }
+        }
+        finally
+        {
 
-        getLog().info("Files selected to precompile: " + jspFiles);
-
-        jspc.execute();
-
-        Thread.currentThread().setContextClassLoader(currentClassLoader);
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+        }
     }
 
     private String getJspFiles(String webAppSourceDirectory)
@@ -345,7 +401,7 @@
      * Until Jasper supports the option to generate the srcs in a different dir
      * than the classes, this is the best we can do.
      * 
-     * @throws Exception
+     * @throws Exception if unable to clean srcs
      */
     public void cleanupSrcs() throws Exception
     {
@@ -391,7 +447,7 @@
      * If you dont specify the insertionMarker, then the fragment will be
      * inserted at the end of the file just before the &lt;/webapp&gt;
      * 
-     * @throws Exception
+     * @throws Exception if unable to merge the web xml
      */
     public void mergeWebXml() throws Exception
     {
@@ -406,58 +462,63 @@
                 return;
             }
 
-            File fragmentWebXml = new File(webXmlFragment);
-            if (!fragmentWebXml.exists())
+            File fragmentWebXml = new File(webXmlFragment);         
+            File mergedWebXml = new File(fragmentWebXml.getParentFile(), "web.xml");
+
+            try (BufferedReader webXmlReader = new BufferedReader(new FileReader(webXml));
+                 PrintWriter mergedWebXmlWriter = new PrintWriter(new FileWriter(mergedWebXml))) 
             {
-                getLog().info("No fragment web.xml file generated");
-            }
-            File mergedWebXml = new File(fragmentWebXml.getParentFile(),
-            "web.xml");
-            try (BufferedReader webXmlReader = new BufferedReader(new FileReader(
-                    webXml));
-                 PrintWriter mergedWebXmlWriter = new PrintWriter(new FileWriter(
-                    mergedWebXml))) {
 
-                // read up to the insertion marker or the </webapp> if there is no
-                // marker
-                boolean atInsertPoint = false;
-                boolean atEOF = false;
-                String marker = (insertionMarker == null
-                        || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker);
-                while (!atInsertPoint && !atEOF)
+                if (!fragmentWebXml.exists())
                 {
-                    String line = webXmlReader.readLine();
-                    if (line == null)
-                        atEOF = true;
-                    else if (line.indexOf(marker) >= 0)
-                    {
-                        atInsertPoint = true;
-                    }
-                    else
-                    {
-                        mergedWebXmlWriter.println(line);
-                    }
-                }
-                
-                if (atEOF && !atInsertPoint)
-                    throw new IllegalStateException("web.xml does not contain insertionMarker "+insertionMarker);
-                
-                //put in a context init-param to flag that the contents have been precompiled
-                mergedWebXmlWriter.println("<context-param><param-name>"+PRECOMPILED_FLAG+"</param-name><param-value>true</param-value></context-param>");
-                
-
-                // put in the generated fragment
-                try (BufferedReader fragmentWebXmlReader = new BufferedReader(
-                        new FileReader(fragmentWebXml))) {
-                    IO.copy(fragmentWebXmlReader, mergedWebXmlWriter);
-
-                    // if we inserted just before the </web-app>, put it back in
-                    if (marker.equals(END_OF_WEBAPP))
-                        mergedWebXmlWriter.println(END_OF_WEBAPP);
-
-                    // copy in the rest of the original web.xml file
+                    getLog().info("No fragment web.xml file generated");
+                    //just copy existing web.xml to expected position
                     IO.copy(webXmlReader, mergedWebXmlWriter);
                 }
+                else
+                {
+                    // read up to the insertion marker or the </webapp> if there is no
+                    // marker
+                    boolean atInsertPoint = false;
+                    boolean atEOF = false;
+                    String marker = (insertionMarker == null
+                            || insertionMarker.equals("") ? END_OF_WEBAPP : insertionMarker);
+                    while (!atInsertPoint && !atEOF)
+                    {
+                        String line = webXmlReader.readLine();
+                        if (line == null)
+                            atEOF = true;
+                        else if (line.indexOf(marker) >= 0)
+                        {
+                            atInsertPoint = true;
+                        }
+                        else
+                        {
+                            mergedWebXmlWriter.println(line);
+                        }
+                    }
+
+                    if (atEOF && !atInsertPoint)
+                        throw new IllegalStateException("web.xml does not contain insertionMarker "+insertionMarker);
+
+                    //put in a context init-param to flag that the contents have been precompiled
+                    mergedWebXmlWriter.println("<context-param><param-name>"+PRECOMPILED_FLAG+"</param-name><param-value>true</param-value></context-param>");
+
+
+                    // put in the generated fragment
+                    try (BufferedReader fragmentWebXmlReader = 
+                            new BufferedReader(new FileReader(fragmentWebXml))) 
+                    {
+                        IO.copy(fragmentWebXmlReader, mergedWebXmlWriter);
+
+                        // if we inserted just before the </web-app>, put it back in
+                        if (marker.equals(END_OF_WEBAPP))
+                            mergedWebXmlWriter.println(END_OF_WEBAPP);
+
+                        // copy in the rest of the original web.xml file
+                        IO.copy(webXmlReader, mergedWebXmlWriter);
+                    }
+                }
             }
         }
     }
@@ -510,87 +571,63 @@
     }
     
     
-    private String setUpSysClassPath () throws Exception
+    
+    /**
+     * @return
+     * @throws MalformedURLException
+     */
+    private Set<URL> getPluginJars () throws MalformedURLException
     {
-        StringBuffer buff = new StringBuffer();
-        
-        //Put each of the plugin's artifacts onto the system classpath for jspc
+        HashSet<URL> pluginJars = new HashSet<>();
         for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext(); )
         {
             Artifact pluginArtifact = iter.next();
             if ("jar".equalsIgnoreCase(pluginArtifact.getType()))
             {
                 if (getLog().isDebugEnabled()) { getLog().debug("Adding plugin artifact "+pluginArtifact);}
-                buff.append(pluginArtifact.getFile().getAbsolutePath());
-                if (iter.hasNext())
-                    buff.append(File.pathSeparator);
+                pluginJars.add(pluginArtifact.getFile().toURI().toURL());
             }
         }
         
+        return pluginJars;
+    }
+    
+    
+    
+    /**
+     * @param pluginJars
+     * @return
+     * @throws MalformedURLException
+     */
+    private Set<URL>  getProvidedScopeJars (Set<URL> pluginJars) throws MalformedURLException
+    {
+        if (!useProvidedScope)
+            return Collections.emptySet();
         
-        if (useProvidedScope)
-        {
-            for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
-            {                   
-                Artifact artifact = iter.next();
-                if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
+        HashSet<URL> providedJars = new HashSet<>();
+        
+        for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
+        {                   
+            Artifact artifact = iter.next();
+            if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
+            {
+                //test to see if the provided artifact was amongst the plugin artifacts
+                URL jar = artifact.getFile().toURI().toURL();
+                if (!pluginJars.contains(jar))
                 {
-                    //test to see if the provided artifact was amongst the plugin artifacts
-                    String path = artifact.getFile().getAbsolutePath();
-                    if (! buff.toString().contains(path))
-                    {
-                        if (buff.length() != 0)
-                            buff.append(File.pathSeparator);
-                        buff.append(path);
-                        if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
-                    }  
-                    else
-                    {
-                        if (getLog().isDebugEnabled()) { getLog().debug("Skipping provided artifact: "+artifact);}
-                    }
+                    providedJars.add(jar);
+                    if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);}
+                }  
+                else
+                {
+                    if (getLog().isDebugEnabled()) { getLog().debug("Skipping provided artifact: "+artifact);}
                 }
             }
         }
-
-        return buff.toString();
+        return providedJars;
     }
 
     
-    /**
-     * Glassfish jsp requires that we set up the list of system jars that have
-     * tlds in them.
-     * 
-     * This method is a little fragile, as it relies on knowing that the jstl jars
-     * are the only ones in the system path that contain tlds.
-     * @return
-     * @throws Exception
-     */
-    private List<URL> getSystemJarsWithTlds() throws Exception
-    {
-        getLog().debug("tld pattern=" + tldJarNamePatterns);   
-        final List<URL> list = new ArrayList<URL>();
-        List<URI> artifactUris = new ArrayList<URI>();
-        Pattern pattern = Pattern.compile(tldJarNamePatterns);
-        for (Iterator<Artifact> iter = pluginArtifacts.iterator(); iter.hasNext(); )
-        {
-            Artifact pluginArtifact = iter.next();
-            Resource res = Resource.newResource(pluginArtifact.getFile());
-            getLog().debug("scan jar: "+res.getURI());
-            artifactUris.add(res.getURI());
-        }
-        
-        PatternMatcher matcher = new PatternMatcher()
-        {
-            public void matched(URI uri) throws Exception
-            {
-                //uri of system artifact matches pattern defining list of jars known to contain tlds
-                list.add(uri.toURL());
-            }
-        };
-        matcher.match(pattern, artifactUris.toArray(new URI[artifactUris.size()]), false);
-        
-        return list;
-    }
     
     private File getWebXmlFile ()
     throws IOException
diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml
index 2f7b5b9..eeee9a0 100644
--- a/jetty-maven-plugin/pom.xml
+++ b/jetty-maven-plugin/pom.xml
@@ -2,15 +2,17 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-maven-plugin</artifactId>
   <packaging>maven-plugin</packaging>
   <name>Jetty :: Jetty Maven Plugin</name>
+  <description>Jetty maven plugins</description>
   <properties>
     <mavenVersion>3.0.3</mavenVersion>
-    <pluginToolsVersion>3.1</pluginToolsVersion>
+    <pluginToolsVersion>3.4</pluginToolsVersion>
+    <bundle-symbolic-name>${project.groupId}.maven.plugin</bundle-symbolic-name>
   </properties>
   <build>
     <plugins>
@@ -29,7 +31,6 @@
             <id>exec-plugin-doc</id>
             <phase>generate-sources</phase>
             <goals>
-              <goal>xdoc</goal>
               <goal>helpmojo</goal>
             </goals>
           </execution>
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
index d07065d..c098f4a 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java
@@ -18,7 +18,6 @@
 
 package org.eclipse.jetty.maven.plugin;
 
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
@@ -40,35 +39,23 @@
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.util.FileUtils;
 import org.eclipse.jetty.security.LoginService;
-import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.RequestLog;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ShutdownMonitor;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.PathWatcher;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
-
-
 /**
- * AbstractJettyMojo
- *
  * Common base class for most jetty mojos.
- * 
- * 
  */
 public abstract class AbstractJettyMojo extends AbstractMojo
 {
     /**
-     * 
-     */
-    public String PORT_SYSPROPERTY = "jetty.port";
-    
-    
-    /**
      * Whether or not to include dependencies on the plugin's classpath with &lt;scope&gt;provided&lt;/scope&gt;
      * Use WITH CAUTION as you may wind up with duplicate jars/classes.
      * 
@@ -77,7 +64,6 @@
      */
     protected boolean useProvidedScope;
     
-    
     /**
      * List of goals that are NOT to be used
      * 
@@ -86,9 +72,6 @@
      */
     protected String[] excludedGoals;
     
-
-  
-    
     /**
      * List of other contexts to set up. Consider using instead
      * the &lt;jettyXml&gt; element to specify external jetty xml config file. 
@@ -99,7 +82,6 @@
      */
     protected ContextHandler[] contextHandlers;
     
-    
     /**
      * List of security realms to set up. Consider using instead
      * the &lt;jettyXml&gt; element to specify external jetty xml config file. 
@@ -109,7 +91,6 @@
      * @parameter
      */
     protected LoginService[] loginServices;
-    
 
     /**
      * A RequestLog implementation to use for the webapp at runtime.
@@ -121,7 +102,6 @@
      */
     protected RequestLog requestLog;
     
-    
     /**
      * An instance of org.eclipse.jetty.webapp.WebAppContext that represents the webapp.
      * Use any of its setters to configure the webapp. This is the preferred and most
@@ -132,25 +112,23 @@
      */
     protected JettyWebAppContext webApp;
 
-
     /**
      * The interval in seconds to scan the webapp for changes 
      * and restart the context if necessary. Ignored if reload
      * is enabled. Disabled by default.
      * 
-     * @parameter expression="${jetty.scanIntervalSeconds}" default-value="0"
+     * @parameter property="jetty.scanIntervalSeconds" default-value="0"
      * @required
      */
     protected int scanIntervalSeconds;
     
-    
     /**
      * reload can be set to either 'automatic' or 'manual'
      *
      * if 'manual' then the context can be reloaded by a linefeed in the console
      * if 'automatic' then traditional reloading on changed files is enabled.
      * 
-     * @parameter expression="${jetty.reload}" default-value="automatic"
+     * @parameter property="jetty.reload" default-value="automatic"
      */
     protected String reload;
 
@@ -162,7 +140,7 @@
      * that have been set on the command line, by the JVM, or directly 
      * in the POM via systemProperties. Optional.
      * 
-     * @parameter expression="${jetty.systemPropertiesFile}"
+     * @parameter property="jetty.systemPropertiesFile"
      */
     protected File systemPropertiesFile;
 
@@ -208,17 +186,15 @@
     /**
      * Use the dump() facility of jetty to print out the server configuration to logging
      * 
-     * @parameter expression"${dumponStart}" default-value="false"
+     * @parameter property="dumponStart" default-value="false"
      */
     protected boolean dumpOnStart;
     
-   
-    
     
     /**  
      * Skip this mojo execution.
      * 
-     * @parameter expression="${jetty.skip}" default-value="false"
+     * @parameter property="jetty.skip" default-value="false"
      */
     protected boolean skip;
 
@@ -236,7 +212,7 @@
     /**
      * The maven project.
      *
-     * @parameter expression="${project}"
+     * @parameter default-value="${project}"
      * @readonly
      */
     protected MavenProject project;
@@ -245,14 +221,14 @@
     /**
      * The artifacts for the project.
      * 
-     * @parameter expression="${project.artifacts}"
+     * @parameter default-value="${project.artifacts}"
      * @readonly
      */
     protected Set projectArtifacts;
     
     
     /** 
-     * @parameter expression="${mojoExecution}" 
+     * @parameter default-value="${mojoExecution}" 
      * @readonly
      */
     protected org.apache.maven.plugin.MojoExecution execution;
@@ -261,7 +237,7 @@
     /**
      * The artifacts for the plugin itself.
      * 
-     * @parameter expression="${plugin.artifacts}"
+     * @parameter default-value="${plugin.artifacts}"
      * @readonly
      */
     protected List pluginArtifacts;
@@ -278,33 +254,27 @@
     
     /**
      * A wrapper for the Server object
+     * @parameter
      */
-    protected JettyServer server = new JettyServer();
+    protected Server server;
     
     
     /**
      * A scanner to check for changes to the webapp
      */
-    protected Scanner scanner;
+    protected PathWatcher scanner;
     
     
-    /**
-     *  List of files and directories to scan
-     */
-    protected ArrayList<File> scanList;
-    
-    
-    /**
-     * List of Listeners for the scanner
-     */
-    protected ArrayList<Scanner.BulkListener> scannerListeners;
-    
     
     /**
      * A scanner to check ENTER hits on the console
      */
     protected Thread consoleScanner;
     
+    protected ServerSupport serverSupport;
+    
+    
+    
     
     /**
      * <p>
@@ -361,9 +331,6 @@
     
     
     
-    /**
-     * @throws MojoExecutionException
-     */
     public void configurePluginClasspath() throws MojoExecutionException
     {  
         //if we are configured to include the provided dependencies on the plugin's classpath
@@ -403,13 +370,6 @@
         }
     }
     
-    
-    
-    
-    /**
-     * @param artifact
-     * @return
-     */
     public boolean isPluginArtifact(Artifact artifact)
     {
         if (pluginArtifacts == null || pluginArtifacts.isEmpty())
@@ -427,12 +387,6 @@
         return isPluginArtifact;
     }
 
-    
-    
-    
-    /**
-     * @throws Exception
-     */
     public void finishConfigurationBeforeStart() throws Exception
     {
         HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
@@ -445,31 +399,24 @@
         }
     }
 
-   
-   
-
-    /**
-     * @throws Exception
-     */
     public void applyJettyXml() throws Exception
-    {
-        if (getJettyXmlFiles() == null)
-            return;
-
-        this.server.applyXmlConfigurations(getJettyXmlFiles());
+    {        
+        Server tmp = ServerSupport.applyXmlConfigurations(server, getJettyXmlFiles());
+        if (server == null)
+            server = tmp;
+        
+        if (server == null)
+            server = new Server();
     }
 
-
-
-    
-    /**
-     * @throws MojoExecutionException
-     */
     public void startJetty () throws MojoExecutionException
     {
         try
         {
             getLog().debug("Starting Jetty Server ...");
+            
+            //make sure Jetty does not use URLConnection caches with the plugin
+            Resource.setDefaultUseCaches(false);
          
             configureMonitor();
             
@@ -478,54 +425,32 @@
             //apply any config from a jetty.xml file first which is able to
             //be overwritten by config in the pom.xml
             applyJettyXml ();      
-
+            
             // if a <httpConnector> was specified in the pom, use it
             if (httpConnector != null)
             {
                 // check that its port was set
                 if (httpConnector.getPort() <= 0)
                 {
-                    //use any jetty.port settings provided
-                    String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR); 
+                    //use any jetty.http.port settings provided
+                    String tmp = System.getProperty(MavenServerConnector.PORT_SYSPROPERTY, System.getProperty("jetty.port", MavenServerConnector.DEFAULT_PORT_STR));
                     httpConnector.setPort(Integer.parseInt(tmp.trim()));
                 }  
-                if (httpConnector.getServer() == null)
-                    httpConnector.setServer(this.server);
-                this.server.addConnector(httpConnector);
+                httpConnector.setServer(server);
             }
 
-            // if the user hasn't configured the connectors in a jetty.xml file so use a default one
-            Connector[] connectors = this.server.getConnectors();
-            if (connectors == null|| connectors.length == 0)
-            {
-                //if <httpConnector> not configured in the pom, create one
-                if (httpConnector == null)
-                {
-                    httpConnector = new MavenServerConnector();               
-                    //use any jetty.port settings provided
-                    String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR);
-                    httpConnector.setPort(Integer.parseInt(tmp.trim()));
-                }
-                if (httpConnector.getServer() == null)
-                    httpConnector.setServer(this.server);
-                this.server.setConnectors(new Connector[] {httpConnector});
-            }
+            ServerSupport.configureConnectors(server, httpConnector);
 
-            //set up a RequestLog if one is provided
-            if (this.requestLog != null)
-                this.server.setRequestLog(this.requestLog);
-
-            //set up the webapp and any context provided
-            this.server.configureHandlers();
+            //set up a RequestLog if one is provided and the handle structure
+            ServerSupport.configureHandlers(server, this.requestLog);
+            
+            //Set up list of default Configurations to apply to a webapp
+            ServerSupport.configureDefaultConfigurationClasses(server);
             configureWebApplication();
-            this.server.addWebApplication(webApp);
+            ServerSupport.addWebApplication(server, webApp);
 
             // set up security realms
-            for (int i = 0; (this.loginServices != null) && i < this.loginServices.length; i++)
-            {
-                getLog().debug(this.loginServices[i].getClass().getName() + ": "+ this.loginServices[i].toString());
-                this.server.addBean(this.loginServices[i]);
-            }
+            ServerSupport.configureLoginServices(server, loginServices);
 
             //do any other configuration required by the
             //particular Jetty version
@@ -535,17 +460,20 @@
             this.server.start();
 
             getLog().info("Started Jetty Server");
-           
-            
+
             if ( dumpOnStart )
             {
                 getLog().info(this.server.dump());
             }
-            
+
             // start the scanner thread (if necessary) on the main webapp
-            configureScanner ();
-            startScanner();
-            
+            if (isScanningEnabled())
+            {
+                scanner = new PathWatcher();
+                configureScanner ();
+                startScanner();
+            }
+
             // start the new line scanner thread if necessary
             startConsoleScanner();
 
@@ -581,11 +509,15 @@
     }
 
     
+    
+    
+    
+    
     /**
      * Subclasses should invoke this to setup basic info
      * on the webapp
      * 
-     * @throws MojoExecutionException
+     * @throws Exception if unable to configure web application 
      */
     public void configureWebApplication () throws Exception
     {
@@ -635,39 +567,40 @@
      * Run a scanner thread on the given list of files and directories, calling
      * stop/start on the given list of LifeCycle objects if any of the watched
      * files change.
-     *
+     * @throws Exception if unable to start scanner 
      */
-    private void startScanner() throws Exception
+    public void startScanner() throws Exception
     {
-        // check if scanning is enabled
-        if (scanIntervalSeconds <= 0) return;
-
-        // check if reload is manual. It disables file scanning
-        if ( "manual".equalsIgnoreCase( reload ) )
-        {
-            // issue a warning if both scanIntervalSeconds and reload
-            // are enabled
-            getLog().warn("scanIntervalSeconds is set to " + scanIntervalSeconds + " but will be IGNORED due to manual reloading");
+        if (!isScanningEnabled())
             return;
-        }
 
-        scanner = new Scanner();
-        scanner.setReportExistingFilesOnStartup(false);
-        scanner.setScanInterval(scanIntervalSeconds);
-        scanner.setScanDirs(scanList);
-        scanner.setRecursive(true);
-        Iterator itor = (this.scannerListeners==null?null:this.scannerListeners.iterator());
-        while (itor!=null && itor.hasNext())
-            scanner.addListener((Scanner.Listener)itor.next());
-        getLog().info("Starting scanner at interval of " + scanIntervalSeconds + " seconds.");
+        scanner.setNotifyExistingOnStart(false);
+       
+       
         scanner.start();
     }
     
     
+    public boolean isScanningEnabled ()
+    {
+        if (scanIntervalSeconds <=0 || "manual".equalsIgnoreCase( reload ))
+            return false;
+        return true;
+    }
+    
+    public void stopScanner() throws Exception
+    {
+        if (!isScanningEnabled())
+            return;
+        
+        if (scanner != null)
+            scanner.stop();
+    }
     
     
     /**
      * Run a thread that monitors the console input to detect ENTER hits.
+     * @throws Exception if unable to start the console
      */
     protected void startConsoleScanner() throws Exception
     {
@@ -679,12 +612,6 @@
         }       
     }
 
-    
-    
-    
-    /**
-     * 
-     */
     protected void printSystemProperties ()
     {
         // print out which system properties were set up
@@ -702,13 +629,10 @@
         }
     }
 
-    
-    
-    
     /**
      * Try and find a jetty-web.xml file, using some
      * historical naming conventions if necessary.
-     * @param webInfDir
+     * @param webInfDir the web inf directory
      * @return the jetty web xml file
      */
     public File findJettyWebXmlFile (File webInfDir)
@@ -730,13 +654,6 @@
         return null;
     }
 
-
-   
-    
-    /**
-     * @param file
-     * @throws Exception
-     */
     public void setSystemPropertiesFile(File file) throws Exception
     {
         this.systemPropertiesFile = file;
@@ -762,12 +679,6 @@
         } 
     }
     
-    
-    
-    
-    /**
-     * @param systemProperties
-     */
     public void setSystemProperties(SystemProperties systemProperties)
     {
         if (this.systemProperties == null)
@@ -781,15 +692,6 @@
         }
     }
     
-
-    
-
-    
-    
-    
-    /**
-     * @return
-     */
     public List<File> getJettyXmlFiles()
     {
         if ( this.jettyXml == null )
@@ -816,12 +718,6 @@
         return jettyXmlFiles;
     }
 
-    
-    
-    /**
-     * @param goal
-     * @return
-     */
     public boolean isExcluded (String goal)
     {
         if (excludedGoals == null || goal == null)
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java
index b18abac..6314e64 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ConsoleScanner.java
@@ -20,9 +20,6 @@
 
 import java.io.IOException;
 
-
-
-
 /**
  * ConsoleScanner
  *
@@ -30,16 +27,8 @@
  */
 public class ConsoleScanner extends Thread 
 {
-    
     private final AbstractJettyMojo mojo;
     
-    
-    
-    
-    
-    /**
-     * @param mojo
-     */
     public ConsoleScanner(AbstractJettyMojo mojo) 
     {
         this.mojo = mojo;
@@ -47,12 +36,6 @@
         setDaemon(true);
     }
     
-    
-    
-    
-    /** 
-     * @see java.lang.Thread#run()
-     */
     public void run() 
     {  
         try 
@@ -69,12 +52,6 @@
         }
     }
     
-    
-    
-    
-    /**
-     * 
-     */
     private void getSomeSleep() 
     {
         try 
@@ -87,12 +64,6 @@
         }
     }
     
-    
-    
-    
-    /**
-     * @throws IOException
-     */
     private void checkSystemInput() throws IOException 
     {     
         while (System.in.available() > 0) {
@@ -107,9 +78,6 @@
         }
     }
     
-    
-    
-    
     /**
      * Skip buffered bytes of system console.
      */
@@ -136,12 +104,6 @@
         }      
     }
     
-    
-    
-    
-    /**
-     * 
-     */
     private void restartWebApp()
     {
         try
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java
index e06b7d3..befd8ab 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java
@@ -18,8 +18,6 @@
 

 package org.eclipse.jetty.maven.plugin;

 

-import java.io.File;

-

 import org.apache.maven.plugin.MojoExecutionException;

 import org.apache.maven.plugin.MojoFailureException;

 

@@ -74,8 +72,7 @@
     {

         super.finishConfigurationBeforeStart();

         //only stop the server at shutdown if we are blocking

-        server.setStopAtShutdown(!nonblocking);

-       

+        server.setStopAtShutdown(!nonblocking); 

     }

 

 }

diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java
index 77c343d..181b40b 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEffectiveWebXml.java
@@ -42,7 +42,7 @@
     /**
      * The target directory
      * 
-     * @parameter expression="${project.build.directory}"
+     * @parameter default-value="${project.build.directory}"
      * @required
      * @readonly
      */
@@ -73,16 +73,7 @@
     {
         //Only do enough setup to be able to produce a quickstart-web.xml file 
         
-        //if the user didn't nominate a file to generate into, pick the name and
-        //make sure that it is deleted on exit
-        if (effectiveWebXml == null)
-        {
-            deleteOnExit = true;
-            effectiveWebXml = new File(target, "effective-web.xml");
-            effectiveWebXml.deleteOnExit();
-        }
-        
-        Resource descriptor = Resource.newResource(effectiveWebXml);
+
         
         QueuedThreadPool tpool = null;
         
@@ -93,9 +84,8 @@
             //apply any config from a jetty.xml file first to our "fake" server instance
             //TODO probably not necessary
             applyJettyXml ();  
-
         
-            server.configureHandlers();
+            ServerSupport.configureHandlers(server, null);
                    
             //ensure config of the webapp based on settings in plugin
             configureWebApplication();
@@ -105,15 +95,29 @@
             webApp.setCopyWebDir(false);
             webApp.setCopyWebInf(false);
             webApp.setGenerateQuickStart(true);
-    
-            if (!effectiveWebXml.getParentFile().exists())
-                effectiveWebXml.getParentFile().mkdirs();
-            if (!effectiveWebXml.exists())
-                effectiveWebXml.createNewFile();
+
+            //if the user didn't nominate a file to generate into, pick the name and
+            //make sure that it is deleted on exit
+            if (webApp.getQuickStartWebDescriptor() == null)
+            {
+                if (effectiveWebXml == null)
+                {
+                    deleteOnExit = true;
+                    effectiveWebXml = new File(target, "effective-web.xml");
+                    effectiveWebXml.deleteOnExit();
+                }
+
+                Resource descriptor = Resource.newResource(effectiveWebXml);
+
+                if (!effectiveWebXml.getParentFile().exists())
+                    effectiveWebXml.getParentFile().mkdirs();
+                if (!effectiveWebXml.exists())
+                    effectiveWebXml.createNewFile();
+
+                webApp.setQuickStartWebDescriptor(descriptor);
+            }
             
-            webApp.setQuickStartWebDescriptor(descriptor);
-            
-            server.addWebApplication(webApp);
+            ServerSupport.addWebApplication(server, webApp);
                        
             //if our server has a thread pool associated we can do any annotation scanning multithreaded,
             //otherwise scanning will be single threaded
@@ -143,7 +147,7 @@
             try
             {
                 //just show the result in the log
-                getLog().info(IO.toString(descriptor.getInputStream()));
+                getLog().info(IO.toString(webApp.getQuickStartWebDescriptor().getInputStream()));
             }
             catch (IOException e)
             {
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java
index 0c73cc6..76e4291 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunForkedMojo.java
@@ -45,7 +45,7 @@
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.eclipse.jetty.annotations.AnnotationConfiguration;
-import org.eclipse.jetty.quickstart.QuickStartDescriptorGenerator;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceCollection;
@@ -53,25 +53,20 @@
 
 
 /**
+ * This goal is used to deploy your unassembled webapp into a forked JVM.
  * <p>
- *  This goal is used to deploy your unassembled webapp into a forked JVM.
- *  </p>
- *  <p>
- *  You need to define a jetty.xml file to configure connectors etc. You can use the normal setters of o.e.j.webapp.WebAppContext on the <b>webApp</b>
- *  configuration element for this plugin. You may also need context xml file for any particularly complex webapp setup.
- *  about your webapp.
- *  </p>
- *  <p>
- *  Unlike the other jetty goals, this does NOT support the <b>scanIntervalSeconds</b> parameter: the webapp will be deployed only once.
- *  </p>
- *  <p>
- *  The <b>stopKey</b>, <b>stopPort</b> configuration elements can be used to control the stopping of the forked process. By default, this plugin will launch
- *  the forked jetty instance and wait for it to complete (in which case it acts much like the <b>jetty:run</b> goal, and you will need to Cntrl-C to stop).
- *  By setting the configuration element <b>waitForChild</b> to <b>false</b>, the plugin will terminate after having forked the jetty process. In this case
- *  you can use the <b>jetty:stop</b> goal to terminate the process.
- *  <p>
- *  See <a href="http://www.eclipse.org/jetty/documentation/">http://www.eclipse.org/jetty/documentation</a> for more information on this and other jetty plugins.
- *  </p>
+ * You need to define a jetty.xml file to configure connectors etc. You can use the normal setters of o.e.j.webapp.WebAppContext on the <b>webApp</b>
+ * configuration element for this plugin. You may also need context xml file for any particularly complex webapp setup.
+ * about your webapp.
+ * <p>
+ * Unlike the other jetty goals, this does NOT support the <b>scanIntervalSeconds</b> parameter: the webapp will be deployed only once.
+ * <p>
+ * The <b>stopKey</b>, <b>stopPort</b> configuration elements can be used to control the stopping of the forked process. By default, this plugin will launch
+ * the forked jetty instance and wait for it to complete (in which case it acts much like the <b>jetty:run</b> goal, and you will need to Cntrl-C to stop).
+ * By setting the configuration element <b>waitForChild</b> to <b>false</b>, the plugin will terminate after having forked the jetty process. In this case
+ * you can use the <b>jetty:stop</b> goal to terminate the process.
+ * <p>
+ * See <a href="http://www.eclipse.org/jetty/documentation/">http://www.eclipse.org/jetty/documentation</a> for more information on this and other jetty plugins.
  * 
  * @goal run-forked
  * @requiresDependencyResolution test
@@ -81,21 +76,10 @@
  */
 public class JettyRunForkedMojo extends JettyRunMojo
 {    
-    public static final String DEFAULT_WEBAPP_SRC = "src"+File.separator+"main"+File.separator+"webapp";
-    public static final String FAKE_WEBAPP = "webapp-tmp";
-    
-    
-    public String PORT_SYSPROPERTY = "jetty.port";
-
-    
- 
-    
-    
-    
     /**
      * The target directory
      * 
-     * @parameter expression="${project.build.directory}"
+     * @parameter default-value="${project.build.directory}"
      * @required
      * @readonly
      */
@@ -104,34 +88,34 @@
     /**
      * The file into which to generate the quickstart web xml for the forked process to use
      * 
-     * @parameter expression="${project.build.directory}/fork-web.xml"
+     * @parameter default-value="${project.build.directory}/fork-web.xml"
      */
     protected File forkWebXml;
     
     
     /**
      * Arbitrary jvm args to pass to the forked process
-     * @parameter expression="${jetty.jvmArgs}"
+     * @parameter property="jetty.jvmArgs"
      */
     private String jvmArgs;
     
     
     /**
-     * @parameter expression="${plugin.artifacts}"
+     * @parameter default-value="${plugin.artifacts}"
      * @readonly
      */
     private List pluginArtifacts;
     
     
     /**
-     * @parameter expression="${plugin}"
+     * @parameter default-value="${plugin}"
      * @readonly
      */
     private PluginDescriptor plugin;
     
     
     /**
-     * @parameter expression="true" default-value="true"
+     * @parameter default-value="true"
      */
     private boolean waitForChild;
 
@@ -249,42 +233,49 @@
     {
         //Only do enough setup to be able to produce a quickstart-web.xml file to
         //pass onto the forked process to run     
-        
-        if (forkWebXml == null)
-            forkWebXml = new File (target, "fork-web.xml");
-        
+
         try
         {
             printSystemProperties();
 
             //do NOT apply the jettyXml configuration - as the jvmArgs may be needed for it to work 
+            if (server == null)
+                server = new Server();
 
             //ensure handler structure enabled
-            server.configureHandlers();
+            ServerSupport.configureHandlers(server, null);
+            
+            ServerSupport.configureDefaultConfigurationClasses(server);
                    
             //ensure config of the webapp based on settings in plugin
             configureWebApplication();
             
             //copy the base resource as configured by the plugin
             originalBaseResource = webApp.getBaseResource();
-            
+
             //get the original persistance setting
             originalPersistTemp = webApp.isPersistTempDirectory();
-            
+
             //set the webapp up to do very little other than generate the quickstart-web.xml
             webApp.setCopyWebDir(false);
             webApp.setCopyWebInf(false);
             webApp.setGenerateQuickStart(true);
-         
-            if (!forkWebXml.getParentFile().exists())
-                forkWebXml.getParentFile().mkdirs();
-            if (!forkWebXml.exists())
-                forkWebXml.createNewFile();
-            
-            webApp.setQuickStartWebDescriptor(Resource.newResource(forkWebXml));
+
+            if (webApp.getQuickStartWebDescriptor() == null)
+            {
+                if (forkWebXml == null)
+                    forkWebXml = new File (target, "fork-web.xml");
+
+                if (!forkWebXml.getParentFile().exists())
+                    forkWebXml.getParentFile().mkdirs();
+                if (!forkWebXml.exists())
+                    forkWebXml.createNewFile();
+
+                webApp.setQuickStartWebDescriptor(Resource.newResource(forkWebXml));
+            }
             
             //add webapp to our fake server instance
-            server.addWebApplication(webApp);
+            ServerSupport.addWebApplication(server, webApp);
                        
             //if our server has a thread pool associated we can do annotation scanning multithreaded,
             //otherwise scanning will be single threaded
@@ -431,13 +422,6 @@
         }
     }
 
-
-
-
-    /**
-     * @return
-     * @throws MojoExecutionException
-     */
     public List<String> getProvidedJars() throws MojoExecutionException
     {  
         //if we are configured to include the provided dependencies on the plugin's classpath
@@ -464,13 +448,6 @@
             return null;
     }
     
-   
-    
-    
-    /**
-     * @return
-     * @throws MojoExecutionException
-     */
     public File prepareConfiguration() throws MojoExecutionException
     {
         try
@@ -610,15 +587,6 @@
         return warArtifacts;
     }
     
-    
-    
-    
-    
-    
-    /**
-     * @param artifact
-     * @return
-     */
     public boolean isPluginArtifact(Artifact artifact)
     {
         if (pluginArtifacts == null || pluginArtifacts.isEmpty())
@@ -636,13 +604,6 @@
         return isPluginArtifact;
     }
     
-    
-    
-    
-    /**
-     * @return
-     * @throws Exception
-     */
     private Set<Artifact> getExtraJars()
     throws Exception
     {
@@ -668,15 +629,6 @@
         return extraJars;
     }
 
-    
-
-   
-
-    
-    /**
-     * @return
-     * @throws Exception
-     */
     public String getContainerClassPath() throws Exception
     {
         StringBuilder classPath = new StringBuilder();
@@ -742,13 +694,6 @@
         return "java";
     }
     
-
-    
-    
-    /**
-     * @param path
-     * @return
-     */
     public static String fileSeparators(String path)
     {
         StringBuilder ret = new StringBuilder();
@@ -766,13 +711,6 @@
         return ret.toString();
     }
 
-
-    
-    
-    /**
-     * @param path
-     * @return
-     */
     public static String pathSeparators(String path)
     {
         StringBuilder ret = new StringBuilder();
@@ -790,24 +728,11 @@
         return ret.toString();
     }
 
-
-    
-    
-    /**
-     * @return
-     */
     private String createToken ()
     {
         return Long.toString(random.nextLong()^System.currentTimeMillis(), 36).toUpperCase(Locale.ENGLISH);
     }
     
-
-    
-    
-    /**
-     * @param mode
-     * @param inputStream
-     */
     private void startPump(String mode, InputStream inputStream)
     {
         ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
@@ -816,13 +741,6 @@
         thread.start();
     }
 
-
-    
-    
-    /**
-     * @param strings
-     * @return
-     */
     private String toCSV (List<String> strings)
     {
         if (strings == null)
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
index 463c168..87a13ba 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java
@@ -31,33 +31,27 @@
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
-import org.codehaus.plexus.util.FileUtils;
-import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.PathWatcher;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.webapp.WebAppContext;
 
-
 /**
- *  <p>
  *  This goal is used in-situ on a Maven project without first requiring that the project 
  *  is assembled into a war, saving time during the development cycle.
+ *  <p>
  *  The plugin forks a parallel lifecycle to ensure that the "compile" phase has been completed before invoking Jetty. This means
  *  that you do not need to explicity execute a "mvn compile" first. It also means that a "mvn clean jetty:run" will ensure that
  *  a full fresh compile is done before invoking Jetty.
- *  </p>
  *  <p>
  *  Once invoked, the plugin can be configured to run continuously, scanning for changes in the project and automatically performing a 
  *  hot redeploy when necessary. This allows the developer to concentrate on coding changes to the project using their IDE of choice and have those changes
  *  immediately and transparently reflected in the running web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying.
- *  </p>
  *  <p>
  *  You may also specify the location of a jetty.xml file whose contents will be applied before any plugin configuration.
  *  This can be used, for example, to deploy a static webapp that is not part of your maven build. 
- *  </p>
  *  <p>
  *  There is a <a href="http://www.eclipse.org/jetty/documentation/current/maven-and-jetty.html">reference guide</a> to the configuration parameters for this plugin.
- *  </p>
- * 
  * 
  * @goal run
  * @requiresDependencyResolution test
@@ -85,7 +79,7 @@
      * The default location of the web.xml file. Will be used
      * if &lt;webApp&gt;&lt;descriptor&gt; is not set.
      * 
-     * @parameter expression="${maven.war.webxml}"
+     * @parameter default-value="${maven.war.webxml}"
      * @readonly
      */
     protected String webXml;
@@ -94,26 +88,41 @@
     /**
      * The directory containing generated classes.
      *
-     * @parameter expression="${project.build.outputDirectory}"
+     * @parameter default-value="${project.build.outputDirectory}"
      * @required
      * 
      */
     protected File classesDirectory;
     
+    /**
+     * An optional pattern for includes/excludes of classes in the classesDirectory
+     * @parameter
+     */
+    protected ScanPattern scanClassesPattern;
+    
+    
+    
     
     /**
      * The directory containing generated test classes.
      * 
-     * @parameter expression="${project.build.testOutputDirectory}"
+     * @parameter default-value="${project.build.testOutputDirectory}"
      * @required
      */
     protected File testClassesDirectory;
     
+    /**
+     * An optional pattern for includes/excludes of classes in the testClassesDirectory
+     * @parameter
+     */
+    protected ScanPattern scanTestClassesPattern;
+    
+   
     
     /**
      * Root directory for all html/jsp etc files
      *
-     * @parameter expression="${maven.war.src}"
+     * @parameter default-value="${maven.war.src}"
      * 
      */
     protected File webAppSourceDirectory;
@@ -136,12 +145,6 @@
 
     
     /**
-     * Extra scan targets as a list
-     */
-    protected List<File> extraScanTargets;
-    
-    
-    /**
      * maven-war-plugin reference
      */
     protected WarPluginInfo warPluginInfo;
@@ -232,59 +235,6 @@
         {
             throw new MojoExecutionException("Location of classesDirectory does not exist");
         }
-        
-        extraScanTargets = new ArrayList<File>();
-        if (scanTargets != null)
-        {            
-            for (int i=0; i< scanTargets.length; i++)
-            {
-                getLog().info("Added extra scan target:"+ scanTargets[i]);
-                extraScanTargets.add(scanTargets[i]);
-            }            
-        }
-        
-        if (scanTargetPatterns!=null)
-        {
-            for (int i=0;i<scanTargetPatterns.length; i++)
-            {
-                Iterator itor = scanTargetPatterns[i].getIncludes().iterator();
-                StringBuffer strbuff = new StringBuffer();
-                while (itor.hasNext())
-                {
-                    strbuff.append((String)itor.next());
-                    if (itor.hasNext())
-                        strbuff.append(",");
-                }
-                String includes = strbuff.toString();
-                
-                itor = scanTargetPatterns[i].getExcludes().iterator();
-                strbuff= new StringBuffer();
-                while (itor.hasNext())
-                {
-                    strbuff.append((String)itor.next());
-                    if (itor.hasNext())
-                        strbuff.append(",");
-                }
-                String excludes = strbuff.toString();
-
-                try
-                {
-                    List<File> files = FileUtils.getFiles(scanTargetPatterns[i].getDirectory(), includes, excludes);
-                    itor = files.iterator();
-                    while (itor.hasNext())
-                        getLog().info("Adding extra scan target from pattern: "+itor.next());
-                    List<File> currentTargets = extraScanTargets;
-                    if(currentTargets!=null && !currentTargets.isEmpty())
-                        currentTargets.addAll(files);
-                    else
-                        extraScanTargets = files;
-                }
-                catch (IOException e)
-                {
-                    throw new MojoExecutionException(e.getMessage());
-                }
-            }
-        }
     }
 
    
@@ -329,9 +279,7 @@
        //get copy of a list of war artifacts
        Set<Artifact> matchedWarArtifacts = new HashSet<Artifact>();
 
-       //make sure each of the war artifacts is added to the scanner
-       for (Artifact a:getWarArtifacts())
-           extraScanTargets.add(a.getFile());
+
 
        //process any overlays and the war type artifacts
        List<Overlay> overlays = new ArrayList<Overlay>();
@@ -420,77 +368,36 @@
     public void configureScanner ()
     throws MojoExecutionException
     {
-        // start the scanner thread (if necessary) on the main webapp
-        scanList = new ArrayList<File>();
-        if (webApp.getDescriptor() != null)
+        try
         {
-            try (Resource r = Resource.newResource(webApp.getDescriptor());)
-            {
-                scanList.add(r.getFile());
-            }
-            catch (IOException e)
-            {
-                throw new MojoExecutionException("Problem configuring scanner for web.xml", e);
-            }
+            gatherScannables();
+        }
+        catch (Exception e)
+        {
+            throw new MojoExecutionException("Error forming scan list", e);
         }
 
-        if (webApp.getJettyEnvXml() != null)
+        scanner.addListener(new PathWatcher.EventListListener()
         {
-            try (Resource r = Resource.newResource(webApp.getJettyEnvXml());)
-            {
-                scanList.add(r.getFile());
-            }
-            catch (IOException e)
-            {
-                throw new MojoExecutionException("Problem configuring scanner for jetty-env.xml", e);
-            }
-        }
 
-        if (webApp.getDefaultsDescriptor() != null)
-        {
-            try (Resource r = Resource.newResource(webApp.getDefaultsDescriptor());)
-            {
-                if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
-                    scanList.add(r.getFile());
-            }
-            catch (IOException e)
-            {
-                throw new MojoExecutionException("Problem configuring scanner for webdefaults.xml", e);
-            }
-        }
-        
-        if (webApp.getOverrideDescriptor() != null)
-        {
-            try (Resource r = Resource.newResource(webApp.getOverrideDescriptor());)
-            {
-                scanList.add(r.getFile());
-            }
-            catch (IOException e)
-            {
-                throw new MojoExecutionException("Problem configuring scanner for webdefaults.xml", e);
-            }
-        }
-        
-        
-        File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
-        if (jettyWebXmlFile != null)
-            scanList.add(jettyWebXmlFile);
-        scanList.addAll(extraScanTargets);
-        scanList.add(project.getFile());
-        if (webApp.getTestClasses() != null)
-            scanList.add(webApp.getTestClasses());
-        if (webApp.getClasses() != null)
-        scanList.add(webApp.getClasses());
-        scanList.addAll(webApp.getWebInfLib());
-     
-        scannerListeners = new ArrayList<Scanner.BulkListener>();
-        scannerListeners.add(new Scanner.BulkListener()
-        {
-            public void filesChanged (List changes)
+            @Override
+            public void onPathWatchEvents(List<PathWatchEvent> events)
             {
                 try
                 {
-                    boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
+                    boolean reconfigure = false;
+                    if (events != null)
+                    {
+                        for (PathWatchEvent e:events)
+                        {
+                            if (e.getPath().equals(project.getFile().toPath()))
+                            {
+                                reconfigure = true;
+                                break;
+                            }
+                        }
+                    }
+
                     restartWebApp(reconfigure);
                 }
                 catch (Exception e)
@@ -502,7 +409,115 @@
     }
 
     
-    
+    public void gatherScannables() throws Exception
+    {
+        if (webApp.getDescriptor() != null)
+        {
+            Resource r = Resource.newResource(webApp.getDescriptor());
+            scanner.watch(r.getFile().toPath());
+        }
+        
+        if (webApp.getJettyEnvXml() != null)
+            scanner.watch(new File(webApp.getJettyEnvXml()).toPath());
+
+        if (webApp.getDefaultsDescriptor() != null)
+        {
+            if (!WebAppContext.WEB_DEFAULTS_XML.equals(webApp.getDefaultsDescriptor()))
+                scanner.watch(new File(webApp.getDefaultsDescriptor()).toPath());
+        }
+
+        if (webApp.getOverrideDescriptor() != null)
+        {
+            scanner.watch(new File(webApp.getOverrideDescriptor()).toPath());
+        }
+        
+        File jettyWebXmlFile = findJettyWebXmlFile(new File(webAppSourceDirectory,"WEB-INF"));
+        if (jettyWebXmlFile != null)
+        {
+            scanner.watch(jettyWebXmlFile.toPath());
+        }
+        
+        //make sure each of the war artifacts is added to the scanner
+        for (Artifact a:getWarArtifacts())
+        {
+            scanner.watch(a.getFile().toPath());
+        }
+        
+        //handle the explicit extra scan targets
+        if (scanTargets != null)
+        {
+            for (File f:scanTargets)
+            {
+                if (f.isDirectory())
+                {
+                    PathWatcher.Config config = new PathWatcher.Config(f.toPath());
+                    config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+                    scanner.watch(config);
+                }
+                else
+                    scanner.watch(f.toPath());
+            }
+        }
+        
+        //handle the extra scan patterns
+        if (scanTargetPatterns != null)
+        {
+            for (ScanTargetPattern p:scanTargetPatterns)
+            {
+                PathWatcher.Config config = new PathWatcher.Config(p.getDirectory().toPath());
+                config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+                for (String pattern:p.getExcludes())
+                    config.addExcludeGlobRelative(pattern);
+                for (String pattern:p.getIncludes())
+                    config.addIncludeGlobRelative(pattern);
+                scanner.watch(config);
+            }
+        }
+      
+
+        scanner.watch(project.getFile().toPath());
+
+        if (webApp.getTestClasses() != null)
+        {
+            PathWatcher.Config config = new PathWatcher.Config(webApp.getTestClasses().toPath());
+            config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);           
+            if (scanTestClassesPattern != null)
+            {
+                for (String p:scanTestClassesPattern.getExcludes())
+                    config.addExcludeGlobRelative(p);
+                for (String p:scanTestClassesPattern.getIncludes())
+                    config.addIncludeGlobRelative(p);
+            }
+            scanner.watch(config);
+        }
+        
+        if (webApp.getClasses() != null)
+        {
+            PathWatcher.Config config = new PathWatcher.Config(webApp.getClasses().toPath());
+            config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+            if (scanClassesPattern != null)
+            {
+                for (String p:scanClassesPattern.getExcludes())
+                    config.addExcludeGlobRelative(p);
+
+                for (String p:scanClassesPattern.getIncludes())
+                    config.addIncludeGlobRelative(p);
+
+            }
+            scanner.watch(config);
+        }
+
+        if (webApp.getWebInfLib() != null)
+        {
+            for (File f:webApp.getWebInfLib())
+            {
+                PathWatcher.Config config = new PathWatcher.Config(f.toPath());
+                config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+                scanner.watch(config);
+            }
+        }
+    }
+
     
     /** 
      * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#restartWebApp(boolean)
@@ -511,7 +526,9 @@
     {
         getLog().info("restarting "+webApp);
         getLog().debug("Stopping webapp ...");
+        stopScanner();
         webApp.stop();
+
         getLog().debug("Reconfiguring webapp ...");
  
         checkPomConfiguration();
@@ -522,23 +539,14 @@
         if (reconfigureScanner)
         {
             getLog().info("Reconfiguring scanner after change to pom.xml ...");
-            scanList.clear();
-            if (webApp.getDescriptor() != null)
-                scanList.add(new File(webApp.getDescriptor()));
-            if (webApp.getJettyEnvXml() != null)
-                scanList.add(new File(webApp.getJettyEnvXml()));
-            scanList.addAll(extraScanTargets);
-            scanList.add(project.getFile());
-            if (webApp.getTestClasses() != null)
-                scanList.add(webApp.getTestClasses());
-            if (webApp.getClasses() != null)
-            scanList.add(webApp.getClasses());
-            scanList.addAll(webApp.getWebInfLib());
-            scanner.setScanDirs(scanList);
+            scanner.reset();
+            warArtifacts = null;
+            configureScanner();
         }
 
         getLog().debug("Restarting webapp ...");
         webApp.start();
+        startScanner();
         getLog().info("Restart completed at "+new Date().toString());
     }
     
@@ -588,8 +596,8 @@
         warArtifacts = new ArrayList<Artifact>();
         for ( Iterator<Artifact> iter = projectArtifacts.iterator(); iter.hasNext(); )
         {
-            Artifact artifact = (Artifact) iter.next();            
-            if (artifact.getType().equals("war"))
+            Artifact artifact = (Artifact) iter.next(); 
+            if (artifact.getType().equals("war") || artifact.getType().equals("zip"))
             {
                 try
                 {                  
@@ -605,13 +613,6 @@
         return warArtifacts;
     }
 
-    
-    
-    /**
-     * @param o
-     * @param warArtifacts
-     * @return
-     */
     protected Artifact getArtifactForOverlay (OverlayConfig o, List<Artifact> warArtifacts)
     {
         if (o == null || warArtifacts == null || warArtifacts.isEmpty())
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java
index 241281f..8b31d9b 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java
@@ -19,12 +19,12 @@
 package org.eclipse.jetty.maven.plugin;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
-import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.PathWatcher;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
 
 /**
  * 
@@ -52,7 +52,7 @@
     /**
      * The location of the war file.
      * 
-     * @parameter expression="${project.build.directory}/${project.build.finalName}"
+     * @parameter default-value="${project.build.directory}/${project.build.finalName}"
      * @required
      */
     private File war;
@@ -96,27 +96,41 @@
      */
     public void configureScanner() throws MojoExecutionException
     {
-        scanList = new ArrayList<File>();
-        scanList.add(project.getFile());
+        scanner.watch(project.getFile().toPath());
         File webInfDir = new File(war,"WEB-INF");
-        scanList.add(new File(webInfDir, "web.xml"));
+        scanner.watch(new File(webInfDir, "web.xml").toPath());
         File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
         if (jettyWebXmlFile != null)
-            scanList.add(jettyWebXmlFile);
+            scanner.watch(jettyWebXmlFile.toPath());
         File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
         if (jettyEnvXmlFile.exists())
-            scanList.add(jettyEnvXmlFile);
-        scanList.add(new File(webInfDir, "classes"));
-        scanList.add(new File(webInfDir, "lib"));
+            scanner.watch(jettyEnvXmlFile.toPath());
+        
+        PathWatcher.Config classesConfig = new PathWatcher.Config(new File(webInfDir, "classes").toPath());
+        classesConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+        scanner.watch(classesConfig);
+        
+        PathWatcher.Config libConfig = new PathWatcher.Config(new File(webInfDir, "lib").toPath());
+        libConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+        scanner.watch(libConfig);   
 
-        scannerListeners = new ArrayList<Scanner.BulkListener>();
-        scannerListeners.add(new Scanner.BulkListener()
+        scanner.addListener(new PathWatcher.EventListListener()
         {
-            public void filesChanged(List changes)
+
+            @Override
+            public void onPathWatchEvents(List<PathWatchEvent> events)
             {
                 try
                 {
-                    boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
+                    boolean reconfigure = false;
+                    for (PathWatchEvent e:events)
+                    {
+                        if (e.getPath().equals(project.getFile().toPath()))
+                        {
+                            reconfigure = true;
+                            break;
+                        }
+                    }
                     restartWebApp(reconfigure);
                 }
                 catch (Exception e)
@@ -137,6 +151,7 @@
     {
         getLog().info("Restarting webapp");
         getLog().debug("Stopping webapp ...");
+        stopScanner();
         webApp.stop();
         getLog().debug("Reconfiguring webapp ...");
 
@@ -147,23 +162,13 @@
         if (reconfigureScanner)
         {
             getLog().info("Reconfiguring scanner after change to pom.xml ...");
-            scanList.clear();
-            scanList.add(project.getFile());
-            File webInfDir = new File(war,"WEB-INF");
-            scanList.add(new File(webInfDir, "web.xml"));
-            File jettyWebXmlFile = findJettyWebXmlFile(webInfDir);
-            if (jettyWebXmlFile != null)
-                scanList.add(jettyWebXmlFile);
-            File jettyEnvXmlFile = new File(webInfDir, "jetty-env.xml");
-            if (jettyEnvXmlFile.exists())
-                scanList.add(jettyEnvXmlFile);
-            scanList.add(new File(webInfDir, "classes"));
-            scanList.add(new File(webInfDir, "lib"));
-            scanner.setScanDirs(scanList);
+            scanner.reset();
+            configureScanner();
         }
 
         getLog().debug("Restarting webapp ...");
         webApp.start();
+        startScanner();
         getLog().info("Restart completed.");
     }
 
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java
index a780a91..a78ae22 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java
@@ -19,12 +19,12 @@
 package org.eclipse.jetty.maven.plugin;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
-import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.PathWatcher;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
 
 /**
  * <p>
@@ -50,7 +50,7 @@
 
     /**
      * The location of the war file.
-     * @parameter expression="${project.build.directory}/${project.build.finalName}.war"
+     * @parameter default-value="${project.build.directory}/${project.build.finalName}.war"
      * @required
      */
     private File war;
@@ -100,18 +100,26 @@
      */
     public void configureScanner() throws MojoExecutionException
     {
-        scanList = new ArrayList();
-        scanList.add(project.getFile());
-        scanList.add(war);
-        
-        scannerListeners = new ArrayList();
-        scannerListeners.add(new Scanner.BulkListener()
+        scanner.watch(project.getFile().toPath());
+        scanner.watch(war.toPath());
+
+        scanner.addListener(new PathWatcher.EventListListener()
         {
-            public void filesChanged(List changes)
+
+            @Override
+            public void onPathWatchEvents(List<PathWatchEvent> events)
             {
                 try
                 {
-                    boolean reconfigure = changes.contains(project.getFile().getCanonicalPath());
+                    boolean reconfigure = false;
+                    for (PathWatchEvent e:events)
+                    {
+                        if (e.getPath().equals(project.getFile().toPath()))
+                        {
+                            reconfigure = true;
+                            break;
+                        }
+                    }
                     restartWebApp(reconfigure);
                 }
                 catch (Exception e)
@@ -132,6 +140,7 @@
     {
         getLog().info("Restarting webapp ...");
         getLog().debug("Stopping webapp ...");
+        stopScanner();
         webApp.stop();
         getLog().debug("Reconfiguring webapp ...");
 
@@ -142,14 +151,13 @@
         if (reconfigureScanner)
         {
             getLog().info("Reconfiguring scanner after change to pom.xml ...");
-            scanList.clear();
-            scanList.add(project.getFile());
-            scanList.add(war);
-            scanner.setScanDirs(scanList);
+            scanner.reset();
+            configureScanner();
         }
 
         getLog().debug("Restarting webapp ...");
         webApp.start();
+        startScanner();
         getLog().info("Restart completed.");
     }
 
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java
deleted file mode 100644
index 33fe6b2..0000000
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyServer.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.maven.plugin;
-
-
-import java.io.File;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.RequestLog;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.server.handler.DefaultHandler;
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.server.handler.RequestLogHandler;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.eclipse.jetty.xml.XmlConfiguration;
-
-
-/**
- * JettyServer
- * 
- * Maven jetty plugin version of a wrapper for the Server class.
- * 
- */
-public class JettyServer extends org.eclipse.jetty.server.Server
-{ 
-    private RequestLog requestLog;
-    private ContextHandlerCollection contexts;
-    
-    
-    
-    /**
-     * 
-     */
-    public JettyServer()
-    {
-        super();
-        //make sure Jetty does not use URLConnection caches with the plugin
-        Resource.setDefaultUseCaches(false);
-    }
-
-   
-    public void setRequestLog (RequestLog requestLog)
-    {
-        this.requestLog = requestLog;
-    }
-
-    /**
-     * @see org.eclipse.jetty.server.Server#doStart()
-     */
-    public void doStart() throws Exception
-    {
-        super.doStart();
-    }
-
- 
-    /**
-     * @see org.eclipse.jetty.server.handler.HandlerCollection#addHandler(org.eclipse.jetty.server.Handler)
-     */
-    public void addWebApplication(WebAppContext webapp) throws Exception
-    {  
-        contexts.addHandler (webapp);
-    }
-
-    
-    /**
-     * Set up the handler structure to receive a webapp.
-     * Also put in a DefaultHandler so we get a nice page
-     * than a 404 if we hit the root and the webapp's
-     * context isn't at root.
-     * @throws Exception
-     */
-    public void configureHandlers () throws Exception 
-    {
-        DefaultHandler defaultHandler = new DefaultHandler();
-        RequestLogHandler requestLogHandler = new RequestLogHandler();
-        if (this.requestLog != null)
-            requestLogHandler.setRequestLog(this.requestLog);
-        
-        contexts = (ContextHandlerCollection)super.getChildHandlerByClass(ContextHandlerCollection.class);
-        if (contexts==null)
-        {   
-            contexts = new ContextHandlerCollection();
-            HandlerCollection handlers = (HandlerCollection)super.getChildHandlerByClass(HandlerCollection.class);
-            if (handlers==null)
-            {
-                handlers = new HandlerCollection();               
-                super.setHandler(handlers);                            
-                handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler});
-            }
-            else
-            {
-                handlers.addHandler(contexts);
-            }
-        }  
-    }
-
-    /**
-     * Apply xml files to server startup, passing in ourselves as the 
-     * "Server" instance.
-     * 
-     * @param files
-     * @throws Exception
-     */
-    public  void applyXmlConfigurations (List<File> files) 
-    throws Exception
-    {
-        if (files == null || files.isEmpty())
-            return;
-
-       Map<String,Object> lastMap = Collections.singletonMap("Server", (Object)this);
-
-        for ( File xmlFile : files )
-        {
-            if (PluginLog.getLog() != null)
-                PluginLog.getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );   
-
-
-            XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
-
-            //chain ids from one config file to another
-            if (lastMap != null)
-                xmlConfiguration.getIdMap().putAll(lastMap); 
-
-            //Set the system properties each time in case the config file set a new one
-            Enumeration<?> ensysprop = System.getProperties().propertyNames();
-            while (ensysprop.hasMoreElements())
-            {
-                String name = (String)ensysprop.nextElement();
-                xmlConfiguration.getProperties().put(name,System.getProperty(name));
-            }
-            xmlConfiguration.configure(); 
-            lastMap = xmlConfiguration.getIdMap();
-        }
-    }
-}
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
index ecef511..20529c5 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyWebAppContext.java
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.EventListener;
@@ -71,23 +72,25 @@
     private static final String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN = ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$|.*javax.servlet.jsp.jstl-[^/]*\\.jar|.*taglibs-standard-impl-.*\\.jar";
     private static final String WEB_INF_CLASSES_PREFIX = "/WEB-INF/classes";
     private static final String WEB_INF_LIB_PREFIX = "/WEB-INF/lib";
+    
+    
+    public  static final String[] DEFAULT_CONFIGURATION_CLASSES = {
+                                                           "org.eclipse.jetty.maven.plugin.MavenWebInfConfiguration",
+                                                           "org.eclipse.jetty.webapp.WebXmlConfiguration",
+                                                           "org.eclipse.jetty.webapp.MetaInfConfiguration",
+                                                           "org.eclipse.jetty.webapp.FragmentConfiguration",
+                                                           "org.eclipse.jetty.plus.webapp.EnvConfiguration",
+                                                           "org.eclipse.jetty.plus.webapp.PlusConfiguration",
+                                                           "org.eclipse.jetty.annotations.AnnotationConfiguration",
+                                                           "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
+                                                           };
 
-    private final Configuration[] _defaultConfigurations = {
-                                                             new MavenWebInfConfiguration(),
-                                                             new WebXmlConfiguration(),
-                                                             new MetaInfConfiguration(),
-                                                             new FragmentConfiguration(),
-                                                             new EnvConfiguration(),
-                                                             new PlusConfiguration(),
-                                                             new AnnotationConfiguration(),
-                                                             new JettyWebXmlConfiguration()
-                                                            };
 
-    private final Configuration[] _quickStartConfigurations = {
-                                                                new MavenQuickStartConfiguration(),
-                                                                new EnvConfiguration(),
-                                                                new PlusConfiguration(),
-                                                                new JettyWebXmlConfiguration()
+    private final String[] QUICKSTART_CONFIGURATION_CLASSES = {
+                                                                "org.eclipse.jetty.maven.plugin.MavenQuickStartConfiguration",
+                                                                "org.eclipse.jetty.plus.webapp.EnvConfiguration",
+                                                                "org.eclipse.jetty.plus.webapp.PlusConfiguration",
+                                                                "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
                                                                };
 
     private File _classes = null;
@@ -99,6 +102,7 @@
     private String _jettyEnvXml;
     private List<Overlay> _overlays;
     private Resource _quickStartWebXml;
+   
     
  
     
@@ -130,7 +134,7 @@
    
 
   
-
+    /* ------------------------------------------------------------ */
     public JettyWebAppContext ()
     throws Exception
     {
@@ -138,81 +142,92 @@
         // Turn off copyWebInf option as it is not applicable for plugin.
         super.setCopyWebInf(false);
     }
+    
+    /* ------------------------------------------------------------ */
     public void setContainerIncludeJarPattern(String pattern)
     {
         _containerIncludeJarPattern = pattern;
     }
     
+    /* ------------------------------------------------------------ */
     public String getContainerIncludeJarPattern()
     {
         return _containerIncludeJarPattern;
     }
     
-    
+    /* ------------------------------------------------------------ */
     public String getWebInfIncludeJarPattern()
     {
         return _webInfIncludeJarPattern;
     }
+    
+    /* ------------------------------------------------------------ */
     public void setWebInfIncludeJarPattern(String pattern)
     {
         _webInfIncludeJarPattern = pattern;
     }
    
-   
+    /* ------------------------------------------------------------ */
     public List<File> getClassPathFiles()
     {
         return this._classpathFiles;
     }
     
-    
+    /* ------------------------------------------------------------ */
     public void setJettyEnvXml (String jettyEnvXml)
     {
         this._jettyEnvXml = jettyEnvXml;
     }
     
+    /* ------------------------------------------------------------ */
     public String getJettyEnvXml()
     {
         return this._jettyEnvXml;
     }
 
-   
+    /* ------------------------------------------------------------ */
     public void setClasses(File dir)
     {
         _classes = dir;
     }
     
+    /* ------------------------------------------------------------ */
     public File getClasses()
     {
         return _classes;
     }
     
+    /* ------------------------------------------------------------ */
     public void setWebInfLib (List<File> jars)
     {
         _webInfJars.addAll(jars);
     }
     
-    
+    /* ------------------------------------------------------------ */
     public void setTestClasses (File dir)
     {
         _testClasses = dir;
     }
     
-    
+    /* ------------------------------------------------------------ */
     public File getTestClasses ()
     {
         return _testClasses;
     }
     
+    
+    /* ------------------------------------------------------------ */
     /**
      * Ordered list of wars to overlay on top of the current project. The list
      * may contain an overlay that represents the current project.
-     * @param overlays
+     * @param overlays the list of overlays
      */
     public void setOverlays (List<Overlay> overlays)
     {
         _overlays = overlays;
     }
     
+    /* ------------------------------------------------------------ */
     public List<Overlay> getOverlays()
     {
         return _overlays;
@@ -231,7 +246,13 @@
     }
     
     /* ------------------------------------------------------------ */
-    public void setQuickStartWebDescriptor (Resource quickStartWebXml)
+    public void setQuickStartWebDescriptor (String quickStartWebXml) throws Exception
+    {
+        setQuickStartWebDescriptor(Resource.newResource(quickStartWebXml));
+    }
+    
+    /* ------------------------------------------------------------ */
+    protected void setQuickStartWebDescriptor (Resource quickStartWebXml)
     {
         _quickStartWebXml = quickStartWebXml;
     }
@@ -260,17 +281,20 @@
         
         setBaseResource(new ResourceCollection(resources.toArray(new String[resources.size()])));
     }
-
+    
+    /* ------------------------------------------------------------ */
     public List<File> getWebInfLib()
     {
         return _webInfJars;
     }
     
+    /* ------------------------------------------------------------ */
     public void setGenerateQuickStart (boolean quickStart)
     {
         _isGenerateQuickStart = quickStart;
     }
     
+    /* ------------------------------------------------------------ */
     public boolean isGenerateQuickStart()
     {
         return _isGenerateQuickStart;
@@ -278,7 +302,7 @@
     
    
     
-    
+    /* ------------------------------------------------------------ */
     @Override
     protected void startWebapp() throws Exception
     {
@@ -294,35 +318,40 @@
             }
         }
         else
+        {
+            if (LOG.isDebugEnabled()) { LOG.debug("Calling full start on webapp");}
             super.startWebapp();
+        }
     }
     
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void stopWebapp() throws Exception
+    {
+        if (isGenerateQuickStart())
+            return;
 
+        if (LOG.isDebugEnabled()) { LOG.debug("Calling stop of fully started webapp");}
+        super.stopWebapp();
+    }
+    
+    /* ------------------------------------------------------------ */
     @Override
     public void doStart () throws Exception
     {
         //choose if this will be a quickstart or normal start
         if (!isGenerateQuickStart() && getQuickStartWebDescriptor() != null)
-            setConfigurations(_quickStartConfigurations);
-        else
         {
-            setConfigurations(_defaultConfigurations);
+            setConfigurationClasses(QUICKSTART_CONFIGURATION_CLASSES);
+        }
+        else
+        { 
             if (isGenerateQuickStart())
             {
                 _preconfigProcessor = new PreconfigureDescriptorProcessor();
                 getMetaData().addDescriptorProcessor(_preconfigProcessor);
             }
         }
-        
-
-        //inject configurations with config from maven plugin    
-        for (Configuration c:getConfigurations())
-        {
-            if (c instanceof EnvConfiguration && getJettyEnvXml() != null)
-                ((EnvConfiguration)c).setJettyEnvXml(Resource.toURL(new File(getJettyEnvXml())));
-            else if (c instanceof MavenQuickStartConfiguration && getQuickStartWebDescriptor() != null)
-                ((MavenQuickStartConfiguration)c).setQuickStartWebXml(getQuickStartWebDescriptor());         
-        }
 
         //Set up the pattern that tells us where the jars are that need scanning
 
@@ -362,10 +391,31 @@
                 _webInfJarMap.put(fileName, file);
         }
         
+        //check for CDI
+        initCDI();
+        
         // CHECK setShutdown(false);
         super.doStart();
     }
-     
+    
+    
+    @Override
+    protected void loadConfigurations() throws Exception
+    {
+        super.loadConfigurations();
+        
+        //inject configurations with config from maven plugin    
+        for (Configuration c:getConfigurations())
+        {
+            if (c instanceof EnvConfiguration && getJettyEnvXml() != null)
+                ((EnvConfiguration)c).setJettyEnvXml(Resource.toURL(new File(getJettyEnvXml())));
+            else if (c instanceof MavenQuickStartConfiguration && getQuickStartWebDescriptor() != null)
+                ((MavenQuickStartConfiguration)c).setQuickStartWebXml(getQuickStartWebDescriptor());         
+        }
+    }
+
+
+    /* ------------------------------------------------------------ */
     public void doStop () throws Exception
     { 
         if (_classpathFiles != null)
@@ -386,8 +436,9 @@
         // CHECK setShutdown(true);
         //just wait a little while to ensure no requests are still being processed
         Thread.currentThread().sleep(500L);
+
         super.doStop();
-        
+
         //remove all listeners, servlets and filters. This is because we will re-apply
         //any context xml file, which means they would potentially be added multiple times.
         setEventListeners(new EventListener[0]);
@@ -396,7 +447,9 @@
         getServletHandler().setServlets(new ServletHolder[0]);
         getServletHandler().setServletMappings(new ServletMapping[0]);
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
     @Override
     public Resource getResource(String uriInContext) throws MalformedURLException
     {
@@ -470,7 +523,9 @@
         }
         return resource;
     }
-
+    
+    
+    /* ------------------------------------------------------------ */
     @Override
     public Set<String> getResourcePaths(String path)
     {
@@ -507,7 +562,7 @@
         return paths;
     }
     
-    
+    /* ------------------------------------------------------------ */
     public String addPattern (String s, String pattern)
     {
         if (s == null)
@@ -524,4 +579,29 @@
         
         return s;
     }
+    
+    
+    /* ------------------------------------------------------------ */
+    public void initCDI()
+    {
+        Class cdiInitializer = null;
+        try
+        {
+            cdiInitializer = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.cdi.servlet.JettyWeldInitializer");
+            Method initWebAppMethod = cdiInitializer.getMethod("initWebApp", new Class[]{WebAppContext.class});
+            initWebAppMethod.invoke(null, new Object[]{this});
+        }
+        catch (ClassNotFoundException e)
+        {
+            LOG.debug("o.e.j.cdi.servlet.JettyWeldInitializer not found, no cdi integration available");
+        }
+        catch (NoSuchMethodException e)
+        {
+            LOG.warn("o.e.j.cdi.servlet.JettyWeldInitializer.initWebApp() not found, no cdi integration available");
+        }
+        catch (Exception e)
+        {
+           LOG.warn("Problem initializing cdi", e);
+        }
+    }
 }
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenServerConnector.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenServerConnector.java
index 8a0b3e9..5bdbe90 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenServerConnector.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenServerConnector.java
@@ -47,6 +47,8 @@
  */
 public class MavenServerConnector extends AbstractLifeCycle implements Connector
 {
+    public static String PORT_SYSPROPERTY = "jetty.http.port";
+    
     public static final int DEFAULT_PORT = 8080;
     public static final String DEFAULT_PORT_STR = String.valueOf(DEFAULT_PORT);
     public static final int DEFAULT_MAX_IDLE_TIME = 30000;
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java
index bf55c8f..d422449 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/MavenWebInfConfiguration.java
@@ -40,8 +40,7 @@
  * MavenWebInfConfiguration
  * 
  * WebInfConfiguration to take account of overlaid wars expressed as project dependencies and
- * potentiall configured via the maven-war-plugin.
- *
+ * potential configured via the maven-war-plugin.
  */
 public class MavenWebInfConfiguration extends WebInfConfiguration
 {
@@ -51,9 +50,6 @@
     protected static int COUNTER = 0; 
     protected Resource _originalResourceBase;
     protected List<Resource>  _unpackedOverlayResources;
-  
-    
-    
     
     /** 
      * @see org.eclipse.jetty.webapp.WebInfConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
@@ -192,7 +188,7 @@
      * Get the jars to examine from the files from which we have
      * synthesized the classpath. Note that the classpath is not
      * set at this point, so we cannot get them from the classpath.
-     * @param context
+     * @param context the web app context
      * @return the list of jars found
      */
     @Override
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java
index 4915dee..f6f87f8 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/OverlayConfig.java
@@ -29,8 +29,6 @@
 
 /**
  * OverlayConfig
- *
- *
  */
 public class OverlayConfig
 {
@@ -271,7 +269,7 @@
      * @param gid Artifact groupId
      * @param aid Artifact artifactId
      * @param cls Artifact classifier
-     * @return
+     * @return true if matched
      */
     public boolean matchesArtifact (String gid, String aid, String cls)
     {
@@ -286,9 +284,9 @@
     /**
      * Check if this overlay configuration matches an Artifact's info
      * 
-     * @param gid
-     * @param aid
-     * @return
+     * @param gid the group id
+     * @param aid the artifact id
+     * @return true if matched
      */
     public boolean matchesArtifact (String gid, String aid)
     {
@@ -299,9 +297,6 @@
         return false;
     }
     
-    
-    
-    
     public String toString()
     {
         StringBuffer strbuff = new StringBuffer();
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java
new file mode 100644
index 0000000..8048f73
--- /dev/null
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanPattern.java
@@ -0,0 +1,53 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.maven.plugin;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * ScanPattern
+ *
+ * A pattern of includes and excludes.
+ */
+public class ScanPattern
+{
+    private List<String> _includes = Collections.emptyList();
+    private List<String> _excludes = Collections.emptyList();
+    
+    public void setIncludes (List<String> includes)
+    {
+        _includes= includes;
+    }
+    
+    public void setExcludes(List<String> excludes)
+    {
+        _excludes = excludes;
+    }
+    
+    public List<String> getIncludes()
+    {
+        return _includes;
+    }
+    
+    public List<String> getExcludes()
+    {
+        return _excludes;
+    }
+}
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java
index 79448ff..5700d54 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ScanTargetPattern.java
@@ -46,8 +46,7 @@
 public class ScanTargetPattern
 {
     private File _directory;
-    private List _includes = Collections.EMPTY_LIST;
-    private List _excludes = Collections.EMPTY_LIST;
+    private ScanPattern _pattern;
 
     /**
      * @return the _directory
@@ -65,24 +64,28 @@
         this._directory = directory;
     }
     
-    public void setIncludes (List includes)
+    public void setIncludes (List<String> includes)
     {
-        _includes= includes;
+        if (_pattern == null)
+            _pattern = new ScanPattern();
+        _pattern.setIncludes(includes);
     }
     
-    public void setExcludes(List excludes)
+    public void setExcludes(List<String> excludes)
     {
-        _excludes = excludes;
+        if (_pattern == null)
+            _pattern = new ScanPattern();
+        _pattern.setExcludes(excludes);
     }
     
-    public List getIncludes()
+    public List<String> getIncludes()
     {
-        return _includes;
+        return (_pattern == null? Collections.emptyList() : _pattern.getIncludes());
     }
     
-    public List getExcludes()
+    public List<String> getExcludes()
     {
-        return _excludes;
+        return (_pattern == null? Collections.emptyList() : _pattern.getExcludes());
     }
 
 }
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java
index 21c25d0..abdea18 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/SelectiveJarResource.java
@@ -52,30 +52,20 @@
     public static final List<String> DEFAULT_INCLUDES = Arrays.asList(new String[]{"**"});// No includes supplied, so set it to 'matches all'
     public static final List<String> DEFAULT_EXCLUDES = Collections.emptyList(); //No includes, set to no exclusions
 
-
     List<String> _includes = null;
     List<String> _excludes = null;
     boolean _caseSensitive = false;
     
-
-    /**
-     * @param url
-     */
     public SelectiveJarResource(URL url)
     {
         super(url);
     }
   
-    /**
-     * @param url
-     * @param useCaches
-     */
     public SelectiveJarResource(URL url, boolean useCaches)
     {
         super(url, useCaches);
     }
     
-    
     public void setCaseSensitive (boolean caseSensitive)
     {
         _caseSensitive = caseSensitive;
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java
new file mode 100644
index 0000000..5385a74
--- /dev/null
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/ServerSupport.java
@@ -0,0 +1,218 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.maven.plugin;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jetty.security.LoginService;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.RequestLog;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.DefaultHandler;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.webapp.Configuration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.xml.XmlConfiguration;
+
+/**
+ * ServerSupport
+ *
+ * Helps configure the Server instance.
+ * 
+ */
+public class ServerSupport
+{
+    
+    public static void configureDefaultConfigurationClasses (Server server)
+    {
+        server.setAttribute(Configuration.ATTR, JettyWebAppContext.DEFAULT_CONFIGURATION_CLASSES);
+    }
+    
+    
+    /**
+     * Set up the handler structure to receive a webapp.
+     * Also put in a DefaultHandler so we get a nice page
+     * than a 404 if we hit the root and the webapp's
+     * context isn't at root.
+     * @param server the server
+     * @param requestLog the request log
+     * @throws Exception if unable to configure the handlers
+     */
+    public static void configureHandlers (Server server, RequestLog requestLog) throws Exception 
+    {
+        if (server == null)
+            throw new IllegalArgumentException ("Server is null");
+
+        DefaultHandler defaultHandler = new DefaultHandler();
+        RequestLogHandler requestLogHandler = new RequestLogHandler();
+        if (requestLog != null)
+            requestLogHandler.setRequestLog(requestLog);
+
+        ContextHandlerCollection contexts = findContextHandlerCollection(server);
+        if (contexts == null)
+        {   
+            contexts = new ContextHandlerCollection();
+            HandlerCollection handlers = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class);
+            if (handlers == null)
+            {
+                handlers = new HandlerCollection();               
+                server.setHandler(handlers);                            
+                handlers.setHandlers(new Handler[]{contexts, defaultHandler, requestLogHandler});
+            }
+            else
+            {
+                handlers.addHandler(contexts);
+            }
+        }  
+    }
+    
+
+    /**
+     * Configure at least one connector for the server
+     * 
+     * @param server the server
+     * @param connector the connector
+     */
+    public static void configureConnectors (Server server, Connector connector)
+    {
+        if (server == null)
+            throw new IllegalArgumentException("Server is null");
+        
+        //if a connector is provided, use it
+        if (connector != null)
+        {
+            server.addConnector(connector);
+            return;
+        }
+        
+        
+
+        // if the user hasn't configured the connectors in a jetty.xml file so use a default one
+        Connector[] connectors = server.getConnectors();
+        if (connectors == null || connectors.length == 0)
+        {
+            //Make a new default connector
+            MavenServerConnector tmp = new MavenServerConnector();               
+            //use any jetty.http.port settings provided
+            String port = System.getProperty(MavenServerConnector.PORT_SYSPROPERTY, System.getProperty("jetty.port", MavenServerConnector.DEFAULT_PORT_STR));
+            tmp.setPort(Integer.parseInt(port.trim()));
+            tmp.setServer(server);
+            server.setConnectors(new Connector[] {tmp});
+        }
+    }
+    
+    
+    /**
+     * Set up any security LoginServices provided.
+     * 
+     * @param server the server
+     * @param loginServices the login services
+     */
+    public static void configureLoginServices (Server server, LoginService[] loginServices)
+    {
+        if (server == null)
+            throw new IllegalArgumentException ("Server is null");
+
+        if (loginServices != null)
+        {
+            for (LoginService loginService:loginServices)
+            {
+                PluginLog.getLog().debug(loginService.getClass().getName() + ": "+ loginService.toString());
+                server.addBean(loginService);
+            }
+        }
+    }
+    
+    public static void addWebApplication(Server server, WebAppContext webapp) throws Exception
+    {  
+        if (server == null)
+            throw new IllegalArgumentException ("Server is null");
+       ContextHandlerCollection contexts = findContextHandlerCollection(server);
+       if (contexts == null)
+           throw new IllegalStateException("ContextHandlerCollection is null");
+       contexts.addHandler (webapp);
+    }
+    
+
+    public static ContextHandlerCollection findContextHandlerCollection (Server server)
+    {
+        if (server == null)
+            return null;
+
+        return (ContextHandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
+    }
+
+
+    /**
+     * Apply xml files to server startup, passing in ourselves as the 
+     * "Server" instance.
+     * 
+     * @param server the server to apply the xml to
+     * @param files the list of xml files
+     * @return the Server implementation, after the xml is applied
+     * @throws Exception if unable to apply the xml configuration
+     */
+    public static Server applyXmlConfigurations (Server server, List<File> files) 
+    throws Exception
+    {
+        if (files == null || files.isEmpty())
+            return server;
+
+        Map<String,Object> lastMap = new HashMap<String,Object>();
+        
+        if (server != null)
+            lastMap.put("Server", server);
+     
+
+        for ( File xmlFile : files )
+        {
+            if (PluginLog.getLog() != null)
+                PluginLog.getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() );   
+
+
+            XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile));
+
+            //chain ids from one config file to another
+            if (lastMap != null)
+                xmlConfiguration.getIdMap().putAll(lastMap); 
+
+            //Set the system properties each time in case the config file set a new one
+            Enumeration<?> ensysprop = System.getProperties().propertyNames();
+            while (ensysprop.hasMoreElements())
+            {
+                String name = (String)ensysprop.nextElement();
+                xmlConfiguration.getProperties().put(name,System.getProperty(name));
+            }
+            xmlConfiguration.configure(); 
+            lastMap = xmlConfiguration.getIdMap();
+        }
+        
+        return (Server)lastMap.get("Server");
+    }
+
+}
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java
index 23fa777..b75f8ec 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/Starter.java
@@ -31,8 +31,8 @@
 import java.util.Set;
 import java.util.TreeMap;
 
-import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ShutdownMonitor;
 import org.eclipse.jetty.server.handler.HandlerCollection;
 import org.eclipse.jetty.util.StringUtil;
@@ -45,20 +45,16 @@
 
 
 /**
- * Starter
- * 
- * Class which is exec'ed to create a new jetty process. Used by the JettyRunForked mojo.
- *
+ * Starter Class which is exec'ed to create a new jetty process. Used by the JettyRunForked mojo.
  */
 public class Starter
 { 
-    public static final String PORT_SYSPROPERTY = "jetty.port";
     private static final Logger LOG = Log.getLogger(Starter.class);
 
     private List<File> jettyXmls; // list of jetty.xml config files to apply - Mandatory
     private File contextXml; //name of context xml file to configure the webapp - Mandatory
 
-    private JettyServer server = new JettyServer();
+    private Server server;
     private JettyWebAppContext webApp;
 
     
@@ -116,41 +112,23 @@
     
     
     
-    /**
-     * @throws Exception
-     */
     public void configureJetty () throws Exception
     {
         LOG.debug("Starting Jetty Server ...");
-
+        Resource.setDefaultUseCaches(false);
+        
         //apply any configs from jetty.xml files first 
         applyJettyXml ();
 
-        // if the user hasn't configured a connector in the jetty.xml
-        //then use a default
-        Connector[] connectors = this.server.getConnectors();
-        if (connectors == null|| connectors.length == 0)
-        {
-            //if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
-            MavenServerConnector httpConnector = new MavenServerConnector();
-            httpConnector.setServer(this.server);
-            String tmp = System.getProperty(PORT_SYSPROPERTY, MavenServerConnector.DEFAULT_PORT_STR);
-            httpConnector.setPort(Integer.parseInt(tmp.trim()));
-            connectors = new Connector[] {httpConnector};
-            this.server.setConnectors(connectors);
-        }
-
-        //check that everything got configured, and if not, make the handlers
-        HandlerCollection handlers = (HandlerCollection) server.getChildHandlerByClass(HandlerCollection.class);
-        if (handlers == null)
-        {
-            handlers = new HandlerCollection();
-            server.setHandler(handlers);
-        }
+        //ensure there's a connector
+        ServerSupport.configureConnectors(server, null);
 
         //check if contexts already configured, create if not
-        this.server.configureHandlers();
-
+        ServerSupport.configureHandlers(server, null);
+        
+        //Set up list of default Configurations to apply to a webapp
+        ServerSupport.configureDefaultConfigurationClasses(server);
+        
         webApp = new JettyWebAppContext();
         
         //configure webapp from properties file describing unassembled webapp
@@ -177,7 +155,7 @@
             xmlConfiguration.configure(webApp);
         }
 
-        this.server.addWebApplication(webApp);
+        ServerSupport.addWebApplication(server, webApp);
 
         if(stopPort>0 && stopKey!=null)
         {
@@ -188,10 +166,6 @@
         }
     }
     
-    
-    /**
-     * @throws Exception
-     */
     public void configureWebApp ()
     throws Exception
     {
@@ -340,10 +314,6 @@
         
     }
 
-    /**
-     * @param args
-     * @throws Exception
-     */
     public void getConfiguration (String[] args)
     throws Exception
     {
@@ -394,9 +364,6 @@
     }
 
 
-    /**
-     * @throws Exception
-     */
     public void run() throws Exception
     {
         LOG.info("Started Jetty Server");
@@ -404,18 +371,12 @@
     }
 
     
-    /**
-     * @throws Exception
-     */
     public void join () throws Exception
     {
         server.join();
     }
     
     
-    /**
-     * @param e
-     */
     public void communicateStartupResult (Exception e)
     {
         if (token != null)
@@ -430,22 +391,21 @@
     
     /**
      * Apply any jetty xml files given
-     * @throws Exception
+     * @throws Exception if unable to apply the xml
      */
     public void applyJettyXml() throws Exception
     {
-        if (jettyXmls == null)
-            return;
-        this.server.applyXmlConfigurations(jettyXmls);
+        Server tmp = ServerSupport.applyXmlConfigurations(server, jettyXmls);
+        if (server == null)
+            server = tmp;
+        
+        if (server == null)
+            server = new Server();
     }
 
 
 
 
-    /**
-     * @param handler
-     * @param handlers
-     */
     protected void prependHandler (Handler handler, HandlerCollection handlers)
     {
         if (handler == null || handlers == null)
@@ -460,11 +420,6 @@
     
     
     
-    /**
-     * @param c
-     * @param wars
-     * @return
-     */
     protected Artifact getArtifactForOverlayConfig (OverlayConfig c, List<Artifact> wars)
     {
         if (wars == null || wars.isEmpty() || c == null)
@@ -499,11 +454,6 @@
         return list;
     }
     
-    
-    
-    /**
-     * @param args
-     */
     public static final void main(String[] args)
     {
         if (args == null)
diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java
index 100d663..7cefb8e 100644
--- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java
+++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/WarPluginInfo.java
@@ -30,11 +30,9 @@
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.eclipse.jetty.util.StringUtil;
 
-
-
 /**
  * WarPluginInfo
- *
+ * <p>
  * Information about the maven-war-plugin contained in the pom
  */
 public class WarPluginInfo
@@ -46,10 +44,6 @@
     private List<OverlayConfig> _overlayConfigs;
     
     
-    
-    /**
-     * @param project
-     */
     public WarPluginInfo (MavenProject project)
     {
         _project = project;
@@ -60,7 +54,7 @@
     
     /**
      * Find the maven-war-plugin, if one is configured
-     * @return
+     * @return the plugin
      */
     public Plugin getPlugin()
     {
@@ -87,7 +81,7 @@
 
     /**
      * Get value of dependentWarIncludes for maven-war-plugin
-     * @return
+     * @return the list of dependent war includes
      */
     public List<String> getDependentMavenWarIncludes()
     {
@@ -116,7 +110,7 @@
     
     /**
      * Get value of dependentWarExcludes for maven-war-plugin
-     * @return
+     * @return the list of dependent war excludes
      */
     public List<String> getDependentMavenWarExcludes()
     {
@@ -146,7 +140,7 @@
     /**
      * Get config for any overlays that have been declared for the maven-war-plugin.
      * 
-     * @return
+     * @return the list of overlay configs
      */
     public List<OverlayConfig> getMavenWarOverlayConfigs ()
     {
diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml
index a611122..22ee8ac 100644
--- a/jetty-monitor/pom.xml
+++ b/jetty-monitor/pom.xml
@@ -19,7 +19,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-monitor</artifactId>
@@ -32,52 +32,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.management.*,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
diff --git a/jetty-monitor/src/main/config/etc/jetty-monitor.xml b/jetty-monitor/src/main/config/etc/jetty-monitor.xml
index 61270b5..a8f6633 100644
--- a/jetty-monitor/src/main/config/etc/jetty-monitor.xml
+++ b/jetty-monitor/src/main/config/etc/jetty-monitor.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
   <!-- Create Thread Monitor, and add to the Server as a lifecycle -->
@@ -13,15 +13,15 @@
         <!-- To enable logging CPU utilization for threads above specified threshold, -->
         <!-- uncomment the following lines, changing log interval (in milliseconds)  -->
         <!-- and log threshold (in percent) as desired.                              -->
-        <!-- 
+        <!--
         <Set name="logInterval">10000</Set>
         <Set name="logThreshold">1</Set>
         -->
-        
+
         <!-- To enable detail dump of the server whenever a thread is detected as spinning, -->
         <!-- uncomment the following lines. -->
         <!--
-        <Set name="dumpable"><Ref id="Server"/></Set>
+        <Set name="dumpable"><Ref refid="Server"/></Set>
         -->
       </New>
     </Arg>
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java
index 15d1fcb..3211302 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java
@@ -29,10 +29,9 @@
 import org.eclipse.jetty.monitor.jmx.ServiceConnection;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
-/* ------------------------------------------------------------ */
 /**
  * JMXMonitor
- *
+ * <p>
  * Performs monitoring of the values of the attributes of MBeans
  * and executes specified actions as well as sends notifications
  * of the specified events that have occurred.
@@ -120,7 +119,7 @@
      * Retrieves a connection to JMX service
      *
      * @return server connection
-     * @throws IOException
+     * @throws IOException if unable to obtain server connection
      */
     public static MBeanServerConnection getServiceConnection()
         throws IOException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
index 7b974fa..3bbd145 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
@@ -24,8 +24,11 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.jetty.monitor.thread.ThreadMonitorException;
 import org.eclipse.jetty.monitor.thread.ThreadMonitorInfo;
@@ -60,7 +63,7 @@
     /**
      * Instantiates a new thread monitor.
      *
-     * @throws Exception
+     * @throws Exception if unable to instantiate thread monitor
      */
     public ThreadMonitor() throws Exception
     {
@@ -72,7 +75,7 @@
      * Instantiates a new thread monitor.
      *
      * @param intervalMs scan interval
-     * @throws Exception
+     * @throws Exception if unable to instantiate thread monitor
      */
     public ThreadMonitor(int intervalMs) throws Exception
     {
@@ -85,7 +88,7 @@
      *
      * @param intervalMs scan interval
      * @param threshold busy threshold
-     * @throws Exception
+     * @throws Exception if unable to instantiate thread monitor
      */
     public ThreadMonitor(int intervalMs, int threshold) throws Exception
     {
@@ -99,7 +102,7 @@
      * @param intervalMs scan interval
      * @param threshold busy threshold
      * @param depth stack compare depth
-     * @throws Exception
+     * @throws Exception if unable to instantiate thread monitor
      */
     public ThreadMonitor(int intervalMs, int threshold, int depth) throws Exception
     {
@@ -114,7 +117,7 @@
      * @param threshold busy threshold
      * @param depth stack compare depth
      * @param trail length of stack trail
-     * @throws Exception
+     * @throws Exception if unable to instantiate thread monitor
      */
     public ThreadMonitor(int intervalMs, int threshold, int depth, int trail) throws Exception
     {
@@ -321,6 +324,8 @@
                 _runner.join();
             }
             catch (InterruptedException ex) {}
+            
+            _monitorInfo.clear();
         }
     }
 
@@ -424,6 +429,8 @@
             // retrieving a single thread stack trace.
             Map<Thread,StackTraceElement[]> all = Thread.getAllStackTraces();
             
+            Set<Long> newOrUpdatedIds = new HashSet<Long>();
+            
             for (Map.Entry<Thread,StackTraceElement[]> entry : all.entrySet())
             {
                 Thread thread = entry.getKey();
@@ -490,7 +497,18 @@
                         }
                     }
                 }
+                newOrUpdatedIds.add(Long.valueOf(threadId));
             }
+            
+            //clean out threads that no longer exist
+            Iterator<Long> iter = _monitorInfo.keySet().iterator();
+            while (iter.hasNext())
+            {
+                Long id = iter.next();
+                if (!newOrUpdatedIds.contains(id))
+                    iter.remove();
+            }
+            newOrUpdatedIds.clear();
         }
         catch (Exception ex)
         {
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java
index e64d341..46f25a6 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java
@@ -50,10 +50,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 
-
-/* ------------------------------------------------------------ */
-/**
- */
 public class JavaMonitorAction extends MonitorAction
 {
     private static final Logger LOG = Log.getLogger(JavaMonitorAction.class);
@@ -68,12 +64,6 @@
     private String _session;
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param notifier
-     * @param pollInterval
-     * @throws Exception 
-     * @throws MalformedObjectNameException 
-     */
     public JavaMonitorAction(EventNotifier notifier, String url, String uuid, String appid, long pollInterval)
         throws Exception
     {
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java
index f9eeaad..8ad566b 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTools.java
@@ -30,12 +30,11 @@
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.ManagedOperation;
 
-/* ------------------------------------------------------------ */
 /**
  * Derived from the JMX bean classes created by Kees Jan Koster for the java-monitor
  * J2EE probe http://code.google.com/p/java-monitor-probes/source/browse/.
  * 
- * @author kjkoster <kjkoster@gmail.com>
+ * @author <a href="mailto:kjkoster@gmail.com">Kees Jan Koster</a>
  */
 @ManagedObject("Java Monitoring Tools")
 public class JavaMonitorTools
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java
index b241064..1ed92ee 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorTrigger.java
@@ -23,8 +23,8 @@
 import org.eclipse.jetty.monitor.triggers.AttrEventTrigger;
 
 
-/* ------------------------------------------------------------ */
 /**
+ * @param <TYPE> the trigger type
  */
 public class JavaMonitorTrigger <TYPE extends Comparable<TYPE>>
     extends AttrEventTrigger<TYPE>
@@ -35,13 +35,6 @@
     private int _count;
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param nameObject
-     * @param attributeName
-     * @param id
-     * @param dynamic
-     * @throws IllegalArgumentException
-     */
     public JavaMonitorTrigger(ObjectName nameObject, String attributeName, String id, String name, boolean dynamic)
         throws IllegalArgumentException
     {   
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java
index e262b8d..93e611c 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ConsoleNotifier.java
@@ -35,7 +35,7 @@
      * Constructs a new notifier with specified format string
      * 
      * @param format the {@link java.util.Formatter format string}
-     * @throws IllegalArgumentException
+     * @throws IllegalArgumentException if format is invalid
      */
     public ConsoleNotifier(String format)
         throws IllegalArgumentException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java
index d091b37..ad509f3 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventNotifier.java
@@ -31,7 +31,8 @@
     /* ------------------------------------------------------------ */
     /**
      * This method is called when a notification event is received by the containing object
-     *  
+     * 
+     * @param trigger the event trigger 
      * @param state an {@link org.eclipse.jetty.monitor.jmx.EventState event state} 
      * @param timestamp time stamp of the event
      */
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java
index e274a8e..51271bf 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventState.java
@@ -30,6 +30,7 @@
  * 
  * Holds the state of one or more {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger}
  * instances to be used when sending notifications as well as executing the actions
+ * @param <TYPE> the event trigger type
  */
 public class EventState<TYPE>
 {
@@ -39,6 +40,7 @@
      * State
      * 
      * Holds the state of a single {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger}
+     * @param <TYPE> the event trigger type
      */
     public static class TriggerState<TYPE>
     {
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java
index 85ab270..2496f72 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/EventTrigger.java
@@ -58,7 +58,9 @@
      * Abstract method to verify if the event trigger conditions
      * are in the appropriate state for an event to be triggered
      * 
+     * @param timestamp the timestamp to match 
      * @return true to trigger an event
+     * @throws Exception if unable to match
      */
     public abstract boolean match(long timestamp) throws Exception;
 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java
index c9fff8b..b78f7a3 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/LoggingNotifier.java
@@ -40,7 +40,7 @@
      * Constructs a new notifier with specified format string
      * 
      * @param format the {@link java.util.Formatter format string}
-     * @throws IllegalArgumentException
+     * @throws IllegalArgumentException if format is invalid
      */
     public LoggingNotifier(String format)
         throws IllegalArgumentException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java
index 447fdcd..ccf5d8c 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/MonitorAction.java
@@ -45,7 +45,7 @@
      * Creates a new monitor action 
      * 
      * @param trigger event trigger to be associated with this action
-     * @throws InvalidParameterException
+     * @throws InvalidParameterException if trigger is invalid
      */
     public MonitorAction(EventTrigger trigger)
         throws InvalidParameterException
@@ -60,7 +60,7 @@
      * 
      * @param trigger event trigger to be associated with this action
      * @param notifier event notifier to be associated with this action
-     * @throws InvalidParameterException
+     * @throws InvalidParameterException if trigger is invalid
      */
     public MonitorAction(EventTrigger trigger, EventNotifier notifier)
         throws InvalidParameterException
@@ -75,7 +75,7 @@
      * @param trigger event trigger to be associated with this action
      * @param notifier event notifier to be associated with this action
      * @param pollInterval interval for polling of the JMX server
-     * @throws InvalidParameterException
+     * @throws InvalidParameterException if trigger is invalid
      */
     public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval)
         throws InvalidParameterException
@@ -91,7 +91,7 @@
      * @param notifier event notifier to be associated with this action
      * @param pollInterval interval for polling of the JMX server
      * @param pollDelay delay before starting to poll the JMX server
-     * @throws InvalidParameterException
+     * @throws InvalidParameterException if trigger is invalid
      */
     public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval, long pollDelay)
         throws InvalidParameterException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java
index 9d7560c..3c0c5a8 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/jmx/ServiceConnection.java
@@ -54,7 +54,7 @@
     /**
      * Construct a loopback connection to an internal server
      * 
-     * @throws IOException
+     * @throws IOException if unable to construct service connection
      */
     public ServiceConnection()
         throws IOException
@@ -67,7 +67,7 @@
      * Construct a connection to specified server
      * 
      * @param url URL of JMX server
-     * @throws IOException
+     * @throws IOException if unable to construct service connection
      */
     public ServiceConnection(String url)
         throws IOException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java
index a3e195b..7cbe6fe 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AggregateEventTrigger.java
@@ -72,27 +72,18 @@
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param trigger
-     */
     public void add(EventTrigger trigger)
     {
         _triggers.add(trigger);
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param triggers
-     */
     public void addAll(List<EventTrigger> triggers)
     {
         _triggers.addAll(triggers);
     }
         
     /* ------------------------------------------------------------ */
-    /**
-     * @param triggers
-     */
     public void addAll(EventTrigger... triggers)
     {
         _triggers.addAll(Arrays.asList(triggers));
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java
index 4a5cae4..a362c9c 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/AttrEventTrigger.java
@@ -32,11 +32,9 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-
-/* ------------------------------------------------------------ */
 /**
  * AttrEventTrigger
- * 
+ * <p>
  * Event trigger that polls a value of an MXBean attribute
  * and matches every invocation of this trigger. It can be
  * used to send notifications of the value of an attribute
@@ -44,6 +42,7 @@
  * a base class for the event triggers that match the 
  * value of an attribute of the MXBean being polled against
  * some specified criteria.
+ * @param <TYPE> the event trigger type
  */
 public class AttrEventTrigger<TYPE extends Comparable<TYPE>> 
     extends EventTrigger
@@ -64,8 +63,8 @@
      * @param objectName object name of an MBean to be polled
      * @param attributeName name of an MBean attribute to be polled
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException if unable to find object due to malformed name reference
+     * @throws IllegalArgumentException if parameters are invalid
      */
     public AttrEventTrigger(String objectName, String attributeName)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -91,7 +90,7 @@
      * @param nameObject object name of an MBean to be polled
      * @param attributeName name of an MBean attribute to be polled
      * 
-     * @throws IllegalArgumentException
+     * @throws IllegalArgumentException if parameters are invalid
      */
     public AttrEventTrigger(ObjectName nameObject, String attributeName)
         throws IllegalArgumentException
@@ -113,7 +112,7 @@
     /**
      * Verify if the event trigger conditions are in the 
      * appropriate state for an event to be triggered.
-     * This event trigger uses the match(Comparable<TYPE>)
+     * This event trigger uses the match(Comparable&lt;TYPE&gt;)
      * method to compare the value of the MXBean attribute
      * to the conditions specified by the subclasses.
      * 
@@ -162,6 +161,8 @@
      * appropriate state for an event to be triggered.
      * Allows subclasses to override the default behavior
      * that matches every invocation of this trigger
+     * @param value the value to match
+     * @return always true
      */
     public boolean match(Comparable<TYPE> value)
     {
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java
index 7043a49..8d236a6 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/EqualToAttrEventTrigger.java
@@ -21,12 +21,12 @@
 import javax.management.MalformedObjectNameException;
 
 
-/* ------------------------------------------------------------ */
 /**
  * EqualToAttrEventTrigger
- * 
+ * <p> 
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is equal to specified value. 
+ * @param <TYPE> the event trigger type
  */
 public class EqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -42,8 +42,8 @@
      * @param attributeName name of an MBean attribute to be polled
      * @param value target value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException if unable to find object due to name issue
+     * @throws IllegalArgumentException on invalid parameters
      */
     public EqualToAttrEventTrigger(String objectName, String attributeName, TYPE value)
         throws MalformedObjectNameException, IllegalArgumentException
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java
index 1edddf6..7ad1556 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanAttrEventTrigger.java
@@ -20,13 +20,12 @@
 
 import javax.management.MalformedObjectNameException;
 
-
-/* ------------------------------------------------------------ */
 /**
  * GreaterThanAttrEventTrigger
- * 
+ * <p> 
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is greater than specified min value. 
+ * @param <TYPE> event trigger type
  */
 public class GreaterThanAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -42,8 +41,8 @@
      * @param attributeName name of an MBean attribute to be polled
      * @param min minimum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public GreaterThanAttrEventTrigger(String objectName, String attributeName, TYPE min)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -72,7 +71,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "min<name". 
+     * in the format "min&lt;name". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java
index e24545f..78558a7 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/GreaterThanOrEqualToAttrEventTrigger.java
@@ -20,13 +20,12 @@
 
 import javax.management.MalformedObjectNameException;
 
-
-/* ------------------------------------------------------------ */
 /**
  * GreaterThanOrEqualToAttrEventTrigger
- * 
+ * <p>
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is greater than or equal to specified min value. 
+ * @param <TYPE> event trigger type
  */
 public class GreaterThanOrEqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -42,8 +41,8 @@
      * @param attributeName name of an MBean attribute to be polled
      * @param min minimum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public GreaterThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE min)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -72,7 +71,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "min<=name". 
+     * in the format "min&lt;=name". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java
index c726744..210c35c 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanAttrEventTrigger.java
@@ -20,13 +20,12 @@
 
 import javax.management.MalformedObjectNameException;
 
-
-/* ------------------------------------------------------------ */
 /**
  * LessThanAttrEventTrigger
- * 
+ * <p>
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is greater than specified max value. 
+ * @param <TYPE> event trigger type
  */
 public class LessThanAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -42,8 +41,8 @@
      * @param attributeName name of an MBean attribute to be polled
      * @param max maximum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public LessThanAttrEventTrigger(String objectName, String attributeName, TYPE max)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -72,7 +71,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "name<max". 
+     * in the format "name&lt;max". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java
index 7e36d44..e5988cb 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/LessThanOrEqualToAttrEventTrigger.java
@@ -21,12 +21,12 @@
 import javax.management.MalformedObjectNameException;
 
 
-/* ------------------------------------------------------------ */
 /**
  * LessThanOrEqualToAttrEventTrigger
- * 
+ * <p> 
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is less than or equal to specified max value. 
+ * @param <TYPE> event trigger type 
  */
 public class LessThanOrEqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -42,8 +42,8 @@
      * @param attributeName name of an MBean attribute to be polled
      * @param max maximum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public LessThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE max)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -72,7 +72,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "name<=max". 
+     * in the format "name&lt;=max". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java
index 65da9bd..b9be08b 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeAttrEventTrigger.java
@@ -20,14 +20,13 @@
 
 import javax.management.MalformedObjectNameException;
 
-
-/* ------------------------------------------------------------ */
 /**
  * RangeAttrEventTrigger
- * 
+ * <p> 
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is in a range from specified min value to
  * specified max value. 
+ * @param <TYPE> event trigger type
  */
 public class RangeAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -45,8 +44,8 @@
      * @param min minimum value of the attribute
      * @param max maximum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public RangeAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -79,7 +78,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "min<name<max". 
+     * in the format "min&lt;name&lt;max". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java
index ce29d35..9d5945b 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/triggers/RangeInclAttrEventTrigger.java
@@ -20,14 +20,13 @@
 
 import javax.management.MalformedObjectNameException;
 
-
-/* ------------------------------------------------------------ */
 /**
  * RangeInclAttrEventTrigger
- * 
+ * <p>
  * Event trigger that polls a value of an MXBean attribute and
  * checks if it is in a range from specified min value to
  * specified max value including the range bounds. 
+ * @param <TYPE> event trigger type
  */
 public class RangeInclAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
 {
@@ -45,8 +44,8 @@
      * @param min minimum value of the attribute
      * @param max maximum value of the attribute
      * 
-     * @throws MalformedObjectNameException
-     * @throws IllegalArgumentException
+     * @throws MalformedObjectNameException on bad object name
+     * @throws IllegalArgumentException on bad parameters
      */
     public RangeInclAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max)
         throws MalformedObjectNameException, IllegalArgumentException
@@ -79,7 +78,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the string representation of this event trigger
-     * in the format "min<=name<=max". 
+     * in the format "min&lt;=name&lt;=max". 
      * 
      * @return string representation of the event trigger
      * 
diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml
index 10bc138..dceec07 100644
--- a/jetty-nosql/pom.xml
+++ b/jetty-nosql/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-nosql</artifactId>
@@ -14,57 +14,6 @@
   <build>
     <defaultGoal>install</defaultGoal>
     <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <configuration>
-          <instructions>
-            <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.server.session.jmx;version="9.1";resolution:=optional,,org.eclipse.jetty.*;version="9.1",*</Import-Package>
-          </instructions>
-        </configuration>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
     </plugins>
   </build>
   <dependencies>
diff --git a/jetty-nosql/src/main/config/etc/jetty-nosql.xml b/jetty-nosql/src/main/config/etc/jetty-nosql.xml
new file mode 100644
index 0000000..ee1ebd1
--- /dev/null
+++ b/jetty-nosql/src/main/config/etc/jetty-nosql.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- ===================================================================== -->
+  <!-- Configure a MongoSessionIdManager                                     -->
+  <!-- ===================================================================== -->
+  <Set name="sessionIdManager">
+    <New id="sessionIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
+      <Arg>
+        <Ref refid="Server"/>
+      </Arg>
+      <Set name="workerName"><Property name="jetty.nosqlSession.workerName" default="node1"/></Set>
+      <Set name="scavengePeriod"><Property name="jetty.nosqlSession.scavenge" default="1800"/></Set>
+    </New>
+  </Set>
+
+</Configure>
diff --git a/jetty-nosql/src/main/config/modules/nosql.mod b/jetty-nosql/src/main/config/modules/nosql.mod
index a4189c9..a5b5a9e 100644
--- a/jetty-nosql/src/main/config/modules/nosql.mod
+++ b/jetty-nosql/src/main/config/modules/nosql.mod
@@ -1,9 +1,31 @@
 #
-# Jetty Nosql module
+# Jetty NoSql module
 #
 
 [depend]
 webapp
 
+[files]
+maven://org.mongodb/mongo-java-driver/2.6.1|lib/nosql/mongo-java-driver-2.6.1.jar
+
 [lib]
-lib/jetty-nosql-${jetty.version}.jar
\ No newline at end of file
+lib/jetty-nosql-${jetty.version}.jar
+lib/nosql/*.jar
+
+[xml]
+etc/jetty-nosql.xml
+
+[license]
+The java driver for the MongoDB document-based database system is hosted on GitHub and released under the Apache 2.0 license.
+http://www.mongodb.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini-template]
+## MongoDB SessionIdManager config
+
+## Unique identifier for this node in the cluster
+# jetty.nosqlSession.workerName=node1
+
+## Interval in seconds between scavenging expired sessions
+# jetty.nosqlSession.scavenge=1800
+
diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java
index 10ed78c..137d238 100644
--- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java
+++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java
@@ -35,7 +35,6 @@
  * NoSqlSessionManager
  *
  * Base class for SessionManager implementations using nosql frameworks
- * 
  */
 public abstract class NoSqlSessionManager extends AbstractSessionManager implements SessionManager
 {
@@ -241,7 +240,7 @@
      * The State Period is the maximum time in seconds that an in memory session is allows to be stale:
      * <ul>  
      * <li>If this period is exceeded, the DB will be checked to see if a more recent version is available.</li>
-     * <li>If the state period is set to a value < 0, then no staleness check will be made.</li>
+     * <li>If the state period is set to a value &lt; 0, then no staleness check will be made.</li>
      * <li>If the state period is set to 0, then a staleness check is made whenever the active request count goes from 0 to 1.</li>
      * </ul>
      * @return the stalePeriod in seconds
@@ -256,7 +255,7 @@
      * The State Period is the maximum time in seconds that an in memory session is allows to be stale:
      * <ul>  
      * <li>If this period is exceeded, the DB will be checked to see if a more recent version is available.</li>
-     * <li>If the state period is set to a value < 0, then no staleness check will be made.</li>
+     * <li>If the state period is set to a value &lt; 0, then no staleness check will be made.</li>
      * <li>If the state period is set to 0, then a staleness check is made whenever the active request count goes from 0 to 1.</li>
      * </ul>
      * @param stalePeriod the stalePeriod in seconds
@@ -274,9 +273,9 @@
      * <li>a save period of -1 means the session is never saved to the DB other than on a shutdown</li>
      * <li>a save period of 0 means the session is written to the DB whenever the active request count goes from 1 to 0.</li>
      * <li>a save period of 1 means the session is written to the DB whenever the active request count goes from 1 to 0 and the session is dirty.</li>
-     * <li>a save period of > 1 means the session is written after that period in seconds of being dirty.</li>
+     * <li>a save period of &gt; 1 means the session is written after that period in seconds of being dirty.</li>
      * </ul>
-     * @return the savePeriod -2,-1,0,1 or the period in seconds >=2 
+     * @return the savePeriod -2,-1,0,1 or the period in seconds &gt;=2 
      */
     public int getSavePeriod()
     {
@@ -291,9 +290,9 @@
      * <li>a save period of -1 means the session is never saved to the DB other than on a shutdown</li>
      * <li>a save period of 0 means the session is written to the DB whenever the active request count goes from 1 to 0.</li>
      * <li>a save period of 1 means the session is written to the DB whenever the active request count goes from 1 to 0 and the session is dirty.</li>
-     * <li>a save period of > 1 means the session is written after that period in seconds of being dirty.</li>
+     * <li>a save period of &gt; 1 means the session is written after that period in seconds of being dirty.</li>
      * </ul>
-     * @param savePeriod the savePeriod -2,-1,0,1 or the period in seconds >=2 
+     * @param savePeriod the savePeriod -2,-1,0,1 or the period in seconds &gt;=2 
      */
     public void setSavePeriod(int savePeriod)
     {
@@ -304,7 +303,7 @@
     /**
      * The Idle Period is the time in seconds before an in memory session is passivated.
      * When this period is exceeded, the session will be passivated and removed from memory.  If the session was dirty, it will be written to the DB.
-     * If the idle period is set to a value < 0, then the session is never idled.
+     * If the idle period is set to a value &lt; 0, then the session is never idled.
      * If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0.
      * @return the idlePeriod
      */
@@ -317,7 +316,7 @@
     /**
      * The Idle Period is the time in seconds before an in memory session is passivated.
      * When this period is exceeded, the session will be passivated and removed from memory.  If the session was dirty, it will be written to the DB.
-     * If the idle period is set to a value < 0, then the session is never idled.
+     * If the idle period is set to a value &lt; 0, then the session is never idled.
      * If the save period is set to 0, then the session is idled whenever the active request count goes from 1 to 0.
      * @param idlePeriod the idlePeriod in seconds
      */
@@ -359,7 +358,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Preserve sessions when the session manager is stopped otherwise remove them from the DB.
-     * @param removeOnStop the removeOnStop to set
+     * @param preserveOnStop the preserveOnStop to set
      */
     public void setPreserveOnStop(boolean preserveOnStop)
     {
diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java
index 5bc7b83..e078b9a 100644
--- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java
+++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionIdManager.java
@@ -21,6 +21,7 @@
 
 import java.net.UnknownHostException;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -34,6 +35,7 @@
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.session.AbstractSessionIdManager;
 import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
@@ -49,13 +51,13 @@
 
 /**
  * Based partially on the JDBCSessionIdManager.
- *
+ * <p>
  * Theory is that we really only need the session id manager for the local 
  * instance so we have something to scavenge on, namely the list of known ids
- * 
+ * <p>
  * This class has a timer that runs a periodic scavenger thread to query
  *  for all id's known to this node whose precalculated expiry time has passed.
- *  
+ * <p>
  * These found sessions are then run through the invalidateAll(id) method that 
  * is a bit hinky but is supposed to notify all handlers this id is now DOA and 
  * ought to be cleaned up.  this ought to result in a save operation on the session
@@ -109,10 +111,15 @@
     
     /**
      * the collection of session ids known to this manager
-     * 
-     * TODO consider if this ought to be concurrent or not
      */
-    protected final Set<String> _sessionsIds = new HashSet<String>();
+    protected final Set<String> _sessionsIds = new ConcurrentHashSet<>();
+
+    /**
+     * The maximum number of items to return from a purge query.
+     */
+    private int _purgeLimit = 0;
+
+    private int _scavengeBlockSize;
     
     
     /**
@@ -182,6 +189,12 @@
                 BasicDBObjectBuilder.start().add("id",1).add("version",1).get(),
                 BasicDBObjectBuilder.start().add("unique",true).add("sparse",false).get());
 
+        // index our accessed and valid fields so that purges are faster, note that the "valid" field is first
+        // so that we can take advantage of index prefixes
+        // http://docs.mongodb.org/manual/core/index-compound/#compound-index-prefix
+        _sessions.ensureIndex(
+                BasicDBObjectBuilder.start().add(MongoSessionManager.__VALID, 1).add(MongoSessionManager.__ACCESSED, 1).get(),
+                BasicDBObjectBuilder.start().add("sparse", false).add("background", true).get());
     }
  
     /* ------------------------------------------------------------ */
@@ -194,29 +207,60 @@
     {
         long now = System.currentTimeMillis();
         __log.debug("SessionIdManager:scavenge:at {}", now);        
-        synchronized (_sessionsIds)
-        {         
-            /*
-             * run a query returning results that:
-             *  - are in the known list of sessionIds
-             *  - the expiry time has passed
-             *  
-             *  we limit the query to return just the __ID so we are not sucking back full sessions
-             */
-            BasicDBObject query = new BasicDBObject();     
-            query.put(MongoSessionManager.__ID,new BasicDBObject("$in", _sessionsIds ));
-            query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$gt", 0));
-            query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$lt", now));
-        
+        /*
+         * run a query returning results that:
+         *  - are in the known list of sessionIds
+         *  - the expiry time has passed
+         *  
+         *  we limit the query to return just the __ID so we are not sucking back full sessions
+         *  
+         *  break scavenge query into blocks for faster mongo queries
+         */
+        Set<String> block = new HashSet<String>();
             
-            DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1));
-                        
-            for ( DBObject session : checkSessions )
-            {             
-                __log.debug("SessionIdManager:scavenge: expiring session {}", (String)session.get(MongoSessionManager.__ID));
-                expireAll((String)session.get(MongoSessionManager.__ID));
+        Iterator<String> itor = _sessionsIds.iterator();
+        while (itor.hasNext())
+        {
+            block.add(itor.next());
+            if ((_scavengeBlockSize > 0) && (block.size() == _scavengeBlockSize))
+            {
+                //got a block
+                scavengeBlock (now, block);
+                //reset for next run
+                block.clear();
             }
-        }      
+        }
+        
+        //non evenly divisble block size, or doing it all at once
+        if (!block.isEmpty())
+            scavengeBlock(now, block);
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Check a block of session ids for expiry and thus scavenge.
+     * 
+     * @param atTime purge at time
+     * @param ids set of session ids
+     */
+    protected void scavengeBlock (long atTime, Set<String> ids)
+    {
+        if (ids == null)
+            return;
+        
+        BasicDBObject query = new BasicDBObject();     
+        query.put(MongoSessionManager.__ID,new BasicDBObject("$in", ids ));
+        query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$gt", 0));
+        query.put(MongoSessionManager.__EXPIRY, new BasicDBObject("$lt", atTime));   
+            
+        DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1));
+                        
+        for ( DBObject session : checkSessions )
+        {             
+            __log.debug("SessionIdManager:scavenge: expiring session {}", (String)session.get(MongoSessionManager.__ID));
+            expireAll((String)session.get(MongoSessionManager.__ID));
+        }            
     }
     
     /* ------------------------------------------------------------ */
@@ -262,11 +306,16 @@
         __log.debug("PURGING");
         BasicDBObject invalidQuery = new BasicDBObject();
 
-        invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge));
         invalidQuery.put(MongoSessionManager.__VALID, false);
+        invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge));
         
         DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
 
+        if (_purgeLimit > 0)
+        {
+            oldSessions.limit(_purgeLimit);
+        }
+
         for (DBObject session : oldSessions)
         {
             String id = (String)session.get("id");
@@ -280,11 +329,16 @@
         {
             BasicDBObject validQuery = new BasicDBObject();
 
-            validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge));
             validQuery.put(MongoSessionManager.__VALID, true);
+            validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge));
 
             oldSessions = _sessions.find(validQuery,new BasicDBObject(MongoSessionManager.__ID,1));
 
+            if (_purgeLimit > 0)
+            {
+                oldSessions.limit(_purgeLimit);
+            }
+
             for (DBObject session : oldSessions)
             {
                 String id = (String)session.get(MongoSessionManager.__ID);
@@ -346,7 +400,7 @@
     /** 
      * The period in seconds between scavenge checks.
      * 
-     * @param scavengePeriod
+     * @param scavengePeriod the scavenge period in seconds
      */
     public void setScavengePeriod(long scavengePeriod)
     {
@@ -357,6 +411,42 @@
     }
 
     /* ------------------------------------------------------------ */
+    /** When scavenging, the max number of session ids in the query.
+     * 
+     * @param size the scavenge block size
+     */
+    public void setScavengeBlockSize (int size)
+    {
+        _scavengeBlockSize = size;
+    }
+
+    /* ------------------------------------------------------------ */
+    public int getScavengeBlockSize ()
+    {
+        return _scavengeBlockSize;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * The maximum number of items to return from a purge query. If &lt;= 0 there is no limit. Defaults to 0
+     * 
+     * @param purgeLimit the purge limit 
+     */
+    public void setPurgeLimit(int purgeLimit)
+    {
+        _purgeLimit = purgeLimit;
+    }
+
+    /* ------------------------------------------------------------ */
+    public int getPurgeLimit()
+    {
+        return _purgeLimit;
+    }
+
+
+
+    /* ------------------------------------------------------------ */
     public void setPurgeDelay(long purgeDelay)
     {
         if ( isRunning() )
@@ -377,6 +467,7 @@
     /**
      * sets how old a session is to be persisted past the point it is
      * no longer valid
+     * @param purgeValidAge the purge valid age
      */
     public void setPurgeInvalidAge(long purgeValidAge)
     {
@@ -395,6 +486,7 @@
      * considered no longer viable and should be removed
      * 
      * NOTE: set this value to 0 to disable purging of valid sessions
+     * @param purgeValidAge the purge valid age
      */
     public void setPurgeValidAge(long purgeValidAge)
     {
@@ -520,10 +612,7 @@
         
         __log.debug("MongoSessionIdManager:addSession {}", session.getId());
         
-        synchronized (_sessionsIds)
-        {
-            _sessionsIds.add(session.getId());
-        }
+        _sessionsIds.add(session.getId());
         
     }
 
@@ -536,10 +625,7 @@
             return;
         }
         
-        synchronized (_sessionsIds)
-        {
-            _sessionsIds.remove(session.getId());
-        }
+        _sessionsIds.remove(session.getId());
     }
 
     /* ------------------------------------------------------------ */
@@ -551,56 +637,51 @@
     @Override
     public void invalidateAll(String sessionId)
     {
-        synchronized (_sessionsIds)
+        _sessionsIds.remove(sessionId);
+            
+        //tell all contexts that may have a session object with this id to
+        //get rid of them
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
         {
-            _sessionsIds.remove(sessionId);
-                
-            //tell all contexts that may have a session object with this id to
-            //get rid of them
-            Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
-            for (int i=0; contexts!=null && i<contexts.length; i++)
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null) 
             {
-                SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
-                if (sessionHandler != null) 
-                {
-                    SessionManager manager = sessionHandler.getSessionManager();
+                SessionManager manager = sessionHandler.getSessionManager();
 
-                    if (manager != null && manager instanceof MongoSessionManager)
-                    {
-                        ((MongoSessionManager)manager).invalidateSession(sessionId);
-                    }
+                if (manager != null && manager instanceof MongoSessionManager)
+                {
+                    ((MongoSessionManager)manager).invalidateSession(sessionId);
                 }
             }
-        }      
-    } 
+        }
+    }      
+ 
 
     /* ------------------------------------------------------------ */
     /**
      * Expire this session for all contexts that are sharing the session 
      * id.
-     * @param sessionId
+     * @param sessionId the session id
      */
     public void expireAll (String sessionId)
     {
-        synchronized (_sessionsIds)
+        _sessionsIds.remove(sessionId);
+            
+            
+        //tell all contexts that may have a session object with this id to
+        //get rid of them
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
         {
-            _sessionsIds.remove(sessionId);
-            
-            
-            //tell all contexts that may have a session object with this id to
-            //get rid of them
-            Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
-            for (int i=0; contexts!=null && i<contexts.length; i++)
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null) 
             {
-                SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
-                if (sessionHandler != null) 
-                {
-                    SessionManager manager = sessionHandler.getSessionManager();
+                SessionManager manager = sessionHandler.getSessionManager();
 
-                    if (manager != null && manager instanceof MongoSessionManager)
-                    {
-                        ((MongoSessionManager)manager).expire(sessionId);
-                    }
+                if (manager != null && manager instanceof MongoSessionManager)
+                {
+                    ((MongoSessionManager)manager).expire(sessionId);
                 }
             }
         }      
@@ -613,24 +694,21 @@
         //generate a new id
         String newClusterId = newSessionId(request.hashCode());
 
-        synchronized (_sessionsIds)
+        _sessionsIds.remove(oldClusterId);//remove the old one from the list
+        _sessionsIds.add(newClusterId); //add in the new session id to the list
+
+        //tell all contexts to update the id 
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
         {
-            _sessionsIds.remove(oldClusterId);//remove the old one from the list
-            _sessionsIds.add(newClusterId); //add in the new session id to the list
-
-            //tell all contexts to update the id 
-            Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
-            for (int i=0; contexts!=null && i<contexts.length; i++)
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null) 
             {
-                SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
-                if (sessionHandler != null) 
-                {
-                    SessionManager manager = sessionHandler.getSessionManager();
+                SessionManager manager = sessionHandler.getSessionManager();
 
-                    if (manager != null && manager instanceof MongoSessionManager)
-                    {
-                        ((MongoSessionManager)manager).renewSessionId(oldClusterId, oldNodeId, newClusterId, getNodeId(newClusterId, request));
-                    }
+                if (manager != null && manager instanceof MongoSessionManager)
+                {
+                    ((MongoSessionManager)manager).renewSessionId(oldClusterId, oldNodeId, newClusterId, getNodeId(newClusterId, request));
                 }
             }
         }
diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java
index 8f57902..9f257a9 100644
--- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java
+++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionManager.java
@@ -43,12 +43,11 @@
 import com.mongodb.DBObject;
 import com.mongodb.MongoException;
 import com.mongodb.WriteConcern;
-import com.mongodb.WriteResult;
 
 
 /**
  * MongoSessionManager
- *
+ * <p>
  * Clustered session manager using MongoDB as the shared DB instance.
  * The document model is an outer object that contains the elements:
  * <ul>
@@ -70,7 +69,7 @@
  * </p>
  * <p>
  * For example:
- * <code>
+ * <pre>
  * { "_id"       : ObjectId("52845534a40b66410f228f23"), 
  *    "accessed" :  NumberLong("1384818548903"), 
  *    "maxIdle"  : 1,
@@ -86,14 +85,12 @@
  *    "id"       : "w01ijx2vnalgv1sqrpjwuirprp7", 
  *    "valid"    : true 
  * }
- * </code>
- * </p>
+ * </pre>
  * <p>
  * In MongoDB, the nesting level is indicated by "." separators for the key name. Thus to
  * interact with a session attribute, the key is composed of:
- * "context".unique_context_name.attribute_name
- *  Eg  "context"."::/contextA"."A"
- *  </p>
+ * <code>"context".unique_context_name.attribute_name</code>
+ *  Eg  <code>"context"."::/contextA"."A"</code>
  */
 @ManagedObject("Mongo Session Manager")
 public class MongoSessionManager extends NoSqlSessionManager
@@ -706,6 +703,7 @@
      * 
      * the count() operation itself is optimized to perform on the server side
      * and avoid loading to client side.
+     * @return the session store count
      */
     @ManagedAttribute("total number of known sessions in the store")
     public long getSessionStoreCount()
diff --git a/jetty-osgi/jetty-osgi-alpn/pom.xml b/jetty-osgi/jetty-osgi-alpn/pom.xml
index 54df720..621f3d1 100644
--- a/jetty-osgi/jetty-osgi-alpn/pom.xml
+++ b/jetty-osgi/jetty-osgi-alpn/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-osgi-alpn</artifactId>
@@ -30,21 +30,26 @@
         </executions>
       </plugin>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
-          <archive>
-            <manifestEntries>
-              <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
+            <instructions>
               <Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
               <Bundle-Name>Jetty OSGi ALPN Fragment</Bundle-Name>
-              <Bundle-Version>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}</Bundle-Version>
+              <Import-Package>!javax.*;!org.eclipse.jetty.*</Import-Package>
               <Export-Package>org.eclipse.jetty.alpn;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
               <Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
-            </manifestEntries>
-          </archive>
+            </instructions>
         </configuration>
       </plugin>
     </plugins>
   </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.eclipse.jetty.alpn</groupId>
+      <artifactId>alpn-api</artifactId>
+      <version>${alpn.api.version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
 </project>
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml
index 34c1f37..5b75afa 100644
--- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml
+++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-osgi-boot-jsp</artifactId>
@@ -42,28 +42,7 @@
       <artifactId>apache-jsp</artifactId>
       <version>${project.version}</version>
     </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.orbit</groupId>
-      <artifactId>javax.servlet.jsp.jstl</artifactId>
-    </dependency>
-   <dependency>
-       <groupId>org.glassfish.web</groupId>
-       <artifactId>javax.servlet.jsp.jstl</artifactId>
-    </dependency>
-   <dependency>
-       <groupId>org.mortbay.jasper</groupId>
-       <artifactId>apache-el</artifactId>
-       <version>8.0.9.M3</version>
-    </dependency>
   </dependencies>
-<!--
-   <dependency>
-       <groupId>javax.el</groupId>
-       <artifactId>javax.el-api</artifactId>
-       <version>3.0.0</version>
-    </dependency>
-  </dependencies>
--->
 
   <build>
     <plugins>
@@ -94,15 +73,6 @@
           <groupId>org.apache.felix</groupId>
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
-          <executions>
-              <execution>
-                  <id>bundle-manifest</id>
-                  <phase>process-classes</phase>
-                  <goals>
-                      <goal>manifest</goal>
-                  </goals>
-              </execution>
-          </executions>
           <configuration>
               <instructions>
                 <Bundle-Name>Jetty-OSGi-Jasper Integration</Bundle-Name>
@@ -110,6 +80,7 @@
                 <Fragment-Host>org.eclipse.jetty.osgi.boot</Fragment-Host>
                 <Export-Package>!org.eclipse.jetty.osgi.boot.*</Export-Package>
                 <Import-Package>org.eclipse.jdt.*;resolution:=optional,
+                                org.eclipse.jdt.core.compiler.*;resolution:=optional,
                 com.sun.el;resolution:=optional,
  com.sun.el.lang;resolution:=optional,
  com.sun.el.parser;resolution:=optional,
@@ -125,20 +96,20 @@
  javax.servlet.jsp.jstl.fmt;version="1.2";resolution:=optional,
  javax.servlet.jsp.jstl.sql;version="1.2";resolution:=optional,
  javax.servlet.jsp.jstl.tlv;version="1.2";resolution:=optional,
- org.apache.el;version="[8.0.9,9)";resolution:=optional,
- org.apache.el.lang;version="[8.0.9,9)";resolution:=optional,
- org.apache.el.stream;version="[8.0.9,9)";resolution:=optional,
- org.apache.el.util;version="[8.0.9,9)";resolution:=optional,
- org.apache.el.parser;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.compiler;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.compiler.tagplugin;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.runtime;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.security;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.servlet;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.tagplugins.jstl;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.util;version="[8.0.9,9)";resolution:=optional,
- org.apache.jasper.xmlparser;version="[8.0.9,9)";resolution:=optional,
+ org.apache.el;version="[8.0.23,9)";resolution:=optional,
+ org.apache.el.lang;version="[8.0.23,9)";resolution:=optional,
+ org.apache.el.stream;version="[8.0.23,9)";resolution:=optional,
+ org.apache.el.util;version="[8.0.23,9)";resolution:=optional,
+ org.apache.el.parser;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.compiler;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.compiler.tagplugin;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.runtime;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.security;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.servlet;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.tagplugins.jstl;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.util;version="[8.0.23,9)";resolution:=optional,
+ org.apache.jasper.xmlparser;version="[8.0.23,9)";resolution:=optional,
  org.apache.taglibs.standard;version="1.2";resolution:=optional,
  org.apache.taglibs.standard.extra.spath;version="1.2";resolution:=optional,
  org.apache.taglibs.standard.functions;version="1.2";resolution:=optional,
@@ -162,8 +133,8 @@
  org.apache.taglibs.standard.tag.rt.xml;version="1.2";resolution:=optional,
  org.apache.taglibs.standard.tei;version="1.2";resolution:=optional,
  org.apache.taglibs.standard.tlv;version="1.2";resolution:=optional,
- org.apache.tomcat;version="[8.0.9,9)";resolution:=optional,
- org.eclipse.jetty.jsp;version="[9.2,10)";resolution:=optional,
+ org.apache.tomcat;version="[8.0.23,9)";resolution:=optional,
+ org.eclipse.jetty.jsp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:=optional,
  org.osgi.*,
  org.xml.*;resolution:=optional,
  org.xml.sax.*;resolution:=optional,
@@ -172,8 +143,7 @@
  org.w3c.dom.ls;resolution:=optional,
  javax.xml.parser;resolution:=optional
  </Import-Package>
-               <_nouses>true</_nouses>
-               <DynamicImport-Package>org.eclipse.jetty.jsp.*;version="9.2.6",org.apache.jasper.*;version="8.0.9",org.apache.el.*;version="8.0.9"</DynamicImport-Package>
+               <DynamicImport-Package>org.eclipse.jetty.jsp.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",org.apache.jasper.*;version="8.0.23",org.apache.el.*;version="8.0.23"</DynamicImport-Package>
               </instructions>
           </configuration>
       </plugin>
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
index d148e37..6e6185e 100644
--- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
+++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
@@ -19,19 +19,13 @@
 package org.eclipse.jetty.osgi.boot.jasper;
 
 import java.io.File;
-import java.io.InputStream;
-import java.lang.reflect.Field;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 
-import javax.servlet.Servlet;
-import javax.servlet.jsp.JspContext;
 import javax.servlet.jsp.JspFactory;
 
-import org.apache.jasper.Constants;
-import org.apache.jasper.compiler.Localizer;
 import org.eclipse.jetty.deploy.DeploymentManager;
 import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
@@ -40,9 +34,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.FrameworkUtil;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 
 /**
  * 
@@ -68,17 +59,7 @@
      */
     private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
 
-    // used to be "org.apache.jasper.runtime.JspFactoryImpl" but now
-    // the standard tag library implementation are stored in a separate bundle.
-
-    // DISABLED please use the tld bundle argument for the OSGiAppProvider
-    // /**
-    // * Default name of a class that belongs to the bundle where the Java
-    // server Faces tld files are defined.
-    // * This is the sun's reference implementation.
-    // */
-    // private static String DEFAUT_JSF_IMPL_CLASS =
-    // "com.sun.faces.config.ConfigureListener";
+ 
 
     /**
      * Default jsp factory implementation. Idally jasper is osgified and we can
@@ -91,8 +72,6 @@
 
     public JSTLBundleDiscoverer()
     {
-        //fixupDtdResolution();
-
         try
         {
             // sanity check:
@@ -168,8 +147,6 @@
             Bundle tldBundle = FrameworkUtil.getBundle(jstlClass);
             File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle);
             
-            System.err.println("jstl bundle: "+tldBundle);
-            System.err.println("jstl bundle location: "+tldBundleLocation);
             if (tldBundleLocation != null && tldBundleLocation.isDirectory())
             {
                 // try to find the jar files inside this folder
@@ -177,7 +154,6 @@
                 {
                     if (f.getName().endsWith(".jar") && f.isFile())
                     {
-                        System.err.println("Tld jar in dir: "+f.toURI());
                         urls.add(f.toURI().toURL());
                     }
                     else if (f.isDirectory() && f.getName().equals("lib"))
@@ -186,7 +162,6 @@
                         {
                             if (f2.getName().endsWith(".jar") && f2.isFile())
                             {
-                                System.err.println("Tld jar in lib dir: "+f2.toURI());
                                 urls.add(f2.toURI().toURL());
                             }
                         }
@@ -196,7 +171,6 @@
             }
             else if (tldBundleLocation != null)
             {
-                System.err.println("Tld bundle uri: "+tldBundleLocation.toURI());
                 urls.add(tldBundleLocation.toURI().toURL());
               
                 String pattern = (String)deployer.getContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern");
@@ -206,90 +180,10 @@
                     pattern += "|"+tldBundle.getSymbolicName();
                     deployer.setContextAttribute("org.eclipse.jetty.server.webapp.containerIncludeBundlePattern", pattern);
                 }
-                System.err.println("PATTERN: "+pattern);
             }
         }
         
         return urls.toArray(new URL[urls.size()]);
     }
 
-    /**
-     * Jasper resolves the dtd when it parses a taglib descriptor. It uses this
-     * code to do that:
-     * ParserUtils.getClass().getResourceAsStream(resourcePath); where
-     * resourcePath is for example:
-     * /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately, the
-     * dtd file is not in the exact same classloader as ParserUtils class and
-     * the dtds are packaged in 2 separate bundles. OSGi does not look in the
-     * dependencies' classloader when a resource is searched.
-     * <p>
-     * The workaround consists of setting the entity resolver. That is a patch
-     * added to the version of glassfish-jasper-jetty. IT is also present in the
-     * latest version of glassfish jasper. Could not use introspection to set
-     * new value on a static friendly field :(
-     * </p>
-     */
-   void fixupDtdResolution()
-    {
-        try
-        {
-           // ParserUtils.setEntityResolver(new MyFixedupEntityResolver());
-         
-
-        }
-        catch (Exception e)
-        {
-            e.printStackTrace();
-        }
-
-    }
-
-    /**
-     * Instead of using the ParserUtil's classloader, we use a class that is
-     * indeed next to the resource for sure.
-     */
-    //static class MyFixedupEntityResolver implements EntityResolver
-    //{
-        /**
-         * Same values than in ParserUtils...
-         */
-      /*  static final String[] CACHED_DTD_PUBLIC_IDS = { Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
-                                                       Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, };
-
-        static final String[] CACHED_DTD_RESOURCE_PATHS = { Constants.TAGLIB_DTD_RESOURCE_PATH_11, Constants.TAGLIB_DTD_RESOURCE_PATH_12,
-                                                           Constants.WEBAPP_DTD_RESOURCE_PATH_22, Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
-
-        static final String[] CACHED_SCHEMA_RESOURCE_PATHS = { Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20, Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
-                                                              Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24, Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25, };*/
-
-      /*  public InputSource resolveEntity(String publicId, String systemId) throws SAXException
-        {
-            for (int i = 0; i < CACHED_DTD_PUBLIC_IDS.length; i++)
-            {
-                String cachedDtdPublicId = CACHED_DTD_PUBLIC_IDS[i];
-                if (cachedDtdPublicId.equals(publicId))
-                {
-                    String resourcePath = CACHED_DTD_RESOURCE_PATHS[i];
-                    InputStream input = null;
-                    input = Servlet.class.getResourceAsStream(resourcePath);
-                    if (input == null)
-                    {
-                        input = JspContext.class.getResourceAsStream(resourcePath);
-                        if (input == null)
-                        {*/
-                            // if that failed try again with the original code:
-                            // although it is likely not changed.
-                   /*         input = this.getClass().getResourceAsStream(resourcePath);
-                      }
-                    }
-                    if (input == null) { throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound", resourcePath)); }
-                    InputSource isrc = new InputSource(input);
-                    return isrc;
-                }
-            }
-
-            return null;
-        }
-    }*/
-
 }
diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml
index 7561df8..b5b69b5 100644
--- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml
+++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -53,15 +53,6 @@
           <groupId>org.apache.felix</groupId>
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
-          <executions>
-              <execution>
-                  <id>bundle-manifest</id>
-                  <phase>process-classes</phase>
-                  <goals>
-                      <goal>manifest</goal> 
-                  </goals>
-              </execution>
-          </executions>
           <configuration>
               <instructions>
                   <Bundle-Name>RFC66 War URL</Bundle-Name>
diff --git a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java
index 67dbec7..60f0ff8 100644
--- a/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java
+++ b/jetty-osgi/jetty-osgi-boot-warurl/src/main/java/org/eclipse/jetty/osgi/boot/warurl/internal/WarBundleManifestGenerator.java
@@ -259,7 +259,7 @@
         {
             poundIndex = url.length();
         }
-        UrlEncoded.decodeUtf8To(url.getBytes(), questionMarkIndex+1,
+        UrlEncoded.decodeUtf8To(url, questionMarkIndex+1,
                     poundIndex - questionMarkIndex - 1, res);
         return res;
     }
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml
index b03a648..19b3a5d 100644
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-deployer.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
new file mode 100644
index 0000000..319ae6c
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- Configure the Jetty Server instance with an ID "Server"       -->
+<!-- by adding a HTTP connector.                                   -->
+<!-- This configuration must be used in conjunction with jetty.xml -->
+<!-- ============================================================= -->
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- =========================================================== -->
+  <!-- Add a HTTP Connector.                                       -->
+  <!-- Configure an o.e.j.server.ServerConnector with a single     -->
+  <!-- HttpConnectionFactory instance using the common httpConfig  -->
+  <!-- instance defined in jetty.xml                               -->
+  <!--                                                             -->
+  <!-- Consult the javadoc of o.e.j.server.ServerConnector and     -->
+  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
+  <!-- that may be set here.                                       -->
+  <!-- =========================================================== -->
+  <Call name="addConnector">
+    <Arg>
+      <New class="org.eclipse.jetty.server.ServerConnector">
+        <Arg name="server"><Ref refid="Server" /></Arg>
+        <Arg name="factories">
+          <Array type="org.eclipse.jetty.server.ConnectionFactory">
+            <Item>
+              <New class="org.eclipse.jetty.server.HttpConnectionFactory">
+                <Arg name="config"><Ref refid="httpConfig" /></Arg>
+              </New>
+            </Item>
+          </Array>
+        </Arg>
+        <Set name="host"><Property name="jetty.http.host" /></Set>
+        <Set name="port"><Property name="jetty.http.port" default="80" /></Set>
+        <Set name="idleTimeout"><Property name="jetty.http.idleTimeout" default="30000"/></Set>
+      </New>
+    </Arg>
+  </Call>
+
+</Configure>
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-selector.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-selector.xml
deleted file mode 100644
index 67cd87c..0000000
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-selector.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-
-    <!-- =========================================================== -->
-    <!-- Add connector                                               -->
-    <!-- =========================================================== -->
-
-    <Call name="addConnector">
-      <Arg>
-          <New class="org.eclipse.jetty.server.ServerConnector">
-            <Arg><Ref refid="Server" /></Arg>
-             <Arg name="factories">
-               <Array type="org.eclipse.jetty.server.ConnectionFactory">
-                <Item>
-                  <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                   <Arg name="config"><Ref refid="httpConfig" /></Arg>
-                  </New>
-                </Item>
-              </Array>
-             </Arg>
-            <Set name="host"><Property name="jetty.host" /></Set>
-            <Set name="port"><Property name="jetty.port" default="8080"/></Set>
-            <Set name="idleTimeout">300000</Set>
-          </New>
-      </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
index 5c882b0..a3850c9 100644
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 
 <!-- =============================================================== -->
@@ -43,7 +43,7 @@
 
     <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
       <Set name="secureScheme">https</Set>
-      <Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
+      <Set name="securePort"><Property name="jetty.httpConfig.securePort" default="8443" /></Set>
       <Set name="outputBufferSize">32768</Set>
       <Set name="requestHeaderSize">8192</Set>
       <Set name="responseHeaderSize">8192</Set>
@@ -63,21 +63,25 @@
 
 
     <!-- =========================================================== -->
-    <!-- jetty-jndi by default                                       -->
-    <!-- =========================================================== -->
-    <Call class="org.eclipse.jetty.webapp.Configuration$ClassList" name="setServerDefault">
-      <Arg><Ref refid="Server" /></Arg>
-      <Call name="addAfter">
-        <Arg name="afterClass">org.eclipse.jetty.webapp.FragmentConfiguration</Arg>
-        <Arg>
-          <Array type="String">
-            <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
-            <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
-            <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
-          </Array>
-        </Arg>
-      </Call>
+    <!-- Set up the list of default configuration classes            -->
+    <!-- =========================================================== -->    
+    <Call name="setAttribute">
+       <Arg>org.eclipse.jetty.webapp.configuration</Arg>
+       <Arg>
+        <New class="org.eclipse.jetty.webapp.Configuration$ClassList">
+          <Arg>
+            <Array type="String">
+              <Item>org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>  
+            </Array>
+          </Arg>
+        </New>
+       </Arg>
     </Call>
+   
 
     <Call class="java.lang.System" name="setProperty">
       <Arg>java.naming.factory.initial</Arg>
diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml
index df32c1f..9fc2e7f 100644
--- a/jetty-osgi/jetty-osgi-boot/pom.xml
+++ b/jetty-osgi/jetty-osgi-boot/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-osgi-boot</artifactId>
@@ -89,20 +89,11 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <id>bundle-manifest</id>
-                        <phase>process-classes</phase>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                    </execution>
-                </executions>
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>org.eclipse.jetty.osgi.boot;singleton:=true</Bundle-SymbolicName>
                         <Bundle-Activator>org.eclipse.jetty.osgi.boot.JettyBootstrapActivator</Bundle-Activator>
-                        <DynamicImport-Package>org.eclipse.jetty.*;version="[9.1,10.0)"</DynamicImport-Package>
+                        <DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
                         <Import-Package>javax.mail;version="1.4.0";resolution:=optional,
  javax.mail.event;version="1.4.0";resolution:=optional,
  javax.mail.internet;version="1.4.0";resolution:=optional,
@@ -112,8 +103,6 @@
  javax.servlet.http;version="[3.1,3.2)",
  javax.transaction;version="1.1.0";resolution:=optional,
  javax.transaction.xa;version="1.1.0";resolution:=optional,
- org.eclipse.jetty.annotations;version="9.1";resolution:=optional,
- org.eclipse.jetty.plus.webapp;version="9.1";resolution:=optional,
  org.objectweb.asm;version=4;resolution:=optional,
  org.osgi.framework,
  org.osgi.service.cm;version="1.2.0",
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java
index f8e9a14..d92ccd5 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java
@@ -25,7 +25,6 @@
 import org.eclipse.jetty.annotations.ClassNameResolver;
 import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
 import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
-import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
@@ -150,7 +149,7 @@
      * @param parser The parser
      * @param webbundle The current webbundle
      * @param fragmentBundle The OSGi fragment bundle to scan
-     * @throws Exception
+     * @throws Exception if unable to parse fragment bundle
      */
     protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser,
             Bundle webbundle, Bundle fragmentBundle) throws Exception
@@ -163,8 +162,7 @@
      * @param context The webapp context
      * @param parser The parser
      * @param webbundle The current webbundle
-     * @param fragmentBundle The OSGi required bundle to scan
-     * @throws Exception
+     * @throws Exception if unable to parse the web bundle
      */
     protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle)
     throws Exception
@@ -177,8 +175,8 @@
      * @param context The webapp context
      * @param parser The parser
      * @param webbundle The current webbundle
-     * @param fragmentBundle The OSGi required bundle to scan
-     * @throws Exception
+     * @param requiredBundle The OSGi required bundle to scan
+     * @throws Exception if unable to parse the required bundle
      */
     protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser,
             Bundle webbundle, Bundle requiredBundle) throws Exception
@@ -209,8 +207,8 @@
     
     /**
      * Returns the same classname resolver than for the webInfjar scanner
-     * @param context
-     * @return
+     * @param context the web app context
+     * @return the class name resolver
      */
     protected ClassNameResolver createClassNameResolver(final WebAppContext context)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java
index 3d703db..a22b407 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java
@@ -30,7 +30,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.jetty.annotations.ClassNameResolver;
-import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
 import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.eclipse.jetty.util.resource.Resource;
@@ -52,9 +51,10 @@
     
     /**
      * Keep track of a jetty URI Resource and its associated OSGi bundle.
-     * @param uri
-     * @param bundle
-     * @throws Exception 
+     * 
+     * @param bundle the bundle to index
+     * @return the resource for the bundle
+     * @throws Exception if unable to create the resource reference
      */
     protected Resource indexBundle(Bundle bundle) throws Exception
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
index a07e3ae..bc1b6f0 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.osgi.boot;
 
 import java.io.File;
-import java.net.URL;
 import java.util.Dictionary;
 import java.util.HashMap;
 
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
index c4e171d..0386f01 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
@@ -20,12 +20,9 @@
 
 import java.io.File;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.List;
 
 import org.eclipse.jetty.deploy.App;
 import org.eclipse.jetty.deploy.AppProvider;
@@ -34,13 +31,13 @@
 import org.eclipse.jetty.osgi.boot.internal.webapp.OSGiWebappClassLoader;
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
 import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.util.ArrayUtil;
-import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.JarResource;
 import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.webapp.Configuration;
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.eclipse.jetty.xml.XmlConfiguration;
 import org.osgi.framework.Bundle;
@@ -48,54 +45,22 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.packageadmin.PackageAdmin;
 
-
-
-
 /**
  * AbstractWebAppProvider
- *
+ * <p>
  * Base class for Jetty DeploymentManager Providers that are capable of deploying a webapp,
  * either from a bundle or an OSGi service.
- * 
  */
 public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider
 {
     private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
     
-    public static String __defaultConfigurations[] = {
-                                                            "org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration",
-                                                            "org.eclipse.jetty.webapp.WebXmlConfiguration",
-                                                            "org.eclipse.jetty.webapp.MetaInfConfiguration",
-                                                            "org.eclipse.jetty.webapp.FragmentConfiguration",
-                                                            "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"                          
-                                                     };
-    
-    public static void setDefaultConfigurations (String[] defaultConfigs)
-    {
-        __defaultConfigurations = defaultConfigs;
-    }
-    
-    public static String[] getDefaultConfigurations ()
-    {
-        List<String> configs = ArrayUtil.asMutableList(__defaultConfigurations);
-        if (annotationsAvailable())
-        {
-            //add before JettyWebXmlConfiguration
-            int i = configs.indexOf("org.eclipse.jetty.webapp.JettyWebXmlConfiguration");
-            configs.add(i, "org.eclipse.jetty.osgi.annotations.AnnotationConfiguration");
-        }
-        
-        if (jndiAvailable())
-        {
-            //add in EnvConfiguration and PlusConfiguration just after FragmentConfiguration
-            int i = configs.indexOf("org.eclipse.jetty.webapp.FragmentConfiguration");
-            configs.add(++i, "org.eclipse.jetty.plus.webapp.EnvConfiguration");
-            configs.add(++i, "org.eclipse.jetty.plus.webapp.PlusConfiguration");
-        }
-
-        return configs.toArray(new String[configs.size()]);
-    }
-
+    /* ------------------------------------------------------------ */
+    /**
+     * Check if we should be enabling annotation processing
+     * 
+     * @return true if the jetty-annotations.jar is present, false otherwise
+     */
     private static boolean annotationsAvailable()
     {
         boolean result = false;
@@ -114,7 +79,12 @@
         return result;
     }
     
-    
+    /* ------------------------------------------------------------ */
+    /**
+     * Check if jndi is support is present.
+     * 
+     * @return true if the jetty-jndi.jar is present, false otherwise
+     */
     private static boolean jndiAvailable()
     {
         try
@@ -146,11 +116,13 @@
     
     private ServerInstanceWrapper _serverWrapper;
     
+    
+    
     /* ------------------------------------------------------------ */
     /**
      * OSGiApp
      *
-     *
+     * Represents a deployable webapp.
      */
     public class OSGiApp extends AbstractOSGiApp
     {
@@ -316,10 +288,8 @@
             // Set up what has been configured on the provider
             _webApp.setParentLoaderPriority(isParentLoaderPriority());
             _webApp.setExtractWAR(isExtract());
-            if (getConfigurationClasses() != null)
-                _webApp.setConfigurationClasses(getConfigurationClasses());
-            else
-                _webApp.setConfigurationClasses(getDefaultConfigurations());
+            _webApp.setConfigurationClasses(getConfigurationClasses());
+
 
             if (getDefaultsDescriptor() != null)
                 _webApp.setDefaultsDescriptor(getDefaultsDescriptor());
@@ -605,13 +575,27 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * 
-     */
     public String[] getConfigurationClasses()
     {
-        return _configurationClasses;
+        if (_configurationClasses != null)
+            return _configurationClasses;
+
+        Configuration.ClassList defaults = Configuration.ClassList.serverDefault(_serverWrapper.getServer());
+
+        //add before JettyWebXmlConfiguration
+        if (annotationsAvailable())
+            defaults.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", 
+                               "org.eclipse.jetty.osgi.annotations.AnnotationConfiguration");
+
+        //add in EnvConfiguration and PlusConfiguration just after FragmentConfiguration
+        if (jndiAvailable())
+            defaults.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
+                              "org.eclipse.jetty.plus.webapp.EnvConfiguration",
+                              "org.eclipse.jetty.plus.webapp.PlusConfiguration");
+       String[] asArray = new String[defaults.size()];
+       return defaults.toArray(asArray);
     }
+    
 
     /* ------------------------------------------------------------ */
     public void setServerInstanceWrapper(ServerInstanceWrapper wrapper)
@@ -625,9 +609,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @return
-     */
     public DeploymentManager getDeploymentManager()
     {
         return _deploymentManager;
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
index e37817f..6a6d713 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
@@ -33,28 +33,20 @@
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceRegistration;
 
-
-
 /**
  * BundleContextProvider
- *
+ * <p>
  * Handles deploying OSGi bundles that define a context xml file for configuring them.
- * 
- *
  */
 public class BundleContextProvider extends AbstractContextProvider implements BundleProvider
 {    
     private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
-    
 
     private Map<String, App> _appMap = new HashMap<String, App>();
     
     private Map<Bundle, List<App>> _bundleMap = new HashMap<Bundle, List<App>>();
     
     private ServiceRegistration _serviceRegForBundles;
-    
-
-    
   
     /* ------------------------------------------------------------ */
     public BundleContextProvider(ServerInstanceWrapper wrapper)
@@ -96,11 +88,6 @@
 
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param bundle
-     * @param contextFiles
-     * @return
-     */
     public boolean bundleAdded (Bundle bundle) throws Exception
     {
         if (bundle == null)
@@ -149,8 +136,8 @@
     /* ------------------------------------------------------------ */
     /** 
      * Bundle has been removed. If it was a context we deployed, undeploy it.
-     * @param bundle
      * 
+     * @param bundle the bundle
      * @return true if this was a context we had deployed, false otherwise
      */
     public boolean bundleRemoved (Bundle bundle) throws Exception
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
index db57316..8d60de0 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
@@ -25,19 +25,17 @@
 
 import org.eclipse.jetty.deploy.App;
 import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
+import org.eclipse.jetty.osgi.boot.utils.Util;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceRegistration;
 
-
-
 /**
  * BundleWebAppProvider
- *
+ * <p>
  * A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle.
- * 
  */
 public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider
 {     
@@ -52,17 +50,11 @@
     
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param wrapper
-     */
     public BundleWebAppProvider (ServerInstanceWrapper wrapper)
     {
         super(wrapper);
     }
     
-    
-    
-    
     /* ------------------------------------------------------------ */
     /** 
      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
@@ -107,7 +99,7 @@
     /* ------------------------------------------------------------ */
     /**
      * A bundle has been added that could be a webapp 
-     * @param bundle
+     * @param bundle the bundle
      */
     public boolean bundleAdded (Bundle bundle) throws Exception
     {
@@ -122,9 +114,10 @@
             Dictionary headers = bundle.getHeaders();
 
             //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH 
-            if (headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH) != null)
+            String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
+            if (resourcePath != null)
             {
-                String base = (String)headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
+                String base = resourcePath;
                 contextPath = getContextPath(bundle);
                 String originId = getOriginId(bundle, base);
  
@@ -188,8 +181,8 @@
     /* ------------------------------------------------------------ */
     /** 
      * Bundle has been removed. If it was a webapp we deployed, undeploy it.
-     * @param bundle
      * 
+     * @param bundle the bundle
      * @return true if this was a webapp we had deployed, false otherwise
      */
     public boolean bundleRemoved (Bundle bundle) throws Exception
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
index 3371cb2..a41904f 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
@@ -36,13 +36,12 @@
 
 /**
  * JettyBootstrapActivator
- * 
+ * <p>
  * Bootstrap jetty and publish a default Server instance as an OSGi service.
- * 
+ * <p>
  * Listen for other Server instances to be published as services and support them as deployment targets.
- * 
+ * <p>
  * Listen for Bundles to be activated, and deploy those that represent webapps/ContextHandlers to one of the known Server instances.
- * 
  */
 public class JettyBootstrapActivator implements BundleActivator
 {
@@ -74,7 +73,7 @@
      * webapps. Setup the BundleListener that supports the extender pattern for
      * the jetty ContextHandler.
      * 
-     * @param context
+     * @param context the bundle context
      */
     public void start(final BundleContext context) throws Exception
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
index 676505e..0f26de8 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
@@ -30,6 +30,7 @@
      * configuration.
      */
     public static final String JETTY_HOME = "jetty.home";
+    public static final String JETTY_BASE = "jetty.base";
 
     /**
      * System property to point to a bundle that embeds a jetty configuration
@@ -42,21 +43,20 @@
      * Usual system property used as the hostname for a typical jetty
      * configuration.
      */
-    public static final String JETTY_HOST = "jetty.host";
+    public static final String JETTY_HOST = "jetty.http.host";
 
     /**
      * Usual system property used as the port for http for a typical jetty
      * configuration.
      */
-    public static final String JETTY_PORT = "jetty.port";
+    public static final String JETTY_PORT = "jetty.http.port";
 
     /**
      * Usual system property used as the port for https for a typical jetty
      * configuration.
      */
-    public static final String JETTY_PORT_SSL = "jetty.port.ssl";
-    
-    
+    public static final String JETTY_PORT_SSL = "jetty.ssl.port";
+
     //for managed jetty instances, name of the configuration parameters
     /**
      * PID of the jetty servers's ManagedFactory
@@ -85,5 +85,4 @@
      * List of URLs to the folders where the legacy J2EE shared libraries are stored aka lib/ext, lib/jsp etc.
      */
     public static final String MANAGED_JETTY_SHARED_LIB_FOLDER_URLS = "managedJettySharedLibFolderUrls";
-    
 }
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
index 5afa826..870a1f3 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
@@ -22,13 +22,16 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
 import java.util.regex.Pattern;
 
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
+import org.eclipse.jetty.osgi.boot.utils.Util;
 import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -202,7 +205,7 @@
     @Override
     public void configure(WebAppContext context) throws Exception
     {
-        TreeMap<String, Resource> patchResourcesPath = new TreeMap<String, Resource>();
+        TreeMap<String, Resource> prependedResourcesPath = new TreeMap<String, Resource>();
         TreeMap<String, Resource> appendedResourcesPath = new TreeMap<String, Resource>();
              
         Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
@@ -226,46 +229,33 @@
                 // looked up.
                 for (Bundle frag : fragments)
                 {
-                    String fragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
-                    String patchFragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
-                    if (fragFolder != null)
-                    {
-                        URL fragUrl = frag.getEntry(fragFolder);
-                        if (fragUrl == null) { throw new IllegalArgumentException("Unable to locate " + fragFolder
-                                                                                  + " inside "
-                                                                                  + " the fragment '"
-                                                                                  + frag.getSymbolicName()
-                                                                                  + "'"); }
-                        fragUrl = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(fragUrl);
-                        String key = fragFolder.startsWith("/") ? fragFolder.substring(1) : fragFolder;
-                        appendedResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(fragUrl));
-                    }
-                    if (patchFragFolder != null)
-                    {
-                        URL patchFragUrl = frag.getEntry(patchFragFolder);
-                        if (patchFragUrl == null)
-                        { 
-                            throw new IllegalArgumentException("Unable to locate " + patchFragUrl
-                                                               + " inside fragment '"+frag.getSymbolicName()+ "'"); 
-                        }
-                        patchFragUrl = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(patchFragUrl);
-                        String key = patchFragFolder.startsWith("/") ? patchFragFolder.substring(1) : patchFragFolder;
-                        patchResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(patchFragUrl));
-                    }
+                    String path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH,OSGiWebappConstants.JETTY_WAR_FRAGMENT_RESOURCE_PATH,frag.getHeaders());
+                    convertFragmentPathToResource(path, frag, appendedResourcesPath);
+                    path = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH, frag.getHeaders());
+                    convertFragmentPathToResource(path, frag, prependedResourcesPath);
                 }
                 if (!appendedResourcesPath.isEmpty())
-                    context.setAttribute(WebInfConfiguration.RESOURCE_DIRS, new HashSet<Resource>(appendedResourcesPath.values()));
+                {
+                    LinkedHashSet<Resource> resources = new LinkedHashSet<Resource>();
+                    //Add in any existing setting of extra resource dirs
+                    Set<Resource> resourceDirs = (Set<Resource>)context.getAttribute(WebInfConfiguration.RESOURCE_DIRS);
+                    if (resourceDirs != null && !resourceDirs.isEmpty())
+                        resources.addAll(resourceDirs);
+                    //Then append the values from JETTY_WAR_FRAGMENT_FOLDER_PATH
+                    resources.addAll(appendedResourcesPath.values());
+                    
+                    context.setAttribute(WebInfConfiguration.RESOURCE_DIRS, resources);
+                }
             }
         }
         
         super.configure(context);
 
-        // place the patch resources at the beginning of the contexts's resource base
-        if (!patchResourcesPath.isEmpty())
+        // place the prepended resources at the beginning of the contexts's resource base
+        if (!prependedResourcesPath.isEmpty())
         {
-            Resource[] resources = new Resource[1+patchResourcesPath.size()];
-            ResourceCollection mergedResources = new ResourceCollection (patchResourcesPath.values().toArray(new Resource[patchResourcesPath.size()]));
-            System.arraycopy(patchResourcesPath.values().toArray(new Resource[patchResourcesPath.size()]), 0, resources, 0, patchResourcesPath.size());
+            Resource[] resources = new Resource[1+prependedResourcesPath.size()];
+            System.arraycopy(prependedResourcesPath.values().toArray(new Resource[prependedResourcesPath.size()]), 0, resources, 0, prependedResourcesPath.size());
             resources[resources.length-1] = context.getBaseResource();
             context.setBaseResource(new ResourceCollection(resources));
         }
@@ -311,4 +301,32 @@
         
         return resources;
     }
+    
+
+    /**
+     * Convert a path inside a fragment into a Resource
+     * @param resourcePath
+     * @param fragment
+     * @param resourceMap
+     * @throws Exception
+     */
+    private void convertFragmentPathToResource (String resourcePath, Bundle fragment, Map<String, Resource> resourceMap )
+    throws Exception
+    {
+        if (resourcePath == null)
+            return;
+
+        URL url = fragment.getEntry(resourcePath);
+        if (url == null) 
+        { 
+            throw new IllegalArgumentException("Unable to locate " + resourcePath
+                                               + " inside "
+                                               + " the fragment '"
+                                               + fragment.getSymbolicName()
+                                               + "'"); 
+        }
+        url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url);
+        String key = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath;
+        resourceMap.put(key + ";" + fragment.getSymbolicName(), Resource.newResource(url));
+    }
 }
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
index 48897bf..fc6b8fe 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
@@ -67,16 +67,23 @@
     public static final String JETTY_CONTEXT_FILE_PATH = "Jetty-ContextFilePath";
 
     /** path within the bundle to the folder that contains the basic resources. */
+    @Deprecated
     public static final String JETTY_WAR_FOLDER_PATH = "Jetty-WarFolderPath";
+    public static final String JETTY_WAR_RESOURCE_PATH = "Jetty-WarResourcePath";
 
     /** path within a fragment hosted by a web-bundle to a folder that contains basic resources.
      * the path is appended to the lookup path where jetty locates static resources */
+    @Deprecated
     public static final String JETTY_WAR_FRAGMENT_FOLDER_PATH = "Jetty-WarFragmentFolderPath";
+    public static final String JETTY_WAR_FRAGMENT_RESOURCE_PATH = "Jetty-WarFragmentResourcePath";
+    
 
     /** path within a fragment hosted by a web-bundle to a folder that contains basic resources.
      * The path is prefixed to the lookup path where jetty locates static resources:
      * this will override static resources with the same name in the web-bundle. */
+    @Deprecated
     public static final String JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH = "Jetty-WarPatchFragmentFolderPath";
+    public static final String JETTY_WAR_PREPEND_FRAGMENT_RESOURCE_PATH = "Jetty-WarPrependFragmentResourcePath";
 
   
     /** installation path of webapp bundle
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
index e61ef56..d99b189 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
@@ -36,19 +36,15 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 
-
-
 /**
  * ServiceWebAppProvider
- *
+ * <p>
  * Jetty Provider that knows how to deploy a WebApp that has been registered as an OSGi service.
- * 
  */
 public class ServiceWebAppProvider extends AbstractWebAppProvider implements ServiceProvider
 {   
     private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
     
-    
     /**
      * Map of ServiceRef to App. Used when it is an osgi service that is a WebAppContext.
      */
@@ -56,7 +52,6 @@
     
     private ServiceRegistration _serviceRegForServices;
     
-    
     /**
      * ServiceApp
      *
@@ -91,9 +86,6 @@
     
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param wrapper
-     */
     public ServiceWebAppProvider (ServerInstanceWrapper wrapper)
     {
         super(wrapper);
@@ -128,6 +120,8 @@
      
         String base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
         if (base == null)
+            base = (String)serviceRef.getProperty(OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH);
+        if (base == null)
             base = (String)serviceRef.getProperty(OSGiWebappConstants.SERVICE_PROP_WAR);
         
        if (base == null)
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
index 06b0232..eaaa3a1 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
@@ -20,7 +20,6 @@
 
 import java.io.File;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -32,7 +31,6 @@
 import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
 import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
-import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
 import org.eclipse.jetty.osgi.boot.utils.Util;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.log.Log;
@@ -44,12 +42,11 @@
 
 /**
  * DefaultJettyAtJettyHomeHelper
- * 
- * 
+ * <p>
  * Creates a default instance of Jetty, based on the values of the
  * System properties "jetty.home" or "jetty.home.bundle", one of which
  * must be specified in order to create the default instance.
- * 
+ * <p> 
  * Called by the {@link JettyBootstrapActivator} during the starting of the
  * bundle. 
  */
@@ -65,7 +62,7 @@
     /**
      * Set of config files to apply to a jetty Server instance if none are supplied by SYS_PROP_JETTY_ETC_FILES
      */
-    public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-selector.xml,etc/jetty-deployer.xml";
+    public static final String DEFAULT_JETTY_ETC_FILES = "etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml";
     
     /**
      * Default location within bundle of a jetty home dir.
@@ -90,10 +87,13 @@
      * files.
      * </p>
      * <p>
-     * In both cases the system properties jetty.host, jetty.port and
-     * jetty.port.ssl are passed to the configuration files that might use them
+     * In both cases the system properties jetty.http.host, jetty.http.port and
+     * jetty.ssl.port are passed to the configuration files that might use them
      * as part of their properties.
      * </p>
+     * @param bundleContext the bundle context
+     * @return the configured server
+     * @throws Exception if unable to create / configure / or start the server
      */
     public static Server startJettyAtJettyHome(BundleContext bundleContext) throws Exception
     {
@@ -157,7 +157,12 @@
         List<URL> configURLs = jettyHomeDir != null ? getJettyConfigurationURLs(jettyHomeDir) : getJettyConfigurationURLs(jettyHomeBundle, properties);
 
         LOG.info("Configuring the default jetty server with {}",configURLs);
-        LOG.info("JETTY.HOME="+properties.get(OSGiServerConstants.JETTY_HOME));
+        String home=properties.get(OSGiServerConstants.JETTY_HOME);
+        String base=properties.get(OSGiServerConstants.JETTY_BASE);
+        if (base==null)
+            base=home;
+        LOG.info("JETTY.HOME="+home);
+        LOG.info("JETTY.BASE="+base);
         ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
         try
         {
@@ -166,13 +171,13 @@
             // these properties usually are the ones passed to this type of
             // configuration.
             properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME);
-            Util.setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST));
-            Util.setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT));
-            Util.setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL));
-
+            Util.setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST, System.getProperty("jetty.host")));
+            Util.setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT, System.getProperty("jetty.port")));
+            Util.setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL, System.getProperty("ssl.port")));
+            Util.setProperty(properties, OSGiServerConstants.JETTY_HOME, home);
+            Util.setProperty(properties, OSGiServerConstants.JETTY_BASE, base);
             Server server = ServerInstanceWrapper.configure(null, configURLs, properties);
-            //ensure jetty.home is set
-            server.setAttribute(OSGiServerConstants.JETTY_HOME, properties.get(OSGiServerConstants.JETTY_HOME));
+            
             
             //Register the default Server instance as an OSGi service.
             //The JettyServerServiceTracker will notice it and set it up to deploy bundles as wars etc
@@ -180,6 +185,11 @@
             LOG.info("Default jetty server configured");
             return server;
         }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+            throw e;
+        }
         finally
         {
             Thread.currentThread().setContextClassLoader(contextCl);
@@ -280,9 +290,9 @@
     /**
      * Get a resource representing a directory inside a bundle. If the dir is null,
      * return a resource representing the installation location of the bundle.
-     * @param bundle
-     * @param dir
-     * @return
+     * @param bundle the bundle
+     * @param dir the directory
+     * @return the resource found
      */
     public static Resource findDir (Bundle bundle, String dir)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
index 8053b7d..cd0ad0e 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.osgi.boot.internal.serverfactory;
 
 import java.io.File;
-import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -52,12 +51,10 @@
 import org.eclipse.jetty.osgi.boot.utils.Util;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.xml.XmlConfiguration;
-import org.xml.sax.SAXParseException;
 
 /**
  * ServerInstanceWrapper
@@ -147,47 +144,42 @@
 
         for (URL jettyConfiguration : jettyConfigurations)
         {
-            InputStream is = null;
-            try
-            {
-                // Execute a Jetty configuration file
-                Resource r = Resource.newResource(jettyConfiguration);
-                if (!r.exists())
-                {
-                    LOG.warn("File does not exist "+r);
-                    throw new IllegalStateException("No such jetty server config file: "+r);
-                }
-                is = r.getInputStream();
-                XmlConfiguration config = new XmlConfiguration(is);
-                config.getIdMap().putAll(id_map);
-                config.getProperties().putAll(properties);
-                
-                // #334062 compute the URL of the folder that contains the
-                // conf file and set it as a property so we can compute relative paths
-                // from it.
-                String urlPath = jettyConfiguration.toString();
-                int lastSlash = urlPath.lastIndexOf('/');
-                if (lastSlash > 4)
-                {
-                    urlPath = urlPath.substring(0, lastSlash);
-                    config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
-                }
-     
-                Object o = config.configure();
-                if (server == null)
-                    server = (Server)o;
-                
-                id_map = config.getIdMap();
-            }
-            catch (SAXParseException saxparse)
-            {
-                LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse);
-                throw saxparse;
-            }
-            finally
-            {
-                IO.close(is);
-            }
+        	try(Resource r = Resource.newResource(jettyConfiguration))
+        	{
+        		// Execute a Jetty configuration file
+        		if (!r.exists())
+        		{
+        			LOG.warn("File does not exist "+r);
+        			throw new IllegalStateException("No such jetty server config file: "+r);
+        		}
+
+        		XmlConfiguration config = new XmlConfiguration(r.getURL());
+
+        		config.getIdMap().putAll(id_map);
+        		config.getProperties().putAll(properties);
+
+        		// #334062 compute the URL of the folder that contains the
+        		// conf file and set it as a property so we can compute relative paths
+        		// from it.
+        		String urlPath = jettyConfiguration.toString();
+        		int lastSlash = urlPath.lastIndexOf('/');
+        		if (lastSlash > 4)
+        		{
+        			urlPath = urlPath.substring(0, lastSlash);
+        			config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
+        		}
+
+        		Object o = config.configure();
+        		if (server == null)
+        			server = (Server)o;
+
+        		id_map = config.getIdMap();
+        	}
+        	catch (Exception e)
+        	{
+        		LOG.warn("Configuration error in " + jettyConfiguration);
+        		throw e;
+        	}
         }
 
         return server;
@@ -214,7 +206,7 @@
      * The classloader that should be the parent classloader for each webapp
      * deployed on this server.
      * 
-     * @return
+     * @return the classloader
      */
     public ClassLoader getParentClassLoaderForWebapps()
     {
@@ -250,7 +242,6 @@
         return _ctxtCollection;
     }
     
-    
     /* ------------------------------------------------------------ */
     public void start(Server server, Dictionary props) throws Exception
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java
index a25ec1d..87ce60a 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java
@@ -42,12 +42,9 @@
 /**
  * BundleWatcher
  * 
- * 
  * Tracks the installation and removal of Bundles in the OSGi environment. Any bundles
  * that are added are passed to the set of Jetty DeploymentManager providers to see if
  * the bundle should be deployed as a webapp or ContextHandler into Jetty.
- * 
- * @author hmalphettes
  */
 public class BundleWatcher implements BundleTrackerCustomizer
 {
@@ -66,9 +63,6 @@
  
     
     /* ------------------------------------------------------------ */
-    /**
-     * @throws Exception
-     */
     public BundleWatcher() throws Exception
     {
         _bundle = FrameworkUtil.getBundle(this.getClass());
@@ -133,10 +127,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param managedServerName
-     * @return
-     */
     public Map<ServiceReference, BundleProvider> getDeployers(String managedServerName)
     {
         if (managedServerName == null)
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
index 95bfd11..23d2f53 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
@@ -30,14 +30,11 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.eclipse.jetty.server.Server;
-
 /**
  * LibExtClassLoaderHelper
- * 
- * 
+ * <p>
  * Helper to create a URL class-loader with the jars inside
- * ${jetty.home}/lib/ext and ${jetty.home}/resources. In an ideal world, every
+ * <code>${jetty.home}/lib/ext</code> and <code>${jetty.home}/resources</code>. In an ideal world, every
  * library is an OSGi bundle that does loads nicely. To support standard jars or
  * bundles that cannot be loaded in the current OSGi environment, we support
  * inserting the jars in the usual jetty/lib/ext folders in the proper classpath
@@ -45,7 +42,6 @@
  * <p>
  * The drawback is that those jars will not be available in the OSGi
  * classloader.
- * </p>
  * <p>
  * Alternatives to placing jars in lib/ext:
  * <ol>
@@ -56,7 +52,6 @@
  * <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper
  * bundle. (Note: it will work only on equinox)</li>
  * </ol>
- * </p>
  */
 public class LibExtClassLoaderHelper
 {
@@ -78,11 +73,12 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param server
+     * @param jettyHome the jetty home 
+     * @param parentClassLoader the parent classloader
      * @return a url classloader with the jars of resources, lib/ext and the
      *         jars passed in the other argument. The parent classloader usually
      *         is the JettyBootStrapper (an osgi classloader.
-     * @throws MalformedURLException
+     * @throws MalformedURLException if the jetty home reference is invalid
      */
     public static ClassLoader createLibEtcClassLoader(File jettyHome, ClassLoader parentClassLoader) throws MalformedURLException
     {
@@ -134,12 +130,14 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param server
+     * @param jarsContainerOrJars the jars via file references
+     * @param otherJarsOrFolder more jars via url references
+     * @param parentClassLoader the parent classloader
      * @return a url classloader with the jars of resources, lib/ext and the
      *         jars passed in the other argument. The parent classloader usually
      *         is the JettyBootStrapper (an osgi classloader). If there was no
      *         extra jars to insert, then just return the parentClassLoader.
-     * @throws MalformedURLException
+     * @throws MalformedURLException if there is a bad jar file reference
      */
     public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, List<URL> otherJarsOrFolder, ClassLoader parentClassLoader) 
     throws MalformedURLException
@@ -183,13 +181,14 @@
      * depending too much directly on a particular logging framework.
      * <p>
      * We can afford to do some implementation specific code for a logging
-     * framework only in a fragment. <br/>
+     * framework only in a fragment.
+     * <p>
      * Trying to configure log4j and logback in here.
-     * </p>
      * <p>
      * We recommend that slf4j jars are all placed in the osgi framework. And a
      * single implementation if possible packaged as an osgi bundle is there.
-     * </p>
+     * @param jettyHome the jetty home reference
+     * @param childrenFiles the map of child files
      */
     protected static void processFilesInResourcesFolder(File jettyHome, Map<String, File> childrenFiles)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
index 1d0cfdc..8c77b13 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
@@ -85,7 +85,7 @@
      * @param parent The parent classloader.
      * @param context The WebAppContext
      * @param contributor The bundle that defines this web-application.
-     * @throws IOException
+     * @throws IOException if unable to cerate the OSGiWebappClassLoader
      */
     public OSGiWebappClassLoader(ClassLoader parent, WebAppContext context, Bundle contributor)
     throws IOException
@@ -272,6 +272,7 @@
      * WebappContext So we place a fake one there to start with. We replace it
      * with the actual webapp context with this method. We also apply the
      * extraclasspath there at the same time.
+     * @param webappContext the web app context
      */
     public void setWebappContext(WebAppContext webappContext)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
index 892190f..023a03a 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
@@ -54,16 +54,11 @@
     
     public static final String FILTER = "(objectclass=" + ServiceProvider.class.getName() + ")";
 
-    
     //track all instances of deployers of webapps as bundles       
     ServiceTracker _serviceTracker;
     
-    
      
     /* ------------------------------------------------------------ */
-    /**
-     * @param registry
-     */
     public ServiceWatcher() throws Exception
     {
         //track all instances of deployers of webapps
@@ -75,10 +70,6 @@
 
    
     /* ------------------------------------------------------------ */
-    /**
-     * @param managedServerName
-     * @return
-     */
     public Map<ServiceReference, ServiceProvider> getDeployers(String managedServerName)
     {
         if (managedServerName == null)
@@ -154,9 +145,10 @@
     
     /* ------------------------------------------------------------ */
     /** Deploy ContextHandler that is a Service.
-     * 
-     * @param reference
-     * @return
+     * @param context the bundle context 
+     * @param contextHandler  the context handler
+     * @param reference the service reference
+     * @return the object added
      */
     public Object addService (BundleContext context, ContextHandler contextHandler, ServiceReference reference)
     {
@@ -200,8 +192,9 @@
     /* ------------------------------------------------------------ */
     /**
      * Undeploy a ContextHandler that is a Service.
-     * 
-     * @param reference
+     * @param context the bundle context 
+     * @param contextHandler the context handler
+     * @param reference the service reference
      */
     public void removeService (BundleContext context, ContextHandler contextHandler, ServiceReference reference)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
index 18fd9d9..8e39a8d 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
@@ -22,10 +22,8 @@
 import org.osgi.framework.Bundle;
 
 /**
- * 
  * BundleClassLoaderHelper
- * 
- * 
+ * <p> 
  * Is there a clean OSGi way to go from the Bundle object to the classloader of
  * the Bundle ? You can certainly take a class inside the bundle and get the
  * bundle's classloader that way. Getting the classloader directly from the
@@ -34,11 +32,9 @@
  * We could use fragments that are specific to each OSGi implementation. Using
  * introspection here to keep packaging simple and avoid the multiplication of
  * the jars.
- * </p>
  * <p>
  * The default implementation relies on introspection and supports equinox-3.5
  * and felix-2.0.0
- * </p>
  */
 public interface BundleClassLoaderHelper
 {
@@ -50,6 +46,7 @@
     public static BundleClassLoaderHelper DEFAULT = new DefaultBundleClassLoaderHelper();
 
     /**
+     * @param bundle the bundle
      * @return The classloader of a given bundle. Assuming the bundle is
      *         started.
      */
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
index 13e419b..8371dda 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
@@ -28,12 +28,9 @@
 
 /**
  * BundleFileLocatorHelper
- * 
- * 
+ * <p> 
  * From a bundle to its location on the filesystem. Assumes the bundle is not a
  * jar.
- * 
- * @author hmalphettes
  */
 public interface BundleFileLocatorHelper
 {
@@ -50,21 +47,20 @@
      * other situations.
      * <p>
      * Currently only works with bundles that are not jar.
-     * </p>
      * 
      * @param bundle The bundle
      * @return Its installation location as a file.
-     * @throws Exception
+     * @throws Exception if unable to get the install location
      */
     public File getBundleInstallLocation(Bundle bundle) throws Exception;
 
     /**
      * Locate a file inside a bundle.
      * 
-     * @param bundle
-     * @param path
-     * @return file object
-     * @throws Exception
+     * @param bundle the bundle
+     * @param path the path
+     * @return file the file object
+     * @throws Exception if unable to get the file
      */
     public File getFileInBundle(Bundle bundle, String path) throws Exception;
 
@@ -76,11 +72,11 @@
      * files inside jars alone. In fact we only support the second situation for
      * development purpose where the bundle was imported in pde and the classes
      * kept in a jar.
-     * </p>
      * 
-     * @param bundle
+     * @param bundle the bundle
      * @return The jar(s) file that is either the bundle itself, either the jars
      *         embedded inside it.
+     * @throws Exception if unable to locate the jars
      */
     public File[] locateJarsInsideBundle(Bundle bundle) throws Exception;
 
@@ -88,37 +84,37 @@
      * Helper method equivalent to Bundle#getEntry(String entryPath) except that
      * it searches for entries in the fragments by using the findEntries method.
      * 
-     * @param bundle
-     * @param entryPath
+     * @param bundle the bundle
+     * @param entryPath the entry path
      * @return null or all the entries found for that path.
      */
     public Enumeration<URL> findEntries(Bundle bundle, String entryPath);
     
     /**
-     * Only useful for equinox: on felix we get the file:// or jar:// url
+     * Only useful for equinox: on felix we get the <code>file://</code> or <code>jar://</code> url
      * already. Other OSGi implementations have not been tested
      * <p>
-     * Get a URL to the bundle entry that uses a common protocol (i.e. file:
-     * jar: or http: etc.).
-     * </p>
+     * Get a URL to the bundle entry that uses a common protocol (i.e. <code>file:</code>
+     * <code>jar:</code> or <code>http:</code> etc.).
      * 
+     * @param url the url 
      * @return a URL to the bundle entry that uses a common protocol
+     * @throws Exception if unable to get the local url
      */
     public URL getLocalURL(URL url) throws Exception;
     
     /**
-     * Only useful for equinox: on felix we get the file:// url already. Other
+     * Only useful for equinox: on felix we get the <code>file://</code> url already. Other
      * OSGi implementations have not been tested
      * <p>
-     * Get a URL to the content of the bundle entry that uses the file:
+     * Get a URL to the content of the bundle entry that uses the <code>file:</code>
      * protocol. The content of the bundle entry may be downloaded or extracted
      * to the local file system in order to create a file: URL.
      * 
+     * @param url the url 
      * @return a URL to the content of the bundle entry that uses the file:
      *         protocol
-     *         </p>
-     * @throws IOException 
-     * @throws Exception 
+     * @throws Exception if unable to get the file url
      */
     public URL getFileURL(URL url) throws Exception;
 
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
index 8ab0fbf..4e25e7c 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
@@ -28,10 +28,7 @@
 import org.osgi.service.event.EventAdmin;
 
 /**
- * EventSender
- *
  * Utility class for emiting OSGi EventAdmin events
- * 
  */
 public class EventSender
 {    
@@ -42,18 +39,10 @@
     public static final String UNDEPLOYED_EVENT = "org/osgi/service/web/UNDEPLOYED"; 
     public static final String FAILED_EVENT = "org/osgi/service/web/FAILED"; 
     
-    
     private static final EventSender __instance = new EventSender();
     private Bundle _myBundle;
     private EventAdmin _eventAdmin;
     
-    
-    
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * 
-     */
     private EventSender ()
     {
         _myBundle = FrameworkUtil.getBundle(EventSender.class);
@@ -62,26 +51,11 @@
             _eventAdmin = (EventAdmin)_myBundle.getBundleContext().getService(ref);
     }
     
-    
-    
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @return
-     */
     public static EventSender getInstance()
     {
         return __instance;
     }
 
-    
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param topic
-     * @param wab
-     * @param contextPath
-     */
     public  void send (String topic, Bundle wab, String contextPath)
     {
         if (topic==null || wab==null || contextPath==null)
@@ -90,15 +64,6 @@
         send(topic, wab, contextPath, null);
     }
     
-    
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param topic
-     * @param wab
-     * @param contextPath
-     * @param ex
-     */
     public  void send (String topic, Bundle wab, String contextPath, Exception ex)
     {        
         if (_eventAdmin == null)
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java
index 544c3d2..a677bac 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java
@@ -22,29 +22,21 @@
 import java.net.URLClassLoader;
 
 /**
- * 
  * FakeURLClassLoader
- * 
+ * <p>
  * A URLClassloader that overrides the getURLs() method to return the list
  * of urls passed in to the constructor, but otherwise acts as if it has no
  * urls, which would cause it to delegate to the parent classloader (in this
  * case an OSGi classloader).
- * 
+ * <p>
  * The main use of this class is with jars containing tlds. Jasper expects a
  * URL classloader to inspect for jars with tlds.
- * 
  */
 public class FakeURLClassLoader extends URLClassLoader
 {
-
     private URL[] _jars;
     
-    
     /* ------------------------------------------------------------ */
-    /**
-     * @param osgiClassLoader
-     * @param jars
-     */
     public FakeURLClassLoader(ClassLoader osgiClassLoader, URL[] jars)
     {
         super(new URL[] {},osgiClassLoader);
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java
index b08bf0b..31fe0ea 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/Util.java
@@ -27,23 +27,43 @@
 import java.util.StringTokenizer;
 
 /**
- * Util
- *
- * Various useful functions used widely.
+ * Various useful functions utility methods for OSGi wide use.
  */
 public class Util
 {
     public static final String DEFAULT_DELIMS = ",;";
 
+    
+    /**
+     * Get the value of a manifest header.
+     * 
+     * @param name the name of the header
+     * @param altName an alternative name for the header (useful for deprecated names)
+     * @param manifest the dictionary
+     * @return the value from the manifest
+     */
+    public static String getManifestHeaderValue (String name, String altName, Dictionary manifest)
+    {
+        if (manifest == null)
+            return null;
+        if (name == null && altName == null)
+            return null;
+        if (name != null)
+            return (String)manifest.get(name);
+        return (String)manifest.get(altName);
+    }
+    
+  
+    
     /* ------------------------------------------------------------ */
     /**
      * Treating the string as a separated list of filenames,
      * convert and return the list of urls.
      * 
-     * @param val the separated list
-     * @param delims the separators (default is ,;)
-     * @return
-     * @throws MalformedURLException 
+     * @param val the separated list of filenames
+     * @param delims the separators (default is <code>,;</code>)
+     * @return the list of URLs found in the input list
+     * @throws Exception if unable to convert entry to a URL
      */
     public static List<URL> fileNamesAsURLs(String val, String delims) 
     throws Exception
@@ -74,13 +94,13 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * recursively substitute the ${sysprop} by their actual system property.
-     * ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no
+     * recursively substitute the <code>${sysprop}</code> by their actual system property.
+     * <code>${sysprop,defaultvalue}</code> will use <code>'defaultvalue'</code> as the value if no
      * sysprop is defined. Not the most efficient code but we are shooting for
      * simplicity and speed of development here.
      * 
-     * @param value
-     * @return
+     * @param value the input string
+     * @return the string with replaced properties
      */
     public static String resolvePropertyValue(String value)
     {
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
index f66362e..818659d 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
@@ -29,15 +29,14 @@
 
 /**
  * DefaultBundleClassLoaderHelper
- * 
- * 
+ * <p>
  * Default implementation of the BundleClassLoaderHelper. Uses introspection to
  * support equinox-3.5 and felix-2.0.0
  */
 public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
 {
     private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
-    private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403};
+    private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge};
     private static OSGiContainerType osgiContainer;
     private static Class Equinox_BundleHost_Class;
     private static Class Equinox_EquinoxBundle_Class;
@@ -56,6 +55,12 @@
     private static Field Felix_ModuleImpl_m_ClassLoader_Field;
     private static Method Felix_BundleWiring_getClassLoader_Method;
     
+    // Concierge
+    private static Class Concierge_BundleImpl_Class;
+    private static Class Concierge_BundleWiring_Class;
+    private static Method Concierge_BundleImpl_Adapt_Method;
+    private static Method Concierge_BundleWiring_getClassLoader_Method;
+    
     
     private static void checkContainerType (Bundle bundle)
     {
@@ -102,10 +107,22 @@
         }
         catch (ClassNotFoundException e)
         {
-            LOG.warn("Unknown OSGi container type");
-            return;
+            LOG.ignore(e);
         }
         
+        try
+        {
+            Concierge_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.concierge.BundleImpl");
+            osgiContainer = OSGiContainerType.Concierge;
+            return;
+        }
+        catch (ClassNotFoundException e)
+        {
+            LOG.ignore(e);
+        }
+
+        LOG.warn("Unknown OSGi container type");
+        return;
     }
 
   
@@ -115,7 +132,7 @@
     /**
      * Assuming the bundle is started.
      * 
-     * @param bundle
+     * @param bundle the bundle
      * @return classloader object
      */
     public ClassLoader getBundleClassLoader(Bundle bundle)
@@ -168,6 +185,12 @@
             {
                 return internalGetFelixBundleClassLoader(bundle); 
             }
+
+            case Concierge:
+            {
+                return internalGetConciergeBundleClassLoader(bundle); 
+            }
+
             default:
             {
                 LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
@@ -363,4 +386,55 @@
         LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
         return null;
     }
+    
+    /**
+     * @param bundle
+     * @return
+     */
+    private static ClassLoader internalGetConciergeBundleClassLoader(Bundle bundle)
+    {
+        if (osgiContainer == OSGiContainerType.Concierge)
+        {
+            try
+            {
+                /** 
+                 * In Concierge:
+                 * 
+                 * Option A:
+                 * <pre>
+                 * Concierge concierge = new Concierge(...);
+                 * BundleWiring bundleWiring = concierge.getWiring(); // method is public
+                 * </pre>
+                 * Problem: getWiring not yet implementd
+                 * 
+                 * Option B:
+                 * <pre>
+                 * Concierge concierge = new Concierge(...);
+                 * BundleWiring bundleWiring = concierge.adapt(org.osgi.framework.wiring.BundleWiring);
+                 * </pre>
+                 * Same approach as done in Felix.
+                 * 
+                 */
+                if (Concierge_BundleWiring_Class == null) {
+                    Concierge_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
+                    Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", new Class[] {Class.class});
+                    Concierge_BundleImpl_Adapt_Method.setAccessible(true);
+                    Concierge_BundleWiring_getClassLoader_Method = Concierge_BundleWiring_Class.getMethod("getClassLoader");
+                    Concierge_BundleWiring_getClassLoader_Method.setAccessible(true);
+                }
+
+                Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Concierge_BundleWiring_Class});
+                ClassLoader cl = (ClassLoader)Concierge_BundleWiring_getClassLoader_Method.invoke(wiring);
+                return cl;
+            }
+            catch (Exception e)
+            {
+                LOG.warn(e);
+                return null;
+            }
+        }
+
+        LOG.warn("No classloader for Concierge platform for bundle "+bundle.getSymbolicName());
+        return null;
+    }
 }
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
index e0b5479..9052c93 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
@@ -32,18 +32,15 @@
 
 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
 import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.resource.FileResource;
+import org.eclipse.jetty.util.resource.PathResource;
 import org.eclipse.jetty.util.resource.Resource;
 import org.osgi.framework.Bundle;
 
 /**
  * DefaultFileLocatorHelper
- * 
- * 
+ * <p> 
  * From a bundle to its location on the filesystem. Assumes the bundle is not a
  * jar.
- * 
- * @author hmalphettes
  */
 public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
 {
@@ -89,7 +86,7 @@
      * 
      * @param bundle The bundle
      * @return Its installation location as a file.
-     * @throws Exception
+     * @throws Exception if unable to get the bundle install location
      */
     public File getBundleInstallLocation(Bundle bundle) throws Exception
     {
@@ -100,10 +97,10 @@
 
         if (url.getProtocol().equals("file"))
         {
-            // some osgi frameworks do use the file protocole directly in some
+            // some osgi frameworks do use the file protocol directly in some
             // situations. Do use the FileResource to transform the URL into a
             // File: URL#toURI is broken
-            return new FileResource(url).getFile().getParentFile().getParentFile();
+            return new PathResource(url).getFile().getParentFile().getParentFile();
         }
         else if (url.getProtocol().equals("bundleentry"))
         {
@@ -212,10 +209,10 @@
     /**
      * Locate a file inside a bundle.
      * 
-     * @param bundle
-     * @param path
+     * @param bundle the bundle
+     * @param path the path
      * @return file object
-     * @throws Exception
+     * @throws Exception if unable to get the file in the bundle
      */
     public File getFileInBundle(Bundle bundle, String path) throws Exception
     {
@@ -239,8 +236,8 @@
      * it searches for entries in the fragments by using the Bundle#findEntries
      * method.
      * 
-     * @param bundle
-     * @param entryPath
+     * @param bundle the bundle
+     * @param entryPath the entry path
      * @return null or all the entries found for that path.
      */
     public Enumeration<URL> findEntries(Bundle bundle, String entryPath)
@@ -266,7 +263,7 @@
      * kept in a jar.
      * </p>
      * 
-     * @param bundle
+     * @param bundle the bundle
      * @return The jar(s) file that is either the bundle itself, either the jars
      *         embedded inside it.
      */
@@ -349,7 +346,7 @@
      * @return a URL to the content of the bundle entry that uses the file:
      *         protocol
      *         </p>
-     * @throws IOException 
+     * @throws Exception if unable to get the file url 
      */
     public URL getFileURL(URL url) throws Exception
  
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
index 2f0f6c3..087af54 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
@@ -36,11 +36,10 @@
 
 /**
  * PackageAdminServiceTracker
- * 
- * 
+ * <p>
  * When the PackageAdmin service is activated we can look for the fragments
  * attached to this bundle and do a fake "activate" on them.
- * 
+ * <p> 
  * See particularly the jetty-osgi-boot-jsp fragment bundle that uses this
  * facility.
  */
@@ -124,8 +123,8 @@
      * bundle. when we drop the support for the older versions of OSGi, we will
      * stop using the PackageAdmin service.
      * 
-     * @param bundle
-     * @return
+     * @param bundle the bundle
+     * @return the bundle fragment list
      */
     public Bundle[] getFragments(Bundle bundle)
     {
@@ -143,9 +142,8 @@
      * collect the required-bundles and fragment when the directive
      * visibility:=reexport is added to a required-bundle.
      * 
-     * @param bundle
-     * @param webFragOrAnnotationOrResources
-     * @return
+     * @param bundle the bundle
+     * @return the bundle fragment and required list
      */
     public Bundle[] getFragmentsAndRequiredBundles(Bundle bundle)
     {
@@ -165,9 +163,13 @@
      * transitively when the directive 'visibility:=reexport' is added to a
      * required-bundle.
      * 
-     * @param bundle
-     * @param webFragOrAnnotationOrResources
-     * @return
+     * @param bundle the bundle
+     * @param admin the admin package
+     * @param deps The map of fragment and required bundles associated to the value of the
+     *         jetty-web attribute.
+     * @param onlyReexport true to collect resources and web-fragments
+     *            transitively if and only if the directive visibility is
+     *            reexport.
      */
     protected void collectFragmentsAndRequiredBundles(Bundle bundle, PackageAdmin admin, Map<String, Bundle> deps, boolean onlyReexport)
     {
@@ -193,12 +195,13 @@
      * A simplistic but good enough parser for the Require-Bundle header. Parses
      * the version range attribute and the visibility directive.
      * 
+     * @param bundle the bundle
+     * @param admin the admin package 
+     * @param deps The map of required bundles associated to the value of the
+     *         jetty-web attribute.
      * @param onlyReexport true to collect resources and web-fragments
      *            transitively if and only if the directive visibility is
      *            reexport.
-     * @param bundle
-     * @return The map of required bundles associated to the value of the
-     *         jetty-web attribute.
      */
     protected void collectRequiredBundles(Bundle bundle, PackageAdmin admin, Map<String, Bundle> deps, boolean onlyReexport)
     {
diff --git a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
index 28b06ea..98c0031 100644
--- a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
+++ b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 <Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
   <!-- this configures the servlet session manager -->
   <Set name="SessionHandler">
diff --git a/jetty-osgi/jetty-osgi-httpservice/pom.xml b/jetty-osgi/jetty-osgi-httpservice/pom.xml
index b77d2ca..c54033c 100644
--- a/jetty-osgi/jetty-osgi-httpservice/pom.xml
+++ b/jetty-osgi/jetty-osgi-httpservice/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-httpservice</artifactId>
@@ -83,15 +83,6 @@
           <groupId>org.apache.felix</groupId>
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
-          <executions>
-              <execution>
-                  <id>bundle-manifest</id>
-                  <phase>process-classes</phase>
-                  <goals>
-                      <goal>manifest</goal>
-                  </goals>
-              </execution>
-          </executions>
           <configuration>
               <instructions>
                 <Bundle-SymbolicName>org.eclipse.jetty.osgi.httpservice</Bundle-SymbolicName>
diff --git a/jetty-osgi/jetty-osgi-npn/pom.xml b/jetty-osgi/jetty-osgi-npn/pom.xml
deleted file mode 100644
index 092278f..0000000
--- a/jetty-osgi/jetty-osgi-npn/pom.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.osgi</groupId>
-    <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.11-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>jetty-osgi-npn</artifactId>
-  <name>Jetty :: OSGi NPN Fragment</name>
-  <packaging>jar</packaging>
-  <properties>
-    <bundle-symbolic-name>org.eclipse.jetty.osgi.npn.fragment</bundle-symbolic-name>
-  </properties>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>build-helper-maven-plugin</artifactId>
-        <version>1.7</version>
-        <executions>
-          <execution>
-            <id>parse-version</id>
-            <goals>
-              <goal>parse-version</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestEntries>
-              <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
-              <Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
-              <Bundle-Name>Jetty OSGi NPN Fragment</Bundle-Name>
-              <Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version>
-              <Export-Package>org.eclipse.jetty.npn</Export-Package>
-              <Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
-            </manifestEntries>
-          </archive>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-</project>
diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml
index 032cfa7..32422e4 100644
--- a/jetty-osgi/pom.xml
+++ b/jetty-osgi/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <groupId>org.eclipse.jetty.osgi</groupId>
   <artifactId>jetty-osgi-project</artifactId>
@@ -25,22 +25,9 @@
     <module>jetty-osgi-httpservice</module>
     <module>test-jetty-osgi-webapp</module>
     <module>test-jetty-osgi-context</module>
-    <module>test-jetty-osgi</module>
     <module>jetty-osgi-alpn</module>
+    <module>test-jetty-osgi</module>
   </modules>
-  <profiles>
-    <profile>
-      <id>npn</id>
-      <activation>
-        <jdk>1.7</jdk>
-      </activation>
-      <modules>
-<!--
-        <module>jetty-osgi-npn</module>
--->
-      </modules>
-    </profile>
-  </profiles>
   <build>
     <resources>
       <resource>
diff --git a/jetty-osgi/test-jetty-osgi-context/pom.xml b/jetty-osgi/test-jetty-osgi-context/pom.xml
index 5f06566..5aae6b0 100644
--- a/jetty-osgi/test-jetty-osgi-context/pom.xml
+++ b/jetty-osgi/test-jetty-osgi-context/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-jetty-osgi-context</artifactId>
@@ -80,15 +80,6 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <id>bundle-manifest</id>
-                        <phase>process-classes</phase>
-                        <goals>
-                            <goal>manifest</goal> 
-                        </goals>
-                    </execution>
-                </executions>
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>org.eclipse.jetty.osgi.testcontext;singleton:=true</Bundle-SymbolicName>
diff --git a/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml b/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml
index 1ff97a4..f6c5cf5 100644
--- a/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml
+++ b/jetty-osgi/test-jetty-osgi-context/src/main/context/acme.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.server.handler.ContextHandler">
 
@@ -8,7 +8,7 @@
     <Arg><Property name="bundle.root"/></Arg>
   </Call>
 
-  <Ref id="res">
+  <Ref refid="res">
     <Call id="base" name="addPath">
       <Arg>/static/</Arg>
     </Call>
@@ -18,7 +18,7 @@
 
   <!-- Set up the base resource for static files relative to inside bundle -->
   <Set name="baseResource">
-     <Ref id="base"/>
+     <Ref refid="base"/>
   </Set>
 
   <Set name="handler">
diff --git a/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java
index 37f9d04..262cbab 100644
--- a/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java
+++ b/jetty-osgi/test-jetty-osgi-context/src/main/java/com/acme/osgi/Activator.java
@@ -24,15 +24,9 @@
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 
-import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandler;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.BundleTracker;
 
 /**
  * Bootstrap a ContextHandler
diff --git a/jetty-osgi/test-jetty-osgi-webapp/pom.xml b/jetty-osgi/test-jetty-osgi-webapp/pom.xml
index 1328ea3..534df5d 100644
--- a/jetty-osgi/test-jetty-osgi-webapp/pom.xml
+++ b/jetty-osgi/test-jetty-osgi-webapp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -73,15 +73,6 @@
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
                 <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <id>bundle-manifest</id>
-                        <phase>process-classes</phase>
-                        <goals>
-                            <goal>manifest</goal> 
-                        </goals>
-                    </execution>
-                </executions>
                 <configuration>
                     <instructions>
                         <Bundle-SymbolicName>org.eclipse.jetty.osgi.testapp;singleton:=true</Bundle-SymbolicName>
@@ -91,7 +82,6 @@
                         <!-- disable the uses directive: jetty will accomodate pretty much any versions
                         of the packages it uses; no need to reflect some tight dependency determined at
                         compilation time. --> 
-                        <_nouses>true</_nouses>
                         <Import-Package>
  org.osgi.framework,
  org.osgi.service.cm;version="1.2.0",
@@ -106,7 +96,7 @@
  org.xml.sax.helpers,
  *
                         </Import-Package>
-                        <DynamicImport-Package>org.eclipse.jetty.*;version="[9.1,10.0)"</DynamicImport-Package>
+                        <DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
                     </instructions>
                 </configuration>
             </plugin>
diff --git a/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java b/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java
index a04e3dd..5ca58be 100644
--- a/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java
+++ b/jetty-osgi/test-jetty-osgi-webapp/src/main/java/com/acme/osgi/Activator.java
@@ -21,16 +21,10 @@
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.webapp.WebAppContext;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.BundleTracker;
 
 /**
  * Bootstrap a webapp
@@ -57,7 +51,7 @@
         Dictionary serverProps = new Hashtable();
         //define the unique name of the server instance
         serverProps.put("managedServerName", serverName);
-        serverProps.put("jetty.port", "9999");
+        serverProps.put("jetty.http.port", "9999");
         //let Jetty apply some configuration files to the Server instance
         serverProps.put("jetty.etc.config.urls", "file:/opt/jetty/etc/jetty.xml,file:/opt/jetty/etc/jetty-selector.xml,file:/opt/jetty/etc/jetty-deployer.xml");
         //register as an OSGi Service for Jetty to find 
diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml
index c2612f1..74d2aed 100644
--- a/jetty-osgi/test-jetty-osgi/pom.xml
+++ b/jetty-osgi/test-jetty-osgi/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.osgi</groupId>
     <artifactId>jetty-osgi-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -11,7 +11,7 @@
   <description>Jetty OSGi Integration test</description>
   <url>http://www.eclipse.org/jetty</url>
   <properties>
-    <bundle-symbolic-name>${project.groupId}.boot.test.spdy</bundle-symbolic-name>
+    <bundle-symbolic-name>${project.groupId}.boot.test.osgi</bundle-symbolic-name>
     <jetty-orbit-url>http://download.eclipse.org/jetty/orbit/</jetty-orbit-url>
     <assembly-directory>target/distribution</assembly-directory>
     <exam.version>3.5.0</exam.version>
@@ -35,7 +35,7 @@
     </dependency>
     
 
-    <!-- use the forked container so we can pass it system properties eg for npn/alpn -->
+    <!-- use the forked container so we can pass it system properties eg for alpn -->
     <dependency>
         <groupId>org.ops4j.pax.exam</groupId>
         <artifactId>pax-exam-container-forked</artifactId>
@@ -164,12 +164,44 @@
     </dependency>
 
     <dependency>
-     <groupId>org.mortbay.jasper</groupId>
-      <artifactId>apache-el</artifactId>
-      <version>8.0.9.M3</version>
-     <scope>test</scope>
+       <groupId>org.glassfish.web</groupId>
+       <artifactId>javax.servlet.jsp.jstl</artifactId>
+       <version>1.2.2</version>
+      <exclusions>
+        <exclusion>
+          <groupId>javax.servlet.jsp.jstl</groupId>
+          <artifactId>jstl-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>javax.servlet</groupId>
+          <artifactId>servlet-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>javax.servlet.jsp</groupId>
+          <artifactId>jsp-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>javax.el</groupId>
+          <artifactId>el-api</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
 
+    <dependency>
+        <groupId>org.eclipse.jetty.orbit</groupId>
+        <artifactId>javax.servlet.jsp.jstl</artifactId>
+        <version>1.2.0.v201105211821</version>
+        <exclusions>
+          <exclusion>
+            <groupId>org.eclipse.jetty.orbit</groupId>
+            <artifactId>javax.servlet</artifactId>
+          </exclusion>
+          <exclusion>
+            <groupId>org.eclipse.jetty.orbit</groupId>
+            <artifactId>javax.servlet.jsp</artifactId>
+          </exclusion>
+        </exclusions>
+    </dependency>
 
     <!-- Jetty Deps -->
     <dependency>
@@ -223,6 +255,7 @@
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-util</artifactId>
+      <version>${project.version}</version> 
       <scope>runtime</scope>
     </dependency>
     <dependency>
@@ -279,28 +312,9 @@
       <scope>runtime</scope>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-core</artifactId>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
       <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-server</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-client</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.mortbay.jetty.alpn</groupId>
diff --git a/jetty-osgi/test-jetty-osgi/src/main/resources/jetty-logging.properties b/jetty-osgi/test-jetty-osgi/src/main/resources/jetty-logging.properties
index 5250a08..147cf00 100644
--- a/jetty-osgi/test-jetty-osgi/src/main/resources/jetty-logging.properties
+++ b/jetty-osgi/test-jetty-osgi/src/main/resources/jetty-logging.properties
@@ -1,2 +1 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-org.eclipse.jetty.spdy.LEVEL=WARN
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml
index b03a648..19b3a5d 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-deployer.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml
new file mode 100644
index 0000000..319ae6c
--- /dev/null
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- Configure the Jetty Server instance with an ID "Server"       -->
+<!-- by adding a HTTP connector.                                   -->
+<!-- This configuration must be used in conjunction with jetty.xml -->
+<!-- ============================================================= -->
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- =========================================================== -->
+  <!-- Add a HTTP Connector.                                       -->
+  <!-- Configure an o.e.j.server.ServerConnector with a single     -->
+  <!-- HttpConnectionFactory instance using the common httpConfig  -->
+  <!-- instance defined in jetty.xml                               -->
+  <!--                                                             -->
+  <!-- Consult the javadoc of o.e.j.server.ServerConnector and     -->
+  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
+  <!-- that may be set here.                                       -->
+  <!-- =========================================================== -->
+  <Call name="addConnector">
+    <Arg>
+      <New class="org.eclipse.jetty.server.ServerConnector">
+        <Arg name="server"><Ref refid="Server" /></Arg>
+        <Arg name="factories">
+          <Array type="org.eclipse.jetty.server.ConnectionFactory">
+            <Item>
+              <New class="org.eclipse.jetty.server.HttpConnectionFactory">
+                <Arg name="config"><Ref refid="httpConfig" /></Arg>
+              </New>
+            </Item>
+          </Array>
+        </Arg>
+        <Set name="host"><Property name="jetty.http.host" /></Set>
+        <Set name="port"><Property name="jetty.http.port" default="80" /></Set>
+        <Set name="idleTimeout"><Property name="jetty.http.idleTimeout" default="30000"/></Set>
+      </New>
+    </Arg>
+  </Call>
+
+</Configure>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml
new file mode 100644
index 0000000..3362c1b
--- /dev/null
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-http2.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- Configure a HTTP2 on the ssl connector.                       -->
+<!-- ============================================================= -->
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory">
+        <Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
+        <Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" default="1024"/></Set>
+      </New>
+    </Arg>
+  </Call>
+</Configure>
+
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
index a6bef16..c9d497e 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-https.xml
@@ -1,47 +1,28 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
 <!-- Configure a HTTPS connector.                                  -->
 <!-- This configuration must be used in conjunction with jetty.xml -->
 <!-- and jetty-ssl.xml.                                            -->
 <!-- ============================================================= -->
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
 
-  <!-- =========================================================== -->
-  <!-- Add a HTTPS Connector.                                      -->
-  <!-- Configure an o.e.j.server.ServerConnector with connection   -->
-  <!-- factories for TLS (aka SSL) and HTTP to provide HTTPS.      -->
-  <!-- All accepted TLS connections are wired to a HTTP connection.-->
-  <!--                                                             -->
-  <!-- Consult the javadoc of o.e.j.server.ServerConnector,        -->
-  <!-- o.e.j.server.SslConnectionFactory and                       -->
-  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
-  <!-- that may be set here.                                       -->
-  <!-- =========================================================== -->
-  <Call id="httpsConnector" name="addConnector">
+  <Call name="addIfAbsentConnectionFactory">
     <Arg>
-      <New class="org.eclipse.jetty.server.ServerConnector">
-        <Arg name="server"><Ref refid="Server" /></Arg>
-          <Arg name="factories">
-            <Array type="org.eclipse.jetty.server.ConnectionFactory">
-              <Item>
-                <New class="org.eclipse.jetty.server.SslConnectionFactory">
-                  <Arg name="next">http/1.1</Arg>
-                  <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
-                </New>
-              </Item>
-              <Item>
-                <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                  <Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
-                </New>
-              </Item>
-            </Array>
-          </Arg>
-          <Set name="host"><Property name="jetty.host" /></Set>
-          <Set name="port"><Property name="jetty.https.port" default="8443" /></Set>
-          <Set name="idleTimeout">30000</Set>
-        </New>
+      <New class="org.eclipse.jetty.server.SslConnectionFactory">
+        <Arg name="next">http/1.1</Arg>
+        <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
+      </New>
     </Arg>
   </Call>
+
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.server.HttpConnectionFactory">
+        <Arg name="config"><Ref refid="sslHttpConfig" /></Arg>
+      </New>
+    </Arg>
+  </Call>
+  
 </Configure>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml
deleted file mode 100644
index 67cd87c..0000000
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-selector.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-
-    <!-- =========================================================== -->
-    <!-- Add connector                                               -->
-    <!-- =========================================================== -->
-
-    <Call name="addConnector">
-      <Arg>
-          <New class="org.eclipse.jetty.server.ServerConnector">
-            <Arg><Ref refid="Server" /></Arg>
-             <Arg name="factories">
-               <Array type="org.eclipse.jetty.server.ConnectionFactory">
-                <Item>
-                  <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                   <Arg name="config"><Ref refid="httpConfig" /></Arg>
-                  </New>
-                </Item>
-              </Array>
-             </Arg>
-            <Set name="host"><Property name="jetty.host" /></Set>
-            <Set name="port"><Property name="jetty.port" default="8080"/></Set>
-            <Set name="idleTimeout">300000</Set>
-          </New>
-      </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml
deleted file mode 100644
index 2bc1fe3..0000000
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-spdy.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-    <!-- =========================================================== -->
-    <!-- Add HTTP Customizer for Secure request                      -->
-    <!-- =========================================================== -->
-    <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-        <Set name="secureScheme">https</Set>
-        <Set name="securePort">
-            <SystemProperty name="jetty.spdy.port" default="8443"/>
-        </Set>
-        <Set name="outputBufferSize">32768</Set>
-        <Set name="requestHeaderSize">8192</Set>
-        <Set name="responseHeaderSize">8192</Set>
-        <Call name="addCustomizer">
-            <Arg>
-                <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/>
-            </Arg>
-        </Call>
-    </New>
-
-
-    <!-- =========================================================== -->
-    <!-- Setup a SSL Context factory                                 -->
-    <!-- =========================================================== -->
-    <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-        <Set name="KeyStorePath"><Property name="jetty.home" default="."/>/etc/keystore
-        </Set>
-        <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
-        <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
-        <Set name="TrustStorePath"><Property name="jetty.home" default="."/>/etc/keystore
-        </Set>
-        <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
-    </New>
-
-    <!-- =========================================================== -->
-    <!-- Set connectors                                              -->
-    <!-- =========================================================== -->
-    <Call id="sslConnector" name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.server.ServerConnector">
-                <Arg name="server">
-                    <Ref refid="Server"/>
-                </Arg>
-                <Arg name="factories">
-                    <Array type="org.eclipse.jetty.server.ConnectionFactory">
-                        <Item>
-                            <New class="org.eclipse.jetty.server.SslConnectionFactory">
-                                <Arg name="next">alpn</Arg>
-                                <Arg name="sslContextFactory">
-                                    <Ref refid="sslContextFactory"/>
-                                </Arg>
-                            </New>
-                        </Item>
-
-                        <Item>
-                            <New class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
-                                <Arg name="protocols">
-                                    <Array type="String">
-                                        <Item>spdy/3</Item>
-                                        <Item>spdy/2</Item>
-                                        <Item>http/1.1</Item>
-                                    </Array>
-                                </Arg>
-                                <Set name="defaultProtocol">http/1.1</Set>
-                            </New>
-                        </Item>
-
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">3</Arg>
-                                <Arg name="config">
-                                    <Ref refid="httpConfig"/>
-                                </Arg>
-                                <!-- Set the initial window size for this SPDY connector. -->
-                                <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
-                                <Set name="initialWindowSize">65536</Set>
-                            </New>
-                        </Item>
-
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">2</Arg>
-                                <Arg name="config">
-                                    <Ref refid="httpConfig"/>
-                                </Arg>
-                                <!-- Set the initial window size for this SPDY connector. -->
-                                <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
-                                <Set name="initialWindowSize">65536</Set>
-                            </New>
-                        </Item>
-
-                        <Item>
-                            <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                                <Arg name="config">
-                                    <Ref refid="httpConfig"/>
-                                </Arg>
-                            </New>
-                        </Item>
-                    </Array>
-                </Arg>
-                <Set name="host">
-                    <Property name="jetty.host"/>
-                </Set>
-                <Set name="port">
-                    <SystemProperty name="jetty.spdy.port" default="8443"/>
-                </Set>
-                <Set name="idleTimeout">30000</Set>
-            </New>
-        </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml
index b4c3551..f82386e 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-ssl.xml
@@ -1,20 +1,46 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
-<!-- Configure a TLS (SSL) Context Factory                         -->
-<!-- This configuration must be used in conjunction with jetty.xml -->
-<!-- and either jetty-https.xml or jetty-spdy.xml (but not both)   -->
+<!-- Base SSL configuration                                        -->
+<!-- This configuration needs to be used together with 1 or more   -->
+<!-- of jetty-https.xml and/or jetty-http2.xml                     -->
 <!-- ============================================================= -->
-<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-  <Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set>
-  <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
-  <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
-  <Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set>
-  <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
-  <Set name="EndpointIdentificationAlgorithm"></Set>
-  <Set name="ExcludeCipherSuites">
-    <Array type="String">
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- =========================================================== -->
+  <!-- Add a SSL Connector with no protocol factories              -->
+  <!-- =========================================================== -->
+  <Call  name="addConnector">
+    <Arg>
+      <New id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+        <Arg name="server"><Ref refid="Server" /></Arg>
+          <Arg name="factories">
+            <Array type="org.eclipse.jetty.server.ConnectionFactory">
+            </Array>
+          </Arg>
+          <Set name="host"><Property name="jetty.ssl.host" /></Set>
+          <Set name="port"><Property name="jetty.ssl.port" default="443" /></Set>
+          <Set name="idleTimeout"><Property name="jetty.ssl.idleTimeout" default="30000"/></Set>
+          <Set name="soLingerTime"><Property name="jetty.ssl.soLingerTime" default="-1"/></Set>
+        </New>
+    </Arg>
+  </Call>
+
+  <!-- ============================================================= -->
+  <!-- Create a TLS (SSL) Context Factory  for later reuse           -->
+  <!-- ============================================================= -->
+  <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
+    <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" default="etc/keystore"/></Set>
+    <Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
+    <Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
+    <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" default="etc/keystore"/></Set>
+    <Set name="TrustStorePassword"><Property name="jetty.sslContext.trustStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
+    <Set name="EndpointIdentificationAlgorithm"></Set>
+    <Set name="NeedClientAuth"><Property name="jetty.sslContext.needClientAuth" default="false"/></Set>
+    <Set name="WantClientAuth"><Property name="jetty.sslContext.wantClientAuth" default="false"/></Set>
+    <Set name="ExcludeCipherSuites">
+     <Array type="String">
       <Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
       <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
       <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
@@ -22,8 +48,9 @@
       <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
       <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
       <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
-    </Array>
-  </Set>
+     </Array>
+    </Set>
+  </New>
 
   <!-- =========================================================== -->
   <!-- Create a TLS specific HttpConfiguration based on the        -->
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml
index d26b427..4c8cb53 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty-testrealm.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
     <!-- =========================================================== -->
     <!-- Configure Authentication Login Service                      -->
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
index 170530b..a3850c9 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/jetty.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 
 <!-- =============================================================== -->
@@ -15,11 +15,11 @@
     <!-- Server Thread Pool                                          -->
     <!-- =========================================================== -->
     <Get name="ThreadPool">
-      <!-- Default queued blocking threadpool -->
       <Set name="minThreads">10</Set>
       <Set name="maxThreads">200</Set>
     </Get>
 
+
     <!-- =========================================================== -->
     <!-- Set handler Collection Structure                            -->
     <!-- =========================================================== -->
@@ -43,7 +43,7 @@
 
     <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
       <Set name="secureScheme">https</Set>
-      <Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
+      <Set name="securePort"><Property name="jetty.httpConfig.securePort" default="8443" /></Set>
       <Set name="outputBufferSize">32768</Set>
       <Set name="requestHeaderSize">8192</Set>
       <Set name="responseHeaderSize">8192</Set>
@@ -63,21 +63,25 @@
 
 
     <!-- =========================================================== -->
-    <!-- jetty-jndi by default                                       -->
-    <!-- =========================================================== -->
-    <Call class="org.eclipse.jetty.webapp.Configuration$ClassList" name="setServerDefault">
-      <Arg><Ref refid="Server" /></Arg>
-      <Call name="addAfter">
-        <Arg name="afterClass">org.eclipse.jetty.webapp.FragmentConfiguration</Arg>
-        <Arg>
-          <Array type="String">
-            <Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
-            <Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
-            <Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
-          </Array>
-        </Arg>
-      </Call>
+    <!-- Set up the list of default configuration classes            -->
+    <!-- =========================================================== -->    
+    <Call name="setAttribute">
+       <Arg>org.eclipse.jetty.webapp.configuration</Arg>
+       <Arg>
+        <New class="org.eclipse.jetty.webapp.Configuration$ClassList">
+          <Arg>
+            <Array type="String">
+              <Item>org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.WebXmlConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.MetaInfConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.FragmentConfiguration</Item>
+              <Item>org.eclipse.jetty.webapp.JettyWebXmlConfiguration</Item>  
+            </Array>
+          </Arg>
+        </New>
+       </Arg>
     </Call>
+   
 
     <Call class="java.lang.System" name="setProperty">
       <Arg>java.naming.factory.initial</Arg>
diff --git a/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml b/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml
index 1d61c93..d54d76f 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml
+++ b/jetty-osgi/test-jetty-osgi/src/test/config/etc/webdefault.xml
@@ -1,113 +1,142 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!-- ===================================================================== -->
-<!-- This file contains the default descriptor for web applications.       -->
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<!-- The intent of this descriptor is to include jetty specific or common  -->
-<!-- configuration for all webapps.   If a context has a webdefault.xml    -->
-<!-- descriptor, it is applied before the contexts own web.xml file        -->
-<!--                                                                       -->
-<!-- A context may be assigned a default descriptor by:                    -->
-<!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
-<!--  + Passed an arg to addWebApplications                                -->
-<!--                                                                       -->
-<!-- This file is used both as the resource within the jetty.jar (which is -->
-<!-- used as the default if no explicit defaults descriptor is set) and it -->
-<!-- is copied to the etc directory of the Jetty distro and explicitly     -->
-<!-- by the jetty.xml file.                                                -->
-<!--                                                                       -->
-<!-- ===================================================================== -->
-<web-app
-   xmlns="http://java.sun.com/xml/ns/javaee"
+<web-app 
+   xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
-   metadata-complete="true"
-   version="2.5">
+   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+   metadata-complete="false"
+   version="3.1"> 
+
+  <!-- ===================================================================== -->
+  <!-- This file contains the default descriptor for web applications.       -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+  <!-- The intent of this descriptor is to include jetty specific or common  -->
+  <!-- configuration for all webapps.   If a context has a webdefault.xml    -->
+  <!-- descriptor, it is applied before the context's own web.xml file       -->
+  <!--                                                                       -->
+  <!-- A context may be assigned a default descriptor by calling             -->
+  <!-- WebAppContext.setDefaultsDescriptor(String).                          -->
+  <!--                                                                       -->
+  <!-- This file is present in the jetty-webapp.jar, and is used as the      -->
+  <!-- defaults descriptor if no other is explicitly set on a context.       -->
+  <!--                                                                       -->
+  <!-- A copy of this file is also placed into the $JETTY_HOME/etc dir of    -->
+  <!-- the  distribution, and is referenced by some of the other xml files,  -->
+  <!-- eg the jetty-deploy.xml file.                                         -->
+  <!-- ===================================================================== -->
 
   <description>
-    Default web.xml file.
+    Default web.xml file.  
     This file is applied to a Web application before it's own WEB_INF/web.xml file
   </description>
 
+  <!-- ==================================================================== -->
+  <!-- Removes static references to beans from javax.el.BeanELResolver to   -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class>
+  </listener>
+  
+  <!-- ==================================================================== -->
+  <!-- Removes static cache of Methods from java.beans.Introspector to      -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->  
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class>
+  </listener>
+  
 
   <!-- ==================================================================== -->
   <!-- Context params to control Session Cookies                            -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- UNCOMMENT TO ACTIVATE
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
-    <param-value>127.0.0.1</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
-    <param-value>/</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
-    <param-value>-1</param-value>
-  </context-param>
+  <!--
+    UNCOMMENT TO ACTIVATE 
+    <context-param> 
+      <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> 
+      <param-value>127.0.0.1</param-value> 
+    </context-param> 
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+      <param-value>/</param-value>
+    </context-param>
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+      <param-value>-1</param-value>
+    </context-param>
   -->
 
-
   <!-- ==================================================================== -->
   <!-- The default servlet.                                                 -->
   <!-- This servlet, normally mapped to /, provides the handling for static -->
   <!-- content, OPTIONS and TRACE methods for the context.                  -->
   <!-- The following initParameters are supported:                          -->
-  <!--                                                                      -->
-  <!--   acceptRanges     If true, range requests and responses are         -->
-  <!--                    supported                                         -->
-  <!--                                                                      -->
-  <!--   dirAllowed       If true, directory listings are returned if no    -->
-  <!--                    welcome file is found. Else 403 Forbidden.        -->
-  <!--                                                                      -->
-  <!--   welcomeServlets  If true, attempt to dispatch to welcome files     -->
-  <!--                    that are servlets, if no matching static          -->
-  <!--                    resources can be found.                           -->
-  <!--                                                                      -->
-  <!--   redirectWelcome  If true, redirect welcome file requests           -->
-  <!--                    else use request dispatcher forwards              -->
-  <!--                                                                      -->
-  <!--   gzip             If set to true, then static content will be served-->
-  <!--                    as gzip content encoded if a matching resource is -->
-  <!--                    found ending with ".gz"                           -->
-  <!--                                                                      -->
-  <!--   resoureBase      Can be set to replace the context resource base   -->
-  <!--                                                                      -->
-  <!--   relativeResourceBase                                               -->
-  <!--                    Set with a pathname relative to the base of the   -->
-  <!--                    servlet context root. Useful for only serving     -->
-  <!--                    static content from only specific subdirectories. -->
-  <!--                                                                      -->
-  <!--   useFileMappedBuffer                                                -->
-  <!--                    If set to true (the default), a  memory mapped    -->
-  <!--                    file buffer will be used to serve static content  -->
-  <!--                    when using an NIO connector. Setting this value   -->
-  <!--                    to false means that a direct buffer will be used  -->
-  <!--                    instead. If you are having trouble with Windows   -->
-  <!--                    file locking, set this to false.                  -->
-  <!--                                                                      -->
-  <!--  cacheControl      If set, all static content will have this value   -->
-  <!--                    set as the cache-control header.                  -->
-  <!--                                                                      -->
-  <!--  maxCacheSize      Maximum size of the static resource cache         -->
-  <!--                                                                      -->
-  <!--  maxCachedFileSize Maximum size of any single file in the cache      -->
-  <!--                                                                      -->
-  <!--  maxCachedFiles    Maximum number of files in the cache              -->
-  <!--                                                                      -->
-  <!--  cacheType         "nio", "bio" or "both" to determine the type(s)   -->
-  <!--                    of resource cache. A bio cached buffer may be used-->
-  <!--                    by nio but is not as efficient as a nio buffer.   -->
-  <!--                    An nio cached buffer may not be used by bio.      -->
-  <!--                                                                      -->
-  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!--  
+ *  acceptRanges      If true, range requests and responses are
+ *                    supported
+ *
+ *  dirAllowed        If true, directory listings are returned if no
+ *                    welcome file is found. Else 403 Forbidden.
+ *
+ *  welcomeServlets   If true, attempt to dispatch to welcome files
+ *                    that are servlets, but only after no matching static
+ *                    resources could be found. If false, then a welcome
+ *                    file must exist on disk. If "exact", then exact
+ *                    servlet matches are supported without an existing file.
+ *                    Default is true.
+ *
+ *                    This must be false if you want directory listings,
+ *                    but have index.jsp in your welcome file list.
+ *
+ *  redirectWelcome   If true, welcome files are redirected rather than
+ *                    forwarded to.
+ *
+ *  gzip              If set to true, then static content will be served as
+ *                    gzip content encoded if a matching resource is
+ *                    found ending with ".gz"
+ *
+ *  resourceBase      Set to replace the context resource base
+ *
+ *  resourceCache     If set, this is a context attribute name, which the servlet
+ *                    will use to look for a shared ResourceCache instance.
+ *
+ *  relativeResourceBase
+ *                    Set with a pathname relative to the base of the
+ *                    servlet context root. Useful for only serving static content out
+ *                    of only specific subdirectories.
+ *
+ *  pathInfoOnly      If true, only the path info will be applied to the resourceBase
+ *
+ *  stylesheet        Set with the location of an optional stylesheet that will be used
+ *                    to decorate the directory listing html.
+ *
+ *  aliases           If True, aliases of resources are allowed (eg. symbolic
+ *                    links and caps variations). May bypass security constraints.
+ *                    
+ *  etags             If True, weak etags will be generated and handled.
+ *
+ *  maxCacheSize      The maximum total size of the cache or 0 for no cache.
+ *  maxCachedFileSize The maximum size of a file to cache
+ *  maxCachedFiles    The maximum number of files to cache
+ *
+ *  useFileMappedBuffer
+ *                    If set to true, it will use mapped file buffers to serve static content
+ *                    when using an NIO connector. Setting this value to false means that
+ *                    a direct buffer will be used instead of a mapped file buffer.
+ *                    This file sets the value to true.
+ *
+ *  cacheControl      If set, all static content will have this value set as the cache-control
+ *                    header.
+ *
+ -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet>
     <servlet-name>default</servlet-name>
     <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
     <init-param>
+      <param-name>aliases</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
       <param-name>acceptRanges</param-name>
       <param-value>true</param-value>
     </init-param>
@@ -129,19 +158,19 @@
     </init-param>
     <init-param>
       <param-name>maxCachedFileSize</param-name>
-      <param-value>10000000</param-value>
+      <param-value>200000000</param-value>
     </init-param>
     <init-param>
       <param-name>maxCachedFiles</param-name>
-      <param-value>1000</param-value>
-    </init-param>
-    <init-param>
-      <param-name>cacheType</param-name>
-      <param-value>both</param-value>
+      <param-value>2048</param-value>
     </init-param>
     <init-param>
       <param-name>gzip</param-name>
-      <param-value>true</param-value>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>etags</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
       <param-name>useFileMappedBuffer</param-name>
@@ -149,6 +178,12 @@
     </init-param>
     <!--
     <init-param>
+      <param-name>resourceCache</param-name>
+      <param-value>resourceCache</param-value>
+    </init-param>
+    -->
+    <!--
+    <init-param>
       <param-name>cacheControl</param-name>
       <param-value>max-age=3600,public</param-value>
     </init-param>
@@ -156,18 +191,21 @@
     <load-on-startup>0</load-on-startup>
   </servlet>
 
-  <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>default</servlet-name>
+    <url-pattern>/</url-pattern>
+  </servlet-mapping>
 
 
   <!-- ==================================================================== -->
   <!-- JSP Servlet                                                          -->
-  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- This is the jasper JSP servlet.                                      -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
-  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
-  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
-  <!-- following initialization parameters (default values are in square    -->
-  <!-- brackets):                                                           -->
+  <!-- used by the jsp container to support JSP pages.  Traditionally,      -->
+  <!-- this servlet is mapped to URL pattern "*.jsp".  This servlet         -->
+  <!-- supports the following initialization parameters (default values     -->
+  <!-- are in square brackets):                                             -->
   <!--                                                                      -->
   <!--   checkInterval       If development is false and reloading is true, -->
   <!--                       background compiles are enabled. checkInterval -->
@@ -175,7 +213,7 @@
   <!--                       if a JSP page needs to be recompiled. [300]    -->
   <!--                                                                      -->
   <!--   compiler            Which compiler Ant should use to compile JSP   -->
-  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       pages.  See the Ant documentation for more     -->
   <!--                       information. [javac]                           -->
   <!--                                                                      -->
   <!--   classdebuginfo      Should the class file be compiled with         -->
@@ -236,30 +274,31 @@
   <!--   xpoweredBy          Determines whether X-Powered-By response       -->
   <!--                       header is added by generated servlet  [false]  -->
   <!--                                                                      -->
-  <!-- If you wish to use Jikes to compile JSP pages:                       -->
-  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
-  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
-  <!--   to cause Jikes to emit error messages in a format compatible with  -->
-  <!--   Jasper.                                                            -->
-  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
-  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet id="jsp">
     <servlet-name>jsp</servlet-name>
-    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
     <init-param>
-        <param-name>logVerbosityLevel</param-name>
-        <param-value>DEBUG</param-value>
+      <param-name>logVerbosityLevel</param-name>
+      <param-value>DEBUG</param-value>
     </init-param>
     <init-param>
-        <param-name>fork</param-name>
-        <param-value>false</param-value>
+      <param-name>fork</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
-        <param-name>xpoweredBy</param-name>
-        <param-value>false</param-value>
+      <param-name>xpoweredBy</param-name>
+      <param-value>false</param-value>
     </init-param>
-    <!--
+    <init-param>
+      <param-name>compilerTargetVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerSourceVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
+    <!--  
     <init-param>
         <param-name>classpath</param-name>
         <param-value>?</param-value>
@@ -280,50 +319,10 @@
     <url-pattern>*.XSP</url-pattern>
   </servlet-mapping>
 
+
   <!-- ==================================================================== -->
-  <!-- Dynamic Servlet Invoker.                                             -->
-  <!-- This servlet invokes anonymous servlets that have not been defined   -->
-  <!-- in the web.xml or by other means. The first element of the pathInfo  -->
-  <!-- of a request passed to the envoker is treated as a servlet name for  -->
-  <!-- an existing servlet, or as a class name of a new servlet.            -->
-  <!-- This servlet is normally mapped to /servlet/*                        -->
-  <!-- This servlet support the following initParams:                       -->
-  <!--                                                                      -->
-  <!--  nonContextServlets       If false, the invoker can only load        -->
-  <!--                           servlets from the contexts classloader.    -->
-  <!--                           This is false by default and setting this  -->
-  <!--                           to true may have security implications.    -->
-  <!--                                                                      -->
-  <!--  verbose                  If true, log dynamic loads                 -->
-  <!--                                                                      -->
-  <!--  *                        All other parameters are copied to the     -->
-  <!--                           each dynamic servlet as init parameters    -->
+  <!-- Default session configuration                                        -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- Uncomment for dynamic invocation
-  <servlet>
-    <servlet-name>invoker</servlet-name>
-    <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
-    <init-param>
-      <param-name>verbose</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>nonContextServlets</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>dynamicParam</param-name>
-      <param-value>anyValue</param-value>
-    </init-param>
-    <load-on-startup>0</load-on-startup>
-  </servlet>
-
-  <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
-  -->
-
-
-
-  <!-- ==================================================================== -->
   <session-config>
     <session-timeout>30</session-timeout>
   </session-config>
@@ -331,7 +330,7 @@
   <!-- ==================================================================== -->
   <!-- Default MIME mappings                                                -->
   <!-- The default MIME mappings are provided by the mime.properties        -->
-  <!-- resource in the org.eclipse.jetty.server.jar file.  Additional or modified  -->
+  <!-- resource in the jetty-http.jar file.  Additional or modified         -->
   <!-- mappings may be specified here                                       -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- UNCOMMENT TO ACTIVATE
@@ -342,6 +341,8 @@
   -->
 
   <!-- ==================================================================== -->
+  <!-- Default welcome files                                                -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <welcome-file-list>
     <welcome-file>index.html</welcome-file>
     <welcome-file>index.htm</welcome-file>
@@ -349,48 +350,170 @@
   </welcome-file-list>
 
   <!-- ==================================================================== -->
+  <!-- Default locale encodings                                             -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <locale-encoding-mapping-list>
-    <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ar</locale>
+      <encoding>ISO-8859-6</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>be</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>bg</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ca</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>cs</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>da</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>de</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>el</locale>
+      <encoding>ISO-8859-7</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>en</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>es</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>et</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fi</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fr</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hr</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hu</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>is</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>it</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>iw</locale>
+      <encoding>ISO-8859-8</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ja</locale>
+      <encoding>Shift_JIS</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ko</locale>
+      <encoding>EUC-KR</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lt</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lv</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>mk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>nl</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>no</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pt</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ro</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ru</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sh</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sk</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sq</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sr</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sv</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>tr</locale>
+      <encoding>ISO-8859-9</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>uk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh</locale>
+      <encoding>GB2312</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh_TW</locale>
+      <encoding>Big5</encoding>
+    </locale-encoding-mapping>
   </locale-encoding-mapping-list>
 
+  <!-- ==================================================================== -->
+  <!-- Disable TRACE method with security constraint                        -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <security-constraint>
     <web-resource-collection>
       <web-resource-name>Disable TRACE</web-resource-name>
@@ -399,6 +522,13 @@
     </web-resource-collection>
     <auth-constraint/>
   </security-constraint>
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Enable everything but TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method-omission>TRACE</http-method-omission>
+    </web-resource-collection>
+  </security-constraint>
 
 </web-app>
 
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java
index 1c1b67e..10510ff 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootContextAsService.java
@@ -18,18 +18,10 @@
 
 package org.eclipse.jetty.osgi.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import javax.inject.Inject;
 
 import org.eclipse.jetty.client.HttpClient;
@@ -40,14 +32,21 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.CoreOptions;
 import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
 /**
  * TestJettyOSGiBootContextAsService
  * 
@@ -70,7 +69,7 @@
     {
         ArrayList<Option> options = new ArrayList<Option>();
         options.add(CoreOptions.junitBundles());
-        options.addAll(configureJettyHomeAndPort("jetty-selector.xml"));
+        options.addAll(configureJettyHomeAndPort("jetty-http.xml"));
         options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*"));
         options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
 
@@ -99,7 +98,8 @@
                 + "/jetty-deployer.xml;"
                 + etc
                 + "/jetty-testrealm.xml"));
-        options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
+        options.add(systemProperty("jetty.http.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT)));
+        options.add(systemProperty("jetty.ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT)));
         options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));
         return options;
     }
@@ -122,7 +122,7 @@
         try
         {
             client.start();
-            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/acme/index.html");
+            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/acme/index.html");
             assertEquals(HttpStatus.OK_200, response.getStatus());
 
             String content = new String(response.getContent());
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java
index 87919bc..2608f57 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootCore.java
@@ -18,14 +18,9 @@
 
 package org.eclipse.jetty.osgi.test;
  
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import javax.inject.Inject;
 
 import org.junit.Ignore;
@@ -39,6 +34,10 @@
 import org.ops4j.pax.exam.options.MavenUrlReference.VersionResolver;
 import org.osgi.framework.BundleContext;
 
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
 
 /**
  * Default OSGi setup integration test
@@ -47,7 +46,10 @@
 public class TestJettyOSGiBootCore
 {
     private static final String LOG_LEVEL = "WARN";
-    public static int DEFAULT_JETTY_HTTP_PORT = 9876;
+    
+    // TODO these should be dynamic
+    public static final int DEFAULT_HTTP_PORT = 9876;
+    public static final int DEFAULT_SSL_PORT = 9877;
 
     @Inject
     private BundleContext bundleContext;
@@ -71,7 +73,8 @@
     { 
         List<Option> res = new ArrayList<Option>();
         // get the jetty home config from the osgi boot bundle.
-        res.add(CoreOptions.systemProperty("jetty.port").value(String.valueOf(DEFAULT_JETTY_HTTP_PORT)));
+        res.add(CoreOptions.systemProperty("jetty.http.port").value(String.valueOf(DEFAULT_HTTP_PORT)));
+        res.add(CoreOptions.systemProperty("jetty.ssl.port").value(String.valueOf(DEFAULT_SSL_PORT)));
         res.add(CoreOptions.systemProperty("jetty.home.bundle").value("org.eclipse.jetty.osgi.boot"));
         res.addAll(coreJettyDependencies());
         return res;
@@ -93,10 +96,10 @@
         res.add(mavenBundle().groupId( "org.apache.geronimo.specs" ).artifactId( "geronimo-jta_1.1_spec" ).version("1.1.1").noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty.orbit" ).artifactId( "javax.mail.glassfish" ).version( "1.4.1.v201005082020" ).noStart());
 
+        res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-util" ).versionAsInProject().noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-deploy" ).versionAsInProject().noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-server" ).versionAsInProject().noStart());  
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-servlet" ).versionAsInProject().noStart());  
-        res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-util" ).versionAsInProject().noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-http" ).versionAsInProject().noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-xml" ).versionAsInProject().noStart());
         res.add(mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-webapp" ).versionAsInProject().noStart());
@@ -141,7 +144,7 @@
         res.add(mavenBundle().groupId("org.mortbay.jasper").artifactId("apache-jsp").versionAsInProject());
         res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("apache-jsp").versionAsInProject());
         res.add(mavenBundle().groupId("org.glassfish.web").artifactId("javax.servlet.jsp.jstl").versionAsInProject());
-        res.add(mavenBundle().groupId("org.eclipse.jetty.orbit").artifactId("org.eclipse.jdt.core").versionAsInProject());
+        res.add(mavenBundle().groupId("org.eclipse.jdt.core.compiler").artifactId("ecj").versionAsInProject());
         res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-boot-jsp").versionAsInProject().noStart());
         return res;
     }
@@ -170,6 +173,6 @@
     @Test
     public void testHttpService() throws Exception
     {
-        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", DEFAULT_JETTY_HTTP_PORT);
+        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", DEFAULT_HTTP_PORT);
     }
 }
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java
new file mode 100644
index 0000000..2851c7e
--- /dev/null
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootHTTP2.java
@@ -0,0 +1,112 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.osgi.test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.inject.Inject;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+/**
+ * HTTP2 setup.
+ */
+@RunWith(PaxExam.class)
+public class TestJettyOSGiBootHTTP2
+{
+    private static final String LOG_LEVEL = "WARN";
+
+
+    @Inject
+    private BundleContext bundleContext;
+
+    @Configuration
+    public Option[] config()
+    {
+        ArrayList<Option> options = new ArrayList<Option>();
+        options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort(true,"jetty-http2.xml"));
+        options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
+        options.addAll(http2JettyDependencies());
+        options.add(CoreOptions.junitBundles());
+        options.addAll(TestJettyOSGiBootCore.httpServiceJetty());
+        options.addAll(Arrays.asList(options(systemProperty("pax.exam.logging").value("none"))));
+        options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL))));
+        options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.osgi.LEVEL").value(LOG_LEVEL))));
+        return options.toArray(new Option[options.size()]);
+    }
+
+    public static List<Option> http2JettyDependencies()
+    {
+        List<Option> res = new ArrayList<Option>();
+        res.add(CoreOptions.systemProperty("jetty.http.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT)));
+        res.add(CoreOptions.systemProperty("jetty.ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT)));
+
+        String alpnBoot = System.getProperty("mortbay-alpn-boot");
+        if (alpnBoot == null) { throw new IllegalStateException("Define path to alpn boot jar as system property -Dmortbay-alpn-boot"); }
+        File checkALPNBoot = new File(alpnBoot);
+        if (!checkALPNBoot.exists()) { throw new IllegalStateException("Unable to find the alpn boot jar here: " + alpnBoot); }
+
+        res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + alpnBoot));
+
+        res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
+        res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-server").versionAsInProject().start());
+
+        res.add(mavenBundle().groupId("org.eclipse.jetty.http2").artifactId("http2-common").versionAsInProject().noStart());
+        res.add(mavenBundle().groupId("org.eclipse.jetty.http2").artifactId("http2-hpack").versionAsInProject().noStart());
+        res.add(mavenBundle().groupId("org.eclipse.jetty.http2").artifactId("http2-server").versionAsInProject().noStart());
+        return res;
+    }
+ 
+    @Test
+    public void checkALPNBootOnBootstrapClasspath() throws Exception
+    {
+        Class<?> alpn = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.alpn.ALPN");
+        Assert.assertNotNull(alpn);
+        Assert.assertNull(alpn.getClassLoader());
+    }
+    
+    @Ignore
+    @Test
+    public void assertAllBundlesActiveOrResolved() throws Exception
+    {
+        TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext);
+    }
+
+    
+    @Test
+    public void testHTTP2OnHttpService() throws Exception
+    {
+        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", TestJettyOSGiBootCore.DEFAULT_SSL_PORT);
+    }
+
+}
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java
deleted file mode 100644
index 745f9c7..0000000
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootSpdy.java
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.osgi.test;
-
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.options;
-
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
-/**
- * SPDY setup.
- */
-@RunWith(PaxExam.class)
-public class TestJettyOSGiBootSpdy
-{
-    private static final String LOG_LEVEL = "WARN";
-    
-    private static final String JETTY_SPDY_PORT = "jetty.spdy.port";
-
-    private static final int DEFAULT_JETTY_SPDY_PORT = 9877;
-
-    @Inject
-    private BundleContext bundleContext;
-
-    @Configuration
-    public Option[] config()
-    {
-        ArrayList<Option> options = new ArrayList<Option>();
-        options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort("jetty-spdy.xml"));
-        options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
-        options.addAll(spdyJettyDependencies());
-        options.add(CoreOptions.junitBundles());
-        options.addAll(TestJettyOSGiBootCore.httpServiceJetty());
-        options.addAll(Arrays.asList(options(systemProperty("pax.exam.logging").value("none"))));
-        options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL))));
-        options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.LEVEL").value(LOG_LEVEL))));
-        return options.toArray(new Option[options.size()]);
-    }
-
-    public static List<Option> spdyJettyDependencies()
-    {
-        List<Option> res = new ArrayList<Option>();
-        res.add(CoreOptions.systemProperty(JETTY_SPDY_PORT).value(String.valueOf(DEFAULT_JETTY_SPDY_PORT)));
-
-        String alpnBoot = System.getProperty("mortbay-alpn-boot");
-        if (alpnBoot == null) { throw new IllegalStateException("Define path to alpn boot jar as system property -Dmortbay-alpn-boot"); }
-        File checkALPNBoot = new File(alpnBoot);
-        if (!checkALPNBoot.exists()) { throw new IllegalStateException("Unable to find the alpn boot jar here: " + alpnBoot); }
-
-
-        res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + alpnBoot));
-
-        res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
-        res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-server").versionAsInProject().start());
-
-        res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-client").versionAsInProject().noStart());
-        res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-core").versionAsInProject().noStart());
-        res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-server").versionAsInProject().noStart());
-        res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-common").versionAsInProject().noStart());
-        res.add(mavenBundle().groupId("org.eclipse.jetty.spdy").artifactId("spdy-http-server").versionAsInProject().noStart());
-        return res;
-    }
-
-    @Test
-    public void checkALPNBootOnBootstrapClasspath() throws Exception
-    {
-        Class<?> alpn = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.alpn.ALPN");
-        Assert.assertNotNull(alpn);
-        Assert.assertNull(alpn.getClassLoader());
-    }
-
-    @Ignore
-    @Test
-    public void assertAllBundlesActiveOrResolved()
-    {
-        TestOSGiUtil.debugBundles(bundleContext);
-        TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext);
-    }
-
-    @Test
-    public void testSpdyOnHttpService() throws Exception
-    {
-        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "https", DEFAULT_JETTY_SPDY_PORT);
-    }
-
-}
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java
index a0b306f..ee9904c 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWebAppAsService.java
@@ -18,18 +18,10 @@
 
 package org.eclipse.jetty.osgi.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import javax.inject.Inject;
 
 import org.eclipse.jetty.client.HttpClient;
@@ -41,13 +33,20 @@
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.CoreOptions;
 import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
 /**
  * TestJettyOSGiBootWebAppAsService
  * 
@@ -72,7 +71,7 @@
     {
         ArrayList<Option> options = new ArrayList<Option>();
         options.add(CoreOptions.junitBundles());
-        options.addAll(configureJettyHomeAndPort("jetty-selector.xml"));
+        options.addAll(configureJettyHomeAndPort("jetty-http.xml"));
         options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*"));
         options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils",
                                                "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal",
@@ -102,7 +101,8 @@
                 + "/jetty-deployer.xml;"
                 + etc
                 + "/jetty-testrealm.xml"));
-        options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
+        options.add(systemProperty("jetty.http.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT)));
+        options.add(systemProperty("jetty.ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT)));
         options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));
         return options;
     }
@@ -137,7 +137,7 @@
         {
             client.start();
 
-            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/acme/index.html");
+            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/acme/index.html");
             assertEquals(HttpStatus.OK_200, response.getStatus());
 
             String content = new String(response.getContent());
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java
index d893aba..4aacdfd 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithAnnotations.java
@@ -18,17 +18,10 @@
 
 package org.eclipse.jetty.osgi.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import javax.inject.Inject;
 
 import org.eclipse.jetty.client.HttpClient;
@@ -45,6 +38,12 @@
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.osgi.framework.BundleContext;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
 /**
  * Pax-Exam to make sure the jetty-osgi-boot can be started along with the
  * httpservice web-bundle. Then make sure we can deploy an OSGi service on the
@@ -62,10 +61,9 @@
     @Configuration
     public static Option[] configure()
     {
-
         ArrayList<Option> options = new ArrayList<Option>();
         options.add(CoreOptions.junitBundles());
-        options.addAll(configureJettyHomeAndPort("jetty-selector.xml"));
+        options.addAll(configureJettyHomeAndPort("jetty-http.xml"));
         options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.sql.*","javax.xml.*", "javax.activation.*"));
         options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils",
                                                "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal",
@@ -75,7 +73,7 @@
         options.addAll(Arrays.asList(options(systemProperty("pax.exam.logging").value("none"))));
         options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL))));
         options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.annotations.LEVEL").value(LOG_LEVEL))));
-        //options.addAll(TestJettyOSGiBootCore.consoleDependencies());
+        // options.addAll(TestJettyOSGiBootCore.consoleDependencies());
         options.addAll(jspDependencies());
         options.addAll(annotationDependencies());
         return options.toArray(new Option[options.size()]);
@@ -101,7 +99,8 @@
                 + "/jetty-testrealm.xml";
 
         options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs));
-        options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
+        options.add(systemProperty("jetty.http.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT)));
+        options.add(systemProperty("jetty.ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT)));
         options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));
         return options;
     }
@@ -135,7 +134,7 @@
     @Test
     public void testHttpService() throws Exception
     {
-        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT);
+        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_HTTP_PORT);
     }
 
  
@@ -143,17 +142,18 @@
     @Test
     public void testIndex() throws Exception
     {        
+        // TestOSGiUtil.debugBundles(bundleContext);
         HttpClient client = new HttpClient();
         try
         {
             client.start();
-            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/index.html");
+            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/index.html");
             assertEquals(HttpStatus.OK_200, response.getStatus());
 
             String content = new String(response.getContent());
             assertTrue(content.contains("<h1>Servlet 3.1 Test WebApp</h1>"));
             
-            Request req = client.POST("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/test");
+            Request req = client.POST("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/test");
             response = req.send();
             content = new String(response.getContent());
             assertTrue(content.contains("<p><b>Result: <span class=\"pass\">PASS</span></p>"));
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java
index 6e4718b..48e82e5 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestJettyOSGiBootWithJsp.java
@@ -18,17 +18,10 @@
 
 package org.eclipse.jetty.osgi.test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import javax.inject.Inject;
 
 import org.eclipse.jetty.client.HttpClient;
@@ -44,6 +37,12 @@
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.osgi.framework.BundleContext;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
 /**
  * Pax-Exam to make sure the jetty-osgi-boot can be started along with the
  * httpservice web-bundle. Then make sure we can deploy an OSGi service on the
@@ -52,7 +51,7 @@
 @RunWith(PaxExam.class)
 public class TestJettyOSGiBootWithJsp
 {
-    private static final String LOG_LEVEL = "INFO";
+    private static final String LOG_LEVEL = "WARN";
 
     @Inject
     BundleContext bundleContext = null;
@@ -60,10 +59,9 @@
     @Configuration
     public static Option[] configure()
     {
-
         ArrayList<Option> options = new ArrayList<Option>();
         options.add(CoreOptions.junitBundles());
-        options.addAll(configureJettyHomeAndPort("jetty-selector.xml"));
+        options.addAll(configureJettyHomeAndPort(false,"jetty-http.xml"));
         options.add(CoreOptions.bootDelegationPackages("org.xml.sax", "org.xml.*", "org.w3c.*", "javax.xml.*", "javax.activation.*"));
         options.add(CoreOptions.systemPackages("com.sun.org.apache.xalan.internal.res","com.sun.org.apache.xml.internal.utils",
                                                "com.sun.org.apache.xml.internal.utils", "com.sun.org.apache.xpath.internal",
@@ -73,33 +71,38 @@
         options.addAll(Arrays.asList(options(systemProperty("pax.exam.logging").value("none"))));
         options.addAll(Arrays.asList(options(systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value(LOG_LEVEL))));
         options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.LEVEL").value(LOG_LEVEL))));
-        options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.annotations.LEVEL").value("DEBUG"))));
+        options.addAll(Arrays.asList(options(systemProperty("org.eclipse.jetty.osgi.LEVEL").value(LOG_LEVEL))));
         options.addAll(jspDependencies());
         return options.toArray(new Option[options.size()]);
     }
 
-    public static List<Option> configureJettyHomeAndPort(String jettySelectorFileName)
+    public static List<Option> configureJettyHomeAndPort(boolean ssl,String jettySelectorFileName)
     {
         File etcFolder = new File("src/test/config/etc");
         String etc = "file://" + etcFolder.getAbsolutePath();
         List<Option> options = new ArrayList<Option>();
-        String xmlConfigs = etc     + "/jetty.xml;"
+        String xmlConfigs = etc     + "/jetty.xml";
+        if (ssl)
+            xmlConfigs += ";" 
+                    + etc
+                    + "/jetty-ssl.xml;"
+                    + etc
+                    + "/jetty-https.xml;";
+        xmlConfigs+= ";"
                 + etc
                 + "/"
                 + jettySelectorFileName
                 + ";"
                 + etc
-                + "/jetty-ssl.xml;"
-                + etc
-                + "/jetty-https.xml;"
-                + etc
                 + "/jetty-deployer.xml;"
                 + etc
                 + "/jetty-testrealm.xml";
 
         options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs));
-        options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
+        options.add(systemProperty("jetty.http.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_HTTP_PORT)));
+        options.add(systemProperty("jetty.ssl.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_SSL_PORT)));
         options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));
+        options.add(systemProperty("jetty.base").value(etcFolder.getParentFile().getAbsolutePath()));
         return options;
     }
 
@@ -114,8 +117,8 @@
     }
 
 
-    @Test
     @Ignore
+    @Test
     public void assertAllBundlesActiveOrResolved()
     {
         TestOSGiUtil.debugBundles(bundleContext);
@@ -128,19 +131,20 @@
     @Test
     public void testHttpService() throws Exception
     {
-        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT);
+        TestOSGiUtil.testHttpServiceGreetings(bundleContext, "http", TestJettyOSGiBootCore.DEFAULT_HTTP_PORT);
     }
 
  
     @Test
     public void testJspDump() throws Exception
     {
-   
+        // TestOSGiUtil.debugBundles(bundleContext);
         HttpClient client = new HttpClient();
         try
         {
             client.start();
-            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT + "/jsp/jstl.jsp");
+            ContentResponse response = client.GET("http://127.0.0.1:" + TestJettyOSGiBootCore.DEFAULT_HTTP_PORT + "/jsp/jstl.jsp");
+            
             assertEquals(HttpStatus.OK_200, response.getStatus());
             String content = new String(response.getContent());
             assertTrue(content.contains("JSTL Example"));           
diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java
index a3547df..8b3a27d 100644
--- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java
+++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java
@@ -20,7 +20,6 @@
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.servlet.ServletException;
@@ -33,7 +32,6 @@
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Assert;
-import org.ops4j.pax.exam.Option;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml
index a531f46..9f0a73b 100644
--- a/jetty-overlay-deployer/pom.xml
+++ b/jetty-overlay-deployer/pom.xml
@@ -10,6 +10,7 @@
   <description>Overlayed deployer</description>
   <url>http://www.eclipse.org/jetty</url>
   <properties>
+    <bundle-symbolic-name>${project.groupId}.overlays</bundle-symbolic-name>
   </properties>
   <build>
     <plugins>
diff --git a/jetty-overlay-deployer/src/main/config/etc/jetty-overlay.xml b/jetty-overlay-deployer/src/main/config/etc/jetty-overlay.xml
index 62317a3..60f23d6 100644
--- a/jetty-overlay-deployer/src/main/config/etc/jetty-overlay.xml
+++ b/jetty-overlay-deployer/src/main/config/etc/jetty-overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Add a ContextProvider to the deployment manager                 -->
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=blue/WEB-INF/overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=blue/WEB-INF/overlay.xml
index 11c70ac..8d29a8a 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=blue/WEB-INF/overlay.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=blue/WEB-INF/overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=green/WEB-INF/overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=green/WEB-INF/overlay.xml
index f6cfcf6..7a15e73 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=green/WEB-INF/overlay.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=green/WEB-INF/overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=red/WEB-INF/overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=red/WEB-INF/overlay.xml
index 6a71455..90685db 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=red/WEB-INF/overlay.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/myfoo=red/WEB-INF/overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/root=root/WEB-INF/overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/root=root/WEB-INF/overlay.xml
index 287e1e0..ca23e18 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/instances/root=root/WEB-INF/overlay.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/instances/root=root/WEB-INF/overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.server.handler.ContextHandler">
   <!--
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml
index 16cba2a..4723bf7 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
   <Call class="org.eclipse.jetty.util.log.Log" name="info"><Arg>Executing jetty-web.xml for <Property name="overlay.instance"/></Arg></Call>
-</Configure>
\ No newline at end of file
+</Configure>
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/template.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/template.xml
index 3104fca..fddd63b 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/template.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/template.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.overlays.TemplateContext">
   <Set name="parentLoaderPriority" type="boolean">false</Set>
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-default.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-default.xml
index 22f82f4..d54d76f 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-default.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-default.xml
@@ -1,43 +1,68 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<web-app 
+   xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+   metadata-complete="false"
+   version="3.1"> 
 
   <!-- ===================================================================== -->
   <!-- This file contains the default descriptor for web applications.       -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
   <!-- The intent of this descriptor is to include jetty specific or common  -->
   <!-- configuration for all webapps.   If a context has a webdefault.xml    -->
-  <!-- descriptor, it is applied before the contexts own web.xml file        -->
+  <!-- descriptor, it is applied before the context's own web.xml file       -->
   <!--                                                                       -->
-  <!-- A context may be assigned a default descriptor by:                    -->
-  <!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
-  <!--  + Passed an arg to addWebApplications                                -->
+  <!-- A context may be assigned a default descriptor by calling             -->
+  <!-- WebAppContext.setDefaultsDescriptor(String).                          -->
   <!--                                                                       -->
-  <!-- This file is used both as the resource within the jetty.jar (which is -->
-  <!-- used as the default if no explicit defaults descriptor is set) and it -->
-  <!-- is copied to the etc directory of the Jetty distro and explicitly     -->
-  <!-- by the jetty.xml file.                                                -->
+  <!-- This file is present in the jetty-webapp.jar, and is used as the      -->
+  <!-- defaults descriptor if no other is explicitly set on a context.       -->
   <!--                                                                       -->
+  <!-- A copy of this file is also placed into the $JETTY_HOME/etc dir of    -->
+  <!-- the  distribution, and is referenced by some of the other xml files,  -->
+  <!-- eg the jetty-deploy.xml file.                                         -->
   <!-- ===================================================================== -->
-<web-app
-  xmlns="http://java.sun.com/xml/ns/javaee"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
-  metadata-complete="true"
-  version="2.5"
->
 
   <description>
     Default web.xml file.  
     This file is applied to a Web application before it's own WEB_INF/web.xml file
   </description>
 
+  <!-- ==================================================================== -->
+  <!-- Removes static references to beans from javax.el.BeanELResolver to   -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class>
+  </listener>
+  
+  <!-- ==================================================================== -->
+  <!-- Removes static cache of Methods from java.beans.Introspector to      -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->  
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class>
+  </listener>
+  
 
   <!-- ==================================================================== -->
   <!-- Context params to control Session Cookies                            -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!--
-    UNCOMMENT TO ACTIVATE <context-param> <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> <param-value>127.0.0.1</param-value> </context-param> <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionPath</param-name> <param-value>/</param-value> </context-param> <context-param> <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
-    <param-value>-1</param-value> </context-param>
+    UNCOMMENT TO ACTIVATE 
+    <context-param> 
+      <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> 
+      <param-value>127.0.0.1</param-value> 
+    </context-param> 
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+      <param-value>/</param-value>
+    </context-param>
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+      <param-value>-1</param-value>
+    </context-param>
   -->
 
   <!-- ==================================================================== -->
@@ -71,33 +96,39 @@
  *
  *  resourceBase      Set to replace the context resource base
  *
- *  resourceCache     If set, this is a context attribute name, which the servlet 
- *                    will use to look for a shared ResourceCache instance. 
- *                        
+ *  resourceCache     If set, this is a context attribute name, which the servlet
+ *                    will use to look for a shared ResourceCache instance.
+ *
  *  relativeResourceBase
  *                    Set with a pathname relative to the base of the
  *                    servlet context root. Useful for only serving static content out
  *                    of only specific subdirectories.
  *
+ *  pathInfoOnly      If true, only the path info will be applied to the resourceBase
+ *
+ *  stylesheet        Set with the location of an optional stylesheet that will be used
+ *                    to decorate the directory listing html.
+ *
  *  aliases           If True, aliases of resources are allowed (eg. symbolic
  *                    links and caps variations). May bypass security constraints.
+ *                    
+ *  etags             If True, weak etags will be generated and handled.
  *
  *  maxCacheSize      The maximum total size of the cache or 0 for no cache.
  *  maxCachedFileSize The maximum size of a file to cache
  *  maxCachedFiles    The maximum number of files to cache
  *
  *  useFileMappedBuffer
- *                    If set to true, it will use mapped file buffer to serve static content
- *                    when using NIO connector. Setting this value to false means that
+ *                    If set to true, it will use mapped file buffers to serve static content
+ *                    when using an NIO connector. Setting this value to false means that
  *                    a direct buffer will be used instead of a mapped file buffer.
- *                    By default, this is set to true.
+ *                    This file sets the value to true.
  *
  *  cacheControl      If set, all static content will have this value set as the cache-control
  *                    header.
+ *
  -->
- 
- 
-  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet>
     <servlet-name>default</servlet-name>
     <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
@@ -127,7 +158,7 @@
     </init-param>
     <init-param>
       <param-name>maxCachedFileSize</param-name>
-      <param-value>10000000</param-value>
+      <param-value>200000000</param-value>
     </init-param>
     <init-param>
       <param-name>maxCachedFiles</param-name>
@@ -135,16 +166,22 @@
     </init-param>
     <init-param>
       <param-name>gzip</param-name>
-      <param-value>true</param-value>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>etags</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
       <param-name>useFileMappedBuffer</param-name>
       <param-value>true</param-value>
     </init-param>
+    <!--
     <init-param>
       <param-name>resourceCache</param-name>
-      <param-value>org.eclipse.jetty.server.ResourceCache</param-value>
+      <param-value>resourceCache</param-value>
     </init-param>
+    -->
     <!--
     <init-param>
       <param-name>cacheControl</param-name>
@@ -162,13 +199,13 @@
 
   <!-- ==================================================================== -->
   <!-- JSP Servlet                                                          -->
-  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- This is the jasper JSP servlet.                                      -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
-  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
-  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
-  <!-- following initialization parameters (default values are in square    -->
-  <!-- brackets):                                                           -->
+  <!-- used by the jsp container to support JSP pages.  Traditionally,      -->
+  <!-- this servlet is mapped to URL pattern "*.jsp".  This servlet         -->
+  <!-- supports the following initialization parameters (default values     -->
+  <!-- are in square brackets):                                             -->
   <!--                                                                      -->
   <!--   checkInterval       If development is false and reloading is true, -->
   <!--                       background compiles are enabled. checkInterval -->
@@ -176,7 +213,7 @@
   <!--                       if a JSP page needs to be recompiled. [300]    -->
   <!--                                                                      -->
   <!--   compiler            Which compiler Ant should use to compile JSP   -->
-  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       pages.  See the Ant documentation for more     -->
   <!--                       information. [javac]                           -->
   <!--                                                                      -->
   <!--   classdebuginfo      Should the class file be compiled with         -->
@@ -237,19 +274,10 @@
   <!--   xpoweredBy          Determines whether X-Powered-By response       -->
   <!--                       header is added by generated servlet  [false]  -->
   <!--                                                                      -->
-  <!-- If you wish to use Jikes to compile JSP pages:                       -->
-  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
-  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
-  <!--   to cause Jikes to emit error messages in a format compatible with  -->
-  <!--   Jasper.                                                            -->
-  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
-  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <servlet
-    id="jsp"
-  >
+  <servlet id="jsp">
     <servlet-name>jsp</servlet-name>
-    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
     <init-param>
       <param-name>logVerbosityLevel</param-name>
       <param-value>DEBUG</param-value>
@@ -262,6 +290,14 @@
       <param-name>xpoweredBy</param-name>
       <param-value>false</param-value>
     </init-param>
+    <init-param>
+      <param-name>compilerTargetVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerSourceVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
     <!--  
     <init-param>
         <param-name>classpath</param-name>
@@ -285,6 +321,8 @@
 
 
   <!-- ==================================================================== -->
+  <!-- Default session configuration                                        -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <session-config>
     <session-timeout>30</session-timeout>
   </session-config>
@@ -292,7 +330,7 @@
   <!-- ==================================================================== -->
   <!-- Default MIME mappings                                                -->
   <!-- The default MIME mappings are provided by the mime.properties        -->
-  <!-- resource in the org.eclipse.jetty.server.jar file.  Additional or modified  -->
+  <!-- resource in the jetty-http.jar file.  Additional or modified         -->
   <!-- mappings may be specified here                                       -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- UNCOMMENT TO ACTIVATE
@@ -303,13 +341,17 @@
   -->
 
   <!-- ==================================================================== -->
+  <!-- Default welcome files                                                -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <welcome-file-list>
-    <welcome-file>index.jsp</welcome-file>
     <welcome-file>index.html</welcome-file>
     <welcome-file>index.htm</welcome-file>
+    <welcome-file>index.jsp</welcome-file>
   </welcome-file-list>
 
   <!-- ==================================================================== -->
+  <!-- Default locale encodings                                             -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <locale-encoding-mapping-list>
     <locale-encoding-mapping>
       <locale>ar</locale>
@@ -469,6 +511,9 @@
     </locale-encoding-mapping>
   </locale-encoding-mapping-list>
 
+  <!-- ==================================================================== -->
+  <!-- Disable TRACE method with security constraint                        -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <security-constraint>
     <web-resource-collection>
       <web-resource-name>Disable TRACE</web-resource-name>
@@ -477,6 +522,13 @@
     </web-resource-collection>
     <auth-constraint/>
   </security-constraint>
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Enable everything but TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method-omission>TRACE</http-method-omission>
+    </web-resource-collection>
+  </security-constraint>
 
 </web-app>
 
diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/root/WEB-INF/overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/root/WEB-INF/overlay.xml
index 813ca58..f3037a1 100644
--- a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/root/WEB-INF/overlay.xml
+++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/root/WEB-INF/overlay.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.eclipse.org/configure_9_3.dtd">
 
 
 <Configure class="org.eclipse.jetty.server.handler.ContextHandler">
diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml
index 9fd7b47..1471c2a 100644
--- a/jetty-plus/pom.xml
+++ b/jetty-plus/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-plus</artifactId>
@@ -14,59 +14,6 @@
   </properties>
   <build>
     <plugins>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-               <_nouses>true</_nouses>
-               <!-- Export-Package>
-                 org.eclipse.jetty.plus.annotation;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
-                 org.eclipse.jetty.plus.webapp;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
-                 org.eclipse.jetty.plus.jndi;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
-                 org.eclipse.jetty.plus.security;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
-               </Export-Package -->
-               <Import-Package>javax.sql.*,javax.security.*,javax.naming.*,
-               javax.servlet.*;version="[2.6.0,3.2)",javax.transaction.*;version="[1.1,1.3)",
-               *
-               </Import-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
       <!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
       with a snapshot. -->
       <plugin>
diff --git a/jetty-plus/src/main/config/etc/jetty-plus.xml b/jetty-plus/src/main/config/etc/jetty-plus.xml
index bfbcce5..ed30824 100644
--- a/jetty-plus/src/main/config/etc/jetty-plus.xml
+++ b/jetty-plus/src/main/config/etc/jetty-plus.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure extended support for webapps                          -->
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
index 5769b2a..10f1aec 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java
@@ -91,7 +91,7 @@
     /**
      * A class has been found that has an annotation of interest
      * to this initializer.
-     * @param className
+     * @param className the class name to add
      */
     public void addAnnotatedTypeName (String className)
     {
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java
index 7fb6082..bfd1963 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java
@@ -32,11 +32,10 @@
 
 /**
  * Injection
- *
+ * <p>
  * Represents the injection of a resource into a target (method or field).
  * The injection is performed by doing an ENC lookup using the jndi
  * name provided, and setting the object obtained on the target.
- *
  */
 public class Injection
 {
@@ -168,7 +167,7 @@
 
     /**
      * Inject a value for a Resource from JNDI into an object
-     * @param injectable
+     * @param injectable the object to inject 
      */
     public void inject (Object injectable)
     {
@@ -187,7 +186,7 @@
     /**
      * The Resource must already exist in the ENC of this webapp.
      * @return the injected valud
-     * @throws NamingException
+     * @throws NamingException if unable to lookup value
      */
     public Object lookupInjectedValue ()
     throws NamingException
@@ -200,8 +199,8 @@
 
     /**
      * Inject value from jndi into a field of an instance
-     * @param field
-     * @param injectable
+     * @param field the field to inject into
+     * @param injectable the value to inject
      */
     protected void injectField (Field field, Object injectable)
     {
@@ -221,8 +220,8 @@
 
     /**
      * Inject value from jndi into a setter method of an instance
-     * @param method
-     * @param injectable
+     * @param method the method to inject into
+     * @param injectable the value to inject
      */
     protected void injectMethod (Method method, Object injectable)
     {
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java
index 8e76330..17e9559 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java
@@ -28,11 +28,8 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-
 /**
  * LifeCycleCallbackCollection
- *
- *
  */
 public class LifeCycleCallbackCollection
 {
@@ -46,7 +43,7 @@
     /**
      * Add a Callback to the list of callbacks.
      * 
-     * @param callback
+     * @param callback the callback
      */
     public void add (LifeCycleCallback callback)
     {
@@ -95,10 +92,10 @@
     }
     
     /**
-     * Call the method, if one exists, that is annotated with PostConstruct
-     * or with &lt;post-construct&gt; in web.xml
+     * Call the method, if one exists, that is annotated with <code>&#064;PostConstruct</code>
+     * or with <code>&lt;post-construct&gt;</code> in web.xml
      * @param o the object on which to attempt the callback
-     * @throws Exception
+     * @throws Exception if unable to call {@link PostConstructCallback}
      */
     public void callPostConstructCallback (Object o)
     throws Exception
@@ -120,9 +117,10 @@
 
     
     /**
-     * Call the method, if one exists, that is annotated with PreDestroy
-     * or with &lt;pre-destroy&gt; in web.xml
+     * Call the method, if one exists, that is annotated with <code>&#064;PreDestroy</code>
+     * or with <code>&lt;pre-destroy&gt;</code> in web.xml
      * @param o the object on which to attempt the callback
+     * @throws Exception if unable to call {@link PreDestroyCallback}
      */
     public void callPreDestroyCallback (Object o)
     throws Exception
@@ -141,7 +139,7 @@
     
     /**
      * Generate a read-only view of the post-construct callbacks
-     * @return
+     * @return the map of {@link PostConstructCallback}s
      */
     public Map<String, List<LifeCycleCallback>> getPostConstructCallbackMap()
     {
@@ -150,7 +148,7 @@
     
     /**
      * Generate a read-only view of the pre-destroy callbacks
-     * @return
+     * @return the map of {@link PreDestroyCallback}s
      */
     public Map<String, List<LifeCycleCallback>> getPreDestroyCallbackMap()
     {
@@ -159,7 +157,7 @@
     
     /**
      * Amalgamate all post-construct callbacks and return a read only list
-     * @return
+     * @return the collection of {@link PostConstructCallback}s
      */
     public Collection<LifeCycleCallback> getPostConstructCallbacks()
     {
@@ -173,7 +171,7 @@
     
     /**
      * Amalgamate all pre-destroy callbacks and return a read only list
-     * @return
+     * @return the collection of {@link PreDestroyCallback}s
      */
     public Collection<LifeCycleCallback> getPreDestroyCallbacks()
     {
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java
index 8321d36..06c8277 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java
@@ -22,8 +22,8 @@
 
 /**
  * RunAs
- * <p/>
- * Represents a &lt;run-as&gt; element in web.xml, or a runAs annotation.
+ * <p>
+ * Represents a <code>&lt;run-as&gt;</code> element in web.xml, or a <code>&#064;RunAs</code> annotation.
  */
 public class RunAs
 {
@@ -54,10 +54,6 @@
         return _roleName;
     }
 
-
-    /**
-     * @param holder
-     */
     public void setRunAs (ServletHolder holder)
     {
         if (holder == null)
@@ -70,6 +66,5 @@
             if (holder.getRegistration().getRunAsRole() == null)
                 holder.getRegistration().setRunAsRole(_roleName);
         }
-            
     }
 }
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/EnvEntry.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/EnvEntry.java
index 2b474c8..f646a43 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/EnvEntry.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/EnvEntry.java
@@ -24,8 +24,6 @@
 
 /**
  * EnvEntry
- *
- *
  */
 public class EnvEntry extends NamingEntry
 {
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java
index 16e6397..944452a 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java
@@ -28,15 +28,13 @@
 import org.eclipse.jetty.jndi.NamingUtil;
 import org.eclipse.jetty.util.log.Logger;
 
-
-
 /**
  * NamingEntry
- *
+ * <p>
  * Base class for all jndi related entities. Instances of
  * subclasses of this class are declared in jetty.xml or in a 
  * webapp's WEB-INF/jetty-env.xml file.
- *
+ * <p>
  * NOTE: that all NamingEntries will be bound in a single namespace.
  *  The "global" level is just in the top level context. The "local"
  *  level is a context specific to a webapp.
@@ -73,7 +71,7 @@
      * be linked to the webapp's env-entry, resource-ref etc entries.
      * 
      * @param jndiName the name of the object which will eventually be in java:comp/env
-     * @throws NamingException
+     * @throws NamingException if unable to create naming entry
      */
     protected NamingEntry (String jndiName)
     throws NamingException
@@ -85,14 +83,15 @@
  
     
     /**
-     * Add a java:comp/env binding for the object represented by this NamingEntry,
+     * Add a <code>java:comp/env</code> binding for the object represented by this NamingEntry,
      * but bind it as the name supplied
-     * @throws NamingException
+     * @param localName the local name to bind
+     * @throws NamingException if unable to bind
      */
     public void bindToENC(String localName)
     throws NamingException
     {
-        //TODO - check on the whole overriding/non-overriding thing
+        // TODO - check on the whole overriding/non-overriding thing
         InitialContext ic = new InitialContext();
         Context env = (Context)ic.lookup("java:comp/env");
         __log.debug("Binding java:comp/env/"+localName+" to "+_objectNameString);
@@ -160,22 +159,24 @@
     
     /**
      * Save the NamingEntry for later use.
-     * 
+     * <p>
      * Saving is done by binding the NamingEntry
      * itself, and the value it represents into
      * JNDI. In this way, we can link to the
      * value it represents later, but also
      * still retrieve the NamingEntry itself too.
-     * 
+     * <p>
      * The object is bound at the jndiName passed in.
      * This NamingEntry is bound at __/jndiName.
-     * 
+     * <p>
      * eg
-     * 
+     * <pre>
      * jdbc/foo    : DataSource
      * __/jdbc/foo : NamingEntry
+     * </pre>
      * 
-     * @throws NamingException
+     * @param object the object to save 
+     * @throws NamingException if unable to save
      */
     protected void save (Object object)
     throws NamingException
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java
index 82e9db9..fd0948e 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntryUtil.java
@@ -48,7 +48,8 @@
      * @param scope the scope of the lookup
      * @param asName the name to bind as
      * @param mappedName the name from the environment to link to asName
-     * @throws NamingException
+     * @return true if bind success, false if not bound
+     * @throws NamingException if unable to bind
      */
     public static boolean bindToENC (Object scope, String asName, String mappedName)
     throws NamingException
@@ -74,10 +75,10 @@
     /**
      * Find a NamingEntry in the given scope.
      *
-     * @param scope
-     * @param jndiName
+     * @param scope the object scope
+     * @param jndiName the jndi name
      * @return the naming entry for the given scope
-     * @throws NamingException
+     * @throws NamingException if unable to lookup naming entry
      */
     public static NamingEntry lookupNamingEntry (Object scope, String jndiName)
     throws NamingException
@@ -112,10 +113,10 @@
      * Get all NameEntries of a certain type in the given naming
      * environment scope (server-wide names or context-specific names)
      *
-     * @param scope
+     * @param scope the object scope
      * @param clazz the type of the entry
      * @return all NameEntries of a certain type in the given naming environment scope (server-wide names or context-specific names)
-     * @throws NamingException
+     * @throws NamingException if unable to lookup the naming entries
      */
     public static List<Object> lookupNamingEntries (Object scope, Class<?> clazz)
     throws NamingException
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Resource.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Resource.java
index 9c8a647..a41af71 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Resource.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/Resource.java
@@ -18,19 +18,13 @@
 
 package org.eclipse.jetty.plus.jndi;
 
-
 import javax.naming.NamingException;
 
-
-
 /**
  * Resource
- *
- *
  */
 public class Resource extends NamingEntry
 {
-    
     public  Resource (Object scope, String jndiName, Object objToBind)
     throws NamingException
     {
@@ -38,15 +32,10 @@
         save(objToBind);
     }
     
-    /**
-     * @param jndiName
-     * @param objToBind
-     */
     public Resource (String jndiName, Object objToBind)
     throws NamingException
     {
         super(jndiName);
         save(objToBind);
     }
-
 }
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
index 79a5bed..4689adb 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java
@@ -32,6 +32,7 @@
 import javax.naming.InitialContext;
 import javax.naming.NameNotFoundException;
 import javax.naming.NamingException;
+import javax.servlet.ServletRequest;
 import javax.sql.DataSource;
 
 import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
@@ -45,9 +46,8 @@
 
 
 /**
- *
  * DataSourceUserRealm
- *
+ * <p>
  * Obtain user/password/role information from a database
  * via jndi DataSource.
  */
@@ -73,6 +73,27 @@
     private String _userSql;
     private String _roleSql;
     private boolean _createTables = false;
+    
+    
+    /**
+     * DBUser
+     */
+    public class DBUser extends KnownUser
+    {
+        private int _key;
+        
+        public DBUser(String name, Credential credential, int key)
+        {
+            super(name, credential);
+            _key = key;
+        }
+        
+        public int getKey ()
+        {
+            return _key;
+        }
+        
+    }
 
     /* ------------------------------------------------------------ */
     public DataSourceLoginService()
@@ -288,15 +309,15 @@
     /* ------------------------------------------------------------ */
     /** Load user's info from database.
      *
-     * @param userName
+     * @param userName the user name
      */
-    @Override
+    @Deprecated
     protected UserIdentity loadUser (String userName)
     {
         try
         {
             try (Connection connection = getConnection();
-                 PreparedStatement statement1 = connection.prepareStatement(_userSql))
+                    PreparedStatement statement1 = connection.prepareStatement(_userSql))
             {
                 statement1.setObject(1, userName);
                 try (ResultSet rs1 = statement1.executeQuery())
@@ -305,19 +326,20 @@
                     {
                         int key = rs1.getInt(_userTableKey);
                         String credentials = rs1.getString(_userTablePasswordField);
-                        List<String> roles = new ArrayList<String>();
-                        try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
-                        {
-                            statement2.setInt(1, key);
-                            try (ResultSet rs2 = statement2.executeQuery())
+                       
+                            List<String> roles = new ArrayList<String>();
+                            try (PreparedStatement statement2 = connection.prepareStatement(_roleSql))
                             {
-                                while (rs2.next())
+                                statement2.setInt(1, key);
+                                try (ResultSet rs2 = statement2.executeQuery())
                                 {
-                                    roles.add(rs2.getString(_roleTableRoleField));
+                                    while (rs2.next())
+                                    {
+                                        roles.add(rs2.getString(_roleTableRoleField));
+                                    }
                                 }
                             }
-                        }
-                        return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
+                            return putUser(userName,  Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
                     }
                 }
             }
@@ -334,10 +356,81 @@
     }
     
     
+    /** 
+     * @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
+     */
+    public KnownUser loadUserInfo (String username)
+    {
+        try
+        {
+            try (Connection connection = getConnection();
+                    PreparedStatement statement1 = connection.prepareStatement(_userSql))
+            {
+                statement1.setObject(1, username);
+                try (ResultSet rs1 = statement1.executeQuery())
+                {
+                    if (rs1.next())
+                    {
+                        int key = rs1.getInt(_userTableKey);
+                        String credentials = rs1.getString(_userTablePasswordField);
+                        
+                        return new DBUser(username, Credential.getCredential(credentials), key);
+                    }
+                }
+            }
+        }
+        catch (NamingException e)
+        {
+            LOG.warn("No datasource for "+_jndiName, e);
+        }
+        catch (SQLException e)
+        {
+            LOG.warn("Problem loading user info for "+username, e);
+        }
+        return null;
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
+     */
+    public String[] loadRoleInfo (KnownUser user)
+    {
+        DBUser dbuser = (DBUser)user;
+
+        try
+        {
+            try (Connection connection = getConnection();
+                    PreparedStatement statement2 = connection.prepareStatement(_roleSql))
+            {
+
+                List<String> roles = new ArrayList<String>();
+
+                statement2.setInt(1, dbuser.getKey());
+                try (ResultSet rs2 = statement2.executeQuery())
+                {
+                    while (rs2.next())
+                    {
+                        roles.add(rs2.getString(_roleTableRoleField));
+                    }
+                    
+                    return roles.toArray(new String[roles.size()]);
+                }
+            }
+        }
+        catch (NamingException e)
+        {
+            LOG.warn("No datasource for "+_jndiName, e);
+        }
+        catch (SQLException e)
+        {
+            LOG.warn("Problem loading user info for "+user.getName(), e);
+        }
+        return null;
+    }
     
     /* ------------------------------------------------------------ */
     @Override
-    public UserIdentity login(String username, Object credentials)
+    public UserIdentity login(String username, Object credentials, ServletRequest request)
     {
         long now = System.currentTimeMillis();
         if (now - _lastPurge > _cacheMs || _cacheMs == 0)
@@ -346,7 +439,7 @@
             _lastPurge = now;
         }
  
-        return super.login(username,credentials);
+        return super.login(username,credentials, request);
     }
 
     /* ------------------------------------------------------------ */
@@ -355,7 +448,8 @@
      * necessary sql query strings based on the configured table
      * and column names.
      *
-     * @throws NamingException
+     * @throws NamingException if unable to init jndi
+     * @throws SQLException if unable to init database
      */
     public void initDb() throws NamingException, SQLException
     {
@@ -366,9 +460,9 @@
         InitialContext ic = new InitialContext();
         assert ic!=null;
 
-        //TODO Should we try webapp scope too?
+        // TODO Should we try webapp scope too?
 
-        //try finding the datasource in the Server scope
+        // try finding the datasource in the Server scope
         if (_server != null)
         {
             try
@@ -401,8 +495,6 @@
         prepareTables();
     }
 
-
-
     private void prepareTables()
     throws NamingException, SQLException
     {
@@ -503,12 +595,10 @@
         }
     }
 
-
     private Connection getConnection ()
     throws NamingException, SQLException
     {
         initDb();
         return _datasource.getConnection();
     }
-
 }
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
index 046e072..1db1c6c 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java
@@ -40,14 +40,13 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.webapp.AbstractConfiguration;
+import org.eclipse.jetty.webapp.Configuration;
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
 
 /**
  * EnvConfiguration
- *
- *
  */
 public class EnvConfiguration extends AbstractConfiguration
 {
@@ -61,10 +60,6 @@
         this.jettyEnvXmlUrl = url;
     }
 
-    /**
-     * @see Configuration#configure(WebAppContext)
-     * @throws Exception
-     */
     @Override
     public void preConfigure (WebAppContext context) throws Exception
     {
@@ -72,9 +67,6 @@
         createEnvContext(context);
     }
 
-    /**
-     * @throws Exception
-     */
     @Override
     public void configure (WebAppContext context) throws Exception
     {
@@ -138,8 +130,7 @@
 
     /**
      * Remove jndi setup from start
-     * @see Configuration#deconfigure(WebAppContext)
-     * @throws Exception
+     * @throws Exception if unable to deconfigure
      */
     @Override
     public void deconfigure (WebAppContext context) throws Exception
@@ -179,8 +170,7 @@
 
     /**
      * Remove all jndi setup
-     * @see Configuration#deconfigure(WebAppContext)
-     * @throws Exception
+     * @throws Exception if unable to destroy
      */
     @Override
     public void destroy (WebAppContext context) throws Exception
@@ -207,7 +197,8 @@
      * web.xml file can potentially override them.
      *
      * We first bind EnvEntries declared in Server scope, then WebAppContext scope.
-     * @throws NamingException
+     * @param context the context to use for the object scope
+     * @throws NamingException if unable to bind env entries
      */
     public void bindEnvEntries (WebAppContext context)
     throws NamingException
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java
index f8fbf7c..c5766ac 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusConfiguration.java
@@ -48,13 +48,13 @@
     public void preConfigure (WebAppContext context)
     throws Exception
     {
-        context.addDecorator(new PlusDecorator(context));
+        context.getObjectFactory().addDecorator(new PlusDecorator(context));
     }
 
     @Override
     public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
     {
-        context.addDecorator(new PlusDecorator(context));
+        context.getObjectFactory().addDecorator(new PlusDecorator(context));
     }
 
     @Override
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java
index 603756b..327d059 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDecorator.java
@@ -21,7 +21,7 @@
 import org.eclipse.jetty.plus.annotation.InjectionCollection;
 import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
 import org.eclipse.jetty.plus.annotation.RunAsCollection;
-import org.eclipse.jetty.servlet.ServletContextHandler.Decorator;
+import org.eclipse.jetty.util.Decorator;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.webapp.WebAppContext;
diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java
index 14db89c..7f58216 100644
--- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java
+++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessor.java
@@ -48,10 +48,7 @@
 
 /**
  * PlusDescriptorProcessor
- *
- *
  */
-
 public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
 {
     private static final Logger LOG = Log.getLogger(PlusDescriptorProcessor.class);
@@ -109,14 +106,13 @@
     {
     }
 
-
-
-
     /**
      * JavaEE 5.4.1.3
-     *
-     * @param node
-     * @throws Exception
+     * 
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
+     * @throws Exception if unable to process jndi bindings
      */
     public void visitEnvEntry (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     throws Exception
@@ -188,18 +184,20 @@
 
     /**
      * Common Annotations Spec section 2.3:
+     * <p>
      *  resource-ref is for:
-     *    - javax.sql.DataSource
-     *    - javax.jms.ConnectionFactory
-     *    - javax.jms.QueueConnectionFactory
-     *    - javax.jms.TopicConnectionFactory
-     *    - javax.mail.Session
-     *    - java.net.URL
-     *    - javax.resource.cci.ConnectionFactory
-     *    - org.omg.CORBA_2_3.ORB
-     *    - any other connection factory defined by a resource adapter
+     * <ul>
+     * <li>javax.sql.DataSource</li>
+     * <li>javax.jms.ConnectionFactory</li>
+     * <li>javax.jms.QueueConnectionFactory</li>
+     * <li>javax.jms.TopicConnectionFactory</li>
+     * <li>javax.mail.Session</li>
+     * <li>java.net.URL</li>
+     * <li>javax.resource.cci.ConnectionFactory</li>
+     * <li>org.omg.CORBA_2_3.ORB</li>
+     * <li>any other connection factory defined by a resource adapter</li>
+     * </ul>
      *
-     * TODO
      * If web.xml contains a resource-ref with injection targets, all resource-ref entries
      * of the same name are ignored in web fragments. If web.xml does not contain any
      * injection-targets, then they are merged from all the fragments.
@@ -211,8 +209,10 @@
      * a real resource in the environment. At the moment, we insist that the
      * jetty.xml file name of the resource has to be exactly the same as the
      * name in web.xml deployment descriptor, but it shouldn't have to be
-     *
+     * 
+     * <p>
      * Maintenance update 3.0a to spec:
+     * <p>
      *   Update Section 8.2.3.h.ii with the following -  If a resource reference
      *   element is specified in two fragments, while absent from the main web.xml,
      *   and all the attributes and child elements of the resource reference element
@@ -220,13 +220,15 @@
      *   It is considered an error if a resource reference element has the same name
      *   specified in two fragments, while absent from the main web.xml and the attributes
      *   and child elements are not identical in the two fragments. For example, if two
-     *   web fragments declare a <resource-ref> with the same <resource-ref-name> element
+     *   web fragments declare a <code>&lt;resource-ref&gt;</code> with the same <code>&lt;resource-ref-name&gt;</code> element
      *   but the type in one is specified as javax.sql.DataSource while the type in the
      *   other is that of a java mail resource, then an error must be reported and the
      *   application MUST fail to deploy.
-     *
-     * @param node
-     * @throws Exception
+     *   
+     * @param context the context  
+     * @param descriptor the descriptor
+     * @param node the xml node
+     * @throws Exception if unable to bind nodes, or load classes
      */
     public void visitResourceRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     throws Exception
@@ -338,13 +340,18 @@
 
     /**
      * Common Annotations Spec section 2.3:
-     *   resource-env-ref is for:
-     *     - javax.transaction.UserTransaction
-     *     - javax.resource.cci.InteractionSpec
-     *     - anything else that is not a connection factory
-     *
-     * @param node
-     * @throws Exception
+     * <p>
+     * resource-env-ref is for:
+     * <ul>
+     * <li>javax.transaction.UserTransaction</li>
+     * <li>javax.resource.cci.InteractionSpec</li>
+     * <li>anything else that is not a connection factory</li>
+     * </ul>
+     * 
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
+     * @throws Exception if unable to load classes, or bind jndi entries
      */
     public void visitResourceEnvRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     throws Exception
@@ -438,11 +445,17 @@
 
     /**
      * Common Annotations Spec section 2.3:
-     *   message-destination-ref is for:
-     *     - javax.jms.Queue
-     *     - javax.jms.Topic
-     * @param node
-     * @throws Exception
+     * <p>
+     * message-destination-ref is for:
+     * <ul>
+     * <li>javax.jms.Queue</li>
+     * <li>javax.jms.Topic</li>
+     * </ul>
+     *     
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
+     * @throws Exception if unable to load classes or bind jndi entries
      */
     public void visitMessageDestinationRef (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     throws Exception
@@ -536,7 +549,10 @@
      * are ignored. Otherwise, post-constructs from fragments are merged.
      * post-construct is the name of a class and method to call after all
      * resources have been setup but before the class is put into use
-     * @param node
+     * 
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
      */
     public void visitPostConstruct(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
@@ -624,7 +640,10 @@
      *
      * pre-destroy is the name of a class and method to call just as
      * the instance is being destroyed
-     * @param node
+     * 
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
      */
     public void visitPreDestroy(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
@@ -705,12 +724,13 @@
 
 
     /**
-     * Iterate over the &lt;injection-target&gt; entries for a node
-     *
-     * @param descriptor
-     * @param node
-     * @param jndiName
-     * @param valueClass
+     * Iterate over the <code>&lt;injection-target&gt;</code> entries for a node
+     * 
+     * @param context the context 
+     * @param descriptor the descriptor 
+     * @param node the xml node
+     * @param jndiName the jndi name
+     * @param valueClass the value class
      */
     public void addInjections (WebAppContext context, Descriptor descriptor, XmlParser.Node node, String jndiName, Class<?> valueClass)
     {
@@ -763,9 +783,9 @@
 
 
     /**
-     * @param name
-     * @param value
-     * @throws Exception
+     * @param name the jndi name
+     * @param value the value
+     * @throws Exception if unable to bind entry
      */
     public void bindEnvEntry(String name, Object value) throws Exception
     {
@@ -799,12 +819,14 @@
 
     /**
      * Bind a resource reference.
-     *
+     * <p>
      * If a resource reference with the same name is in a jetty-env.xml
      * file, it will already have been bound.
-     *
-     * @param name
-     * @throws Exception
+     * 
+     * @param context the context 
+     * @param name the jndi name
+     * @param typeClass the type class
+     * @throws Exception if unable to bind resource
      */
     public void bindResourceRef(WebAppContext context, String name, Class<?> typeClass)
     throws Exception
@@ -812,10 +834,6 @@
         bindEntry(context, name, typeClass);
     }
 
-    /**
-     * @param name
-     * @throws Exception
-     */
     public void bindResourceEnvRef(WebAppContext context, String name, Class<?> typeClass)
     throws Exception
     {
@@ -834,16 +852,17 @@
      * Bind a resource with the given name from web.xml of the given type
      * with a jndi resource from either the server or the webapp's naming
      * environment.
-     *
+     * <p>
      * As the servlet spec does not cover the mapping of names in web.xml with
      * names from the execution environment, jetty uses the concept of a Link, which is
      * a subclass of the NamingEntry class. A Link defines a mapping of a name
      * from web.xml with a name from the execution environment (ie either the server or the
      * webapp's naming environment).
-     *
+     * 
+     * @param context the context
      * @param name name of the resource from web.xml
-     * @param typeClass
-     * @throws Exception
+     * @param typeClass the type class
+     * @throws Exception the exception
      */
     protected void bindEntry (WebAppContext context, String name, Class<?> typeClass)
     throws Exception
diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java
index ba17f08..7868b14 100644
--- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java
+++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java
@@ -44,9 +44,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-/**
- *
- */
 public class TestNamingEntries
 {
     public class ScopeA
@@ -145,7 +142,7 @@
      * after each test we should scrape out any lingering bindings to prevent cross test pollution
      * as observed when running java 7
      *
-     * @throws Exception
+     * @throws Exception on test failure
      */
     @After
     public void after() throws Exception
diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java
index 859b600..62fa092 100644
--- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java
+++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java
@@ -19,12 +19,12 @@
 package org.eclipse.jetty.plus.webapp;
 
 
-import java.lang.reflect.InvocationTargetException;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 
 import javax.naming.Context;
@@ -42,8 +42,6 @@
 
 /**
  * PlusDescriptorProcessorTest
- *
- *
  */
 public class PlusDescriptorProcessorTest
 {
@@ -53,9 +51,7 @@
     protected FragmentDescriptor fragDescriptor3;
     protected FragmentDescriptor fragDescriptor4;
     protected WebAppContext context;
-    /**
-     * @throws java.lang.Exception
-     */
+    
     @Before
     public void setUp() throws Exception
     {
diff --git a/jetty-proxy/pom.xml b/jetty-proxy/pom.xml
index 51bf4a7..d284a78 100644
--- a/jetty-proxy/pom.xml
+++ b/jetty-proxy/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-proxy</artifactId>
@@ -15,52 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-proxy/src/main/config/etc/jetty-proxy.xml b/jetty-proxy/src/main/config/etc/jetty-proxy.xml
index 0e96724..20ef318 100644
--- a/jetty-proxy/src/main/config/etc/jetty-proxy.xml
+++ b/jetty-proxy/src/main/config/etc/jetty-proxy.xml
@@ -1,35 +1,35 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
-    <Set name="handler">
-        <New class="org.eclipse.jetty.proxy.ConnectHandler">
-            <Set name="handler">
-                <New class="org.eclipse.jetty.servlet.ServletHandler">
-                    <Call id="proxyHolder" name="addServletWithMapping">
-                        <Arg><Property name="jetty.proxy.servletClass" default="org.eclipse.jetty.proxy.ProxyServlet"/></Arg>
-                        <Arg><Property name="jetty.proxy.servletMapping" default="/*"/></Arg>
-                        <Call name="setInitParameter">
-                            <Arg>maxThreads</Arg>
-                            <Arg><Property name="jetty.proxy.maxThreads" default="128" /></Arg>
-                        </Call>
-                        <Call name="setInitParameter">
-                            <Arg>maxConnections</Arg>
-                            <Arg><Property name="jetty.proxy.maxConnections" default="256" /></Arg>
-                        </Call>
-                        <Call name="setInitParameter">
-                            <Arg>idleTimeout</Arg>
-                            <Arg><Property name="jetty.proxy.idleTimeout" default="30000" /></Arg>
-                        </Call>
-                        <Call name="setInitParameter">
-                            <Arg>timeout</Arg>
-                            <Arg><Property name="jetty.proxy.timeout" default="60000" /></Arg>
-                        </Call>
-                    </Call>
-                </New>
-            </Set>
+  <Set name="handler">
+    <New class="org.eclipse.jetty.proxy.ConnectHandler">
+      <Set name="handler">
+        <New class="org.eclipse.jetty.servlet.ServletHandler">
+          <Call id="proxyHolder" name="addServletWithMapping">
+            <Arg><Property name="jetty.proxy.servletClass" default="org.eclipse.jetty.proxy.ProxyServlet"/></Arg>
+            <Arg><Property name="jetty.proxy.servletMapping" default="/*"/></Arg>
+            <Call name="setInitParameter">
+              <Arg>maxThreads</Arg>
+              <Arg><Property name="jetty.proxy.maxThreads" default="128" /></Arg>
+            </Call>
+            <Call name="setInitParameter">
+              <Arg>maxConnections</Arg>
+              <Arg><Property name="jetty.proxy.maxConnections" default="256" /></Arg>
+            </Call>
+            <Call name="setInitParameter">
+              <Arg>idleTimeout</Arg>
+              <Arg><Property name="jetty.proxy.idleTimeout" default="30000" /></Arg>
+            </Call>
+            <Call name="setInitParameter">
+              <Arg>timeout</Arg>
+              <Arg><Property name="jetty.proxy.timeout" default="60000" /></Arg>
+            </Call>
+          </Call>
         </New>
-    </Set>
+      </Set>
+    </New>
+  </Set>
 
 </Configure>
diff --git a/jetty-proxy/src/main/config/modules/proxy.mod b/jetty-proxy/src/main/config/modules/proxy.mod
index a879ae1..6b91f68 100644
--- a/jetty-proxy/src/main/config/modules/proxy.mod
+++ b/jetty-proxy/src/main/config/modules/proxy.mod
@@ -14,9 +14,9 @@
 
 [ini-template]
 ## Proxy Configuration
-#jetty.proxy.servletClass=org.eclipse.jetty.proxy.ProxyServlet
-#jetty.proxy.servletMapping=/*
-#jetty.proxy.maxThreads=128
-#jetty.proxy.maxConnections=256
-#jetty.proxy.idleTimeout=30000
-#jetty.proxy.timeout=60000
+# jetty.proxy.servletClass=org.eclipse.jetty.proxy.ProxyServlet
+# jetty.proxy.servletMapping=/*
+# jetty.proxy.maxThreads=128
+# jetty.proxy.maxConnections=256
+# jetty.proxy.idleTimeout=30000
+# jetty.proxy.timeout=60000
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
index bd8b4b3..8350feb 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
@@ -215,6 +215,7 @@
      * <p>Creates a {@link HttpClient} instance, configured with init parameters of this servlet.</p>
      * <p>The init parameters used to configure the {@link HttpClient} instance are:</p>
      * <table>
+     * <caption>Init Parameters</caption>
      * <thead>
      * <tr>
      * <th>init-param</th>
@@ -412,11 +413,11 @@
      * like {@link HttpServletResponse#sendError(int)}.</p>
      *
      * @param clientRequest the client request
-     * @param clientResponse the client response
+     * @param proxyResponse the client response
      */
-    protected void onProxyRewriteFailed(HttpServletRequest clientRequest, HttpServletResponse clientResponse)
+    protected void onProxyRewriteFailed(HttpServletRequest clientRequest, HttpServletResponse proxyResponse)
     {
-        clientResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
+        sendProxyResponseError(clientRequest, proxyResponse, HttpStatus.FORBIDDEN_403);
     }
 
     protected boolean hasContent(HttpServletRequest clientRequest)
@@ -548,8 +549,7 @@
             int status = failure instanceof TimeoutException ?
                     HttpStatus.REQUEST_TIMEOUT_408 :
                     HttpStatus.INTERNAL_SERVER_ERROR_500;
-            proxyResponse.setStatus(status);
-            clientRequest.getAsyncContext().complete();
+            sendProxyResponseError(clientRequest, proxyResponse, status);
         }
     }
 
@@ -635,13 +635,10 @@
         else
         {
             proxyResponse.resetBuffer();
-            if (failure instanceof TimeoutException)
-                proxyResponse.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT);
-            else
-                proxyResponse.setStatus(HttpServletResponse.SC_BAD_GATEWAY);
-            proxyResponse.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
-            AsyncContext asyncContext = clientRequest.getAsyncContext();
-            asyncContext.complete();
+            int status = failure instanceof TimeoutException ?
+                    HttpStatus.GATEWAY_TIMEOUT_504 :
+                    HttpStatus.BAD_GATEWAY_502;
+            sendProxyResponseError(clientRequest, proxyResponse, status);
         }
     }
 
@@ -650,6 +647,14 @@
         return System.identityHashCode(clientRequest);
     }
 
+    protected void sendProxyResponseError(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, int status)
+    {
+        proxyResponse.setStatus(status);
+        proxyResponse.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
+        if (clientRequest.isAsyncStarted())
+            clientRequest.getAsyncContext().complete();
+    }
+
     /**
      * <p>Utility class that implement transparent proxy functionalities.</p>
      * <p>Configuration parameters:</p>
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java
index 36d6be8..491258a 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java
@@ -138,6 +138,7 @@
         return new ProxyWriter(clientRequest, proxyResponse);
     }
 
+    @Override
     protected Response.CompleteListener newProxyResponseListener(HttpServletRequest clientRequest, HttpServletResponse proxyResponse)
     {
         return new ProxyResponseListener(clientRequest, proxyResponse);
@@ -207,7 +208,7 @@
     /**
      * <p>Convenience extension of {@link AsyncMiddleManServlet} that offers transparent proxy functionalities.</p>
      *
-     * @see TransparentDelegate
+     * @see org.eclipse.jetty.proxy.AbstractProxyServlet.TransparentDelegate
      */
     public static class Transparent extends ProxyServlet
     {
@@ -258,7 +259,7 @@
         {
             if (!provider.isClosed())
             {
-                process(BufferUtil.EMPTY_BUFFER, new Adapter()
+                process(BufferUtil.EMPTY_BUFFER, new Callback()
                 {
                     @Override
                     public void failed(Throwable x)
@@ -286,14 +287,18 @@
             while (input.isReady() && !input.isFinished())
             {
                 int read = readClientRequestContent(input, buffer);
+
                 if (_log.isDebugEnabled())
                     _log.debug("{} asynchronous read {} bytes on {}", getRequestId(clientRequest), read, input);
 
+                if (read < 0)
+                    return Action.SUCCEEDED;
+
                 if (contentLength > 0 && read > 0)
                     length += read;
 
                 ByteBuffer content = read > 0 ? ByteBuffer.wrap(buffer, 0, read) : BufferUtil.EMPTY_BUFFER;
-                boolean finished = read < 0 || length == contentLength;
+                boolean finished = length == contentLength;
                 process(content, this, finished);
 
                 if (read > 0)
@@ -681,19 +686,19 @@
          * <p>Typical implementations:</p>
          * <pre>
          * // Identity transformation (no transformation, the input is copied to the output)
-         * public void transform(ByteBuffer input, boolean finished, List<ByteBuffer> output)
+         * public void transform(ByteBuffer input, boolean finished, List&lt;ByteBuffer&gt; output)
          * {
          *     output.add(input);
          * }
          *
          * // Discard transformation (all input is discarded)
-         * public void transform(ByteBuffer input, boolean finished, List<ByteBuffer> output)
+         * public void transform(ByteBuffer input, boolean finished, List&lt;ByteBuffer&gt; output)
          * {
          *     // Empty
          * }
          *
          * // Buffering identity transformation (all input is buffered aside until it is finished)
-         * public void transform(ByteBuffer input, boolean finished, List<ByteBuffer> output)
+         * public void transform(ByteBuffer input, boolean finished, List&lt;ByteBuffer&gt; output)
          * {
          *     ByteBuffer copy = ByteBuffer.allocate(input.remaining());
          *     copy.put(input).flip();
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
index 1d33066..146932d 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.proxy;
 
 import java.io.IOException;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.channels.WritePendingException;
 
@@ -52,17 +51,17 @@
     private static final String WRITE_LISTENER_ATTRIBUTE = AsyncProxyServlet.class.getName() + ".writeListener";
 
     @Override
-    protected ContentProvider proxyRequestContent(Request proxyRequest, HttpServletRequest request) throws IOException
+    protected ContentProvider proxyRequestContent(HttpServletRequest request, HttpServletResponse response, Request proxyRequest) throws IOException
     {
         ServletInputStream input = request.getInputStream();
         DeferredContentProvider provider = new DeferredContentProvider();
-        input.setReadListener(newReadListener(proxyRequest, request, provider));
+        input.setReadListener(newReadListener(request, response, proxyRequest, provider));
         return provider;
     }
 
-    protected ReadListener newReadListener(Request proxyRequest, HttpServletRequest request, DeferredContentProvider provider)
+    protected ReadListener newReadListener(HttpServletRequest request, HttpServletResponse response, Request proxyRequest, DeferredContentProvider provider)
     {
-        return new StreamReader(proxyRequest, request, provider);
+        return new StreamReader(request, response, proxyRequest, provider);
     }
 
     @Override
@@ -107,7 +106,7 @@
     /**
      * <p>Convenience extension of {@link AsyncProxyServlet} that offers transparent proxy functionalities.</p>
      *
-     * @see TransparentDelegate
+     * @see org.eclipse.jetty.proxy.AbstractProxyServlet.TransparentDelegate
      */
     public static class Transparent extends AsyncProxyServlet
     {
@@ -121,23 +120,25 @@
         }
 
         @Override
-        protected URI rewriteURI(HttpServletRequest request)
+        protected String rewriteTarget(HttpServletRequest clientRequest)
         {
-            return URI.create(delegate.rewriteTarget(request));
+            return delegate.rewriteTarget(clientRequest);
         }
     }
 
     protected class StreamReader extends IteratingCallback implements ReadListener
     {
         private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()];
-        private final Request proxyRequest;
         private final HttpServletRequest request;
+        private final HttpServletResponse response;
+        private final Request proxyRequest;
         private final DeferredContentProvider provider;
 
-        protected StreamReader(Request proxyRequest, HttpServletRequest request, DeferredContentProvider provider)
+        protected StreamReader(HttpServletRequest request, HttpServletResponse response, Request proxyRequest, DeferredContentProvider provider)
         {
-            this.proxyRequest = proxyRequest;
             this.request = request;
+            this.response = response;
+            this.proxyRequest = proxyRequest;
             this.provider = provider;
         }
 
@@ -158,7 +159,7 @@
         @Override
         public void onError(Throwable t)
         {
-            onClientRequestFailure(proxyRequest, request, t);
+            onClientRequestFailure(request, proxyRequest, response, t);
         }
 
         @Override
@@ -178,7 +179,7 @@
                 {
                     if (_log.isDebugEnabled())
                         _log.debug("{} proxying content to upstream: {} bytes", requestId, read);
-                    onRequestContent(proxyRequest, request, provider, buffer, 0, read, this);
+                    onRequestContent(request, proxyRequest, provider, buffer, 0, read, this);
                     return Action.SCHEDULED;
                 }
             }
@@ -197,7 +198,7 @@
             }
         }
 
-        protected void onRequestContent(Request proxyRequest, HttpServletRequest request, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback)
+        protected void onRequestContent(HttpServletRequest request, Request proxyRequest, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback)
         {
             provider.offer(ByteBuffer.wrap(buffer, offset, length), callback);
         }
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
index 3f95ac8..ddb61cf 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/BalancerServlet.java
@@ -31,6 +31,7 @@
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 
+import org.eclipse.jetty.client.api.Response;
 import org.eclipse.jetty.util.URIUtil;
 
 public class BalancerServlet extends ProxyServlet
@@ -129,7 +130,7 @@
     }
 
     @Override
-    protected URI rewriteURI(HttpServletRequest request)
+    protected String rewriteTarget(HttpServletRequest request)
     {
         BalancerMember balancerMember = selectBalancerMember(request);
         if (_log.isDebugEnabled())
@@ -138,7 +139,7 @@
         String query = request.getQueryString();
         if (query != null)
             path += "?" + query;
-        return URI.create(balancerMember.getProxyTo() + "/" + path).normalize();
+        return URI.create(balancerMember.getProxyTo() + "/" + path).normalize().toString();
     }
 
     private BalancerMember selectBalancerMember(HttpServletRequest request)
@@ -214,7 +215,7 @@
     }
 
     @Override
-    protected String filterResponseHeader(HttpServletRequest request, String headerName, String headerValue)
+    protected String filterServerResponseHeader(HttpServletRequest request, Response serverResponse, String headerName, String headerValue)
     {
         if (_proxyPassReverse && REVERSE_PROXY_HEADERS.contains(headerName))
         {
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
index a0d4997..643cf1f 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
@@ -41,6 +41,7 @@
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectorManager;
@@ -207,7 +208,7 @@
      * @param response      the http response
      * @param serverAddress the remote server address in the form {@code host:port}
      */
-    protected void handleConnect(Request baseRequest, final HttpServletRequest request, final HttpServletResponse response, String serverAddress)
+    protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
     {
         baseRequest.setHandled(true);
         try
@@ -238,7 +239,7 @@
                 return;
             }
 
-            final HttpTransport transport = baseRequest.getHttpChannel().getHttpTransport();
+            HttpTransport transport = baseRequest.getHttpChannel().getHttpTransport();
             // TODO Handle CONNECT over HTTP2!
             if (!(transport instanceof HttpConnection))
             {
@@ -248,7 +249,7 @@
                 return;
             }
 
-            final AsyncContext asyncContext = request.startAsync();
+            AsyncContext asyncContext = request.startAsync();
             asyncContext.setTimeout(0);
 
             if (LOG.isDebugEnabled())
@@ -454,6 +455,7 @@
      * @param endPoint the endPoint to write to
      * @param buffer   the buffer to write
      * @param callback the completion callback to invoke
+     * @param context  the context information related to the connection
      */
     protected void write(EndPoint endPoint, ByteBuffer buffer, Callback callback, ConcurrentMap<String, Object> context)
     {
@@ -547,14 +549,8 @@
         protected void connectionFailed(SocketChannel channel, final Throwable ex, final Object attachment)
         {
             close(channel);
-            getExecutor().execute(new Runnable()
-            {
-                public void run()
-                {
-                    ConnectContext connectContext = (ConnectContext)attachment;
-                    onConnectFailure(connectContext.request, connectContext.response, connectContext.asyncContext, ex);
-                }
-            });
+            ConnectContext connectContext = (ConnectContext)attachment;
+            onConnectFailure(connectContext.request, connectContext.response, connectContext.asyncContext, ex);
         }
     }
 
@@ -614,14 +610,8 @@
         public void onOpen()
         {
             super.onOpen();
-            getExecutor().execute(new Runnable()
-            {
-                public void run()
-                {
-                    onConnectSuccess(connectContext, UpstreamConnection.this);
-                    fillInterested();
-                }
-            });
+            onConnectSuccess(connectContext, UpstreamConnection.this);
+            fillInterested();
         }
 
         @Override
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
index ee2b7d2..f921fc6 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyConnection.java
@@ -121,6 +121,7 @@
             {
                 if (LOG.isDebugEnabled())
                     LOG.debug(ProxyConnection.this + " could not fill", x);
+                bufferPool.release(buffer);
                 disconnect();
                 return Action.SUCCEEDED;
             }
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
index bc7bb0f..34b696b 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java
@@ -20,7 +20,6 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.util.concurrent.TimeUnit;
 
@@ -53,7 +52,7 @@
     {
         final int requestId = getRequestId(request);
 
-        URI rewrittenURI = rewriteURI(request);
+        String rewrittenTarget = rewriteTarget(request);
 
         if (_log.isDebugEnabled())
         {
@@ -61,20 +60,20 @@
             if (request.getQueryString() != null)
                 uri.append("?").append(request.getQueryString());
             if (_log.isDebugEnabled())
-                _log.debug("{} rewriting: {} -> {}", requestId, uri, rewrittenURI);
+                _log.debug("{} rewriting: {} -> {}", requestId, uri, rewrittenTarget);
         }
 
-        if (rewrittenURI == null)
+        if (rewrittenTarget == null)
         {
-            onRewriteFailed(request, response);
+            onProxyRewriteFailed(request, response);
             return;
         }
 
-        final Request proxyRequest = getHttpClient().newRequest(rewrittenURI)
+        final Request proxyRequest = getHttpClient().newRequest(rewrittenTarget)
                 .method(request.getMethod())
                 .version(HttpVersion.fromString(request.getProtocol()));
 
-        copyHeaders(request, proxyRequest);
+        copyRequestHeaders(request, proxyRequest);
 
         addProxyHeaders(request, proxyRequest);
 
@@ -84,64 +83,22 @@
         proxyRequest.timeout(getTimeout(), TimeUnit.MILLISECONDS);
 
         if (hasContent(request))
-            proxyRequest.content(proxyRequestContent(proxyRequest, request));
-
-        customizeProxyRequest(proxyRequest, request);
+            proxyRequest.content(proxyRequestContent(request, response, proxyRequest));
 
         sendProxyRequest(request, response, proxyRequest);
     }
 
-    /**
-     * @deprecated use {@link #copyRequestHeaders(HttpServletRequest, Request)} instead
-     */
-    @Deprecated
-    protected void copyHeaders(HttpServletRequest clientRequest, Request proxyRequest)
+    protected ContentProvider proxyRequestContent(HttpServletRequest request, HttpServletResponse response, Request proxyRequest) throws IOException
     {
-        copyRequestHeaders(clientRequest, proxyRequest);
+        return new ProxyInputStreamContentProvider(request, response, proxyRequest, request.getInputStream());
     }
 
-    protected ContentProvider proxyRequestContent(final Request proxyRequest, final HttpServletRequest request) throws IOException
-    {
-        return new ProxyInputStreamContentProvider(proxyRequest, request, request.getInputStream());
-    }
-
+    @Override
     protected Response.Listener newProxyResponseListener(HttpServletRequest request, HttpServletResponse response)
     {
         return new ProxyResponseListener(request, response);
     }
 
-    protected void onClientRequestFailure(Request proxyRequest, HttpServletRequest request, Throwable failure)
-    {
-        if (_log.isDebugEnabled())
-            _log.debug(getRequestId(request) + " client request failure", failure);
-        proxyRequest.abort(failure);
-    }
-
-    /**
-     * @deprecated use {@link #onProxyRewriteFailed(HttpServletRequest, HttpServletResponse)}
-     */
-    @Deprecated
-    protected void onRewriteFailed(HttpServletRequest request, HttpServletResponse response) throws IOException
-    {
-        onProxyRewriteFailed(request, response);
-    }
-
-    /**
-     * @deprecated use {@link #onServerResponseHeaders(HttpServletRequest, HttpServletResponse, Response)}
-     */
-    @Deprecated
-    protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
-    {
-        onServerResponseHeaders(request, response, proxyResponse);
-    }
-
-    // TODO: remove in Jetty 9.3, only here for backward compatibility.
-    @Override
-    protected String filterServerResponseHeader(HttpServletRequest clientRequest, Response serverResponse, String headerName, String headerValue)
-    {
-        return filterResponseHeader(clientRequest, headerName, headerValue);
-    }
-
     protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length, Callback callback)
     {
         try
@@ -158,62 +115,9 @@
     }
 
     /**
-     * @deprecated Use {@link #onProxyResponseSuccess(HttpServletRequest, HttpServletResponse, Response)}
-     */
-    @Deprecated
-    protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
-    {
-        onProxyResponseSuccess(request, response, proxyResponse);
-    }
-
-    /**
-     * @deprecated Use {@link #onProxyResponseFailure(HttpServletRequest, HttpServletResponse, Response, Throwable)}
-     */
-    @Deprecated
-    protected void onResponseFailure(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, Throwable failure)
-    {
-        onProxyResponseFailure(request, response, proxyResponse, failure);
-    }
-
-    /**
-     * @deprecated use {@link #rewriteTarget(HttpServletRequest)}
-     */
-    @Deprecated
-    protected URI rewriteURI(HttpServletRequest request)
-    {
-        String newTarget = rewriteTarget(request);
-        return newTarget == null ? null : URI.create(newTarget);
-    }
-
-    /**
-     * @deprecated use {@link #sendProxyRequest(HttpServletRequest, HttpServletResponse, Request)}
-     */
-    @Deprecated
-    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request)
-    {
-    }
-
-    /**
-     * Extension point for remote server response header filtering.
-     * The default implementation returns the header value as is.
-     * If null is returned, this header won't be forwarded back to the client.
-     *
-     * @param headerName the header name
-     * @param headerValue the header value
-     * @param request the request to proxy
-     * @return filteredHeaderValue the new header value
-     * @deprecated use {@link #filterServerResponseHeader(HttpServletRequest, Response, String, String)} instead
-     */
-    @Deprecated
-    protected String filterResponseHeader(HttpServletRequest request, String headerName, String headerValue)
-    {
-        return headerValue;
-    }
-
-    /**
      * <p>Convenience extension of {@link ProxyServlet} that offers transparent proxy functionalities.</p>
      *
-     * @see TransparentDelegate
+     * @see org.eclipse.jetty.proxy.AbstractProxyServlet.TransparentDelegate
      */
     public static class Transparent extends ProxyServlet
     {
@@ -227,9 +131,9 @@
         }
 
         @Override
-        protected URI rewriteURI(HttpServletRequest request)
+        protected String rewriteTarget(HttpServletRequest request)
         {
-            return URI.create(delegate.rewriteTarget(request));
+            return delegate.rewriteTarget(request);
         }
     }
 
@@ -253,7 +157,7 @@
         @Override
         public void onHeaders(Response proxyResponse)
         {
-            onResponseHeaders(request, response, proxyResponse);
+            onServerResponseHeaders(request, response, proxyResponse);
         }
 
         @Override
@@ -295,9 +199,9 @@
         public void onComplete(Result result)
         {
             if (result.isSucceeded())
-                onResponseSuccess(request, response, result.getResponse());
+                onProxyResponseSuccess(request, response, result.getResponse());
             else
-                onResponseFailure(request, response, result.getResponse(), result.getFailure());
+                onProxyResponseFailure(request, response, result.getResponse(), result.getFailure());
             if (_log.isDebugEnabled())
                 _log.debug("{} proxying complete", getRequestId(request));
         }
@@ -305,14 +209,16 @@
 
     protected class ProxyInputStreamContentProvider extends InputStreamContentProvider
     {
+        private final HttpServletResponse response;
         private final Request proxyRequest;
         private final HttpServletRequest request;
 
-        protected ProxyInputStreamContentProvider(Request proxyRequest, HttpServletRequest request, InputStream input)
+        protected ProxyInputStreamContentProvider(HttpServletRequest request, HttpServletResponse response, Request proxyRequest, InputStream input)
         {
             super(input);
-            this.proxyRequest = proxyRequest;
             this.request = request;
+            this.response = response;
+            this.proxyRequest = proxyRequest;
         }
 
         @Override
@@ -326,10 +232,10 @@
         {
             if (_log.isDebugEnabled())
                 _log.debug("{} proxying content to upstream: {} bytes", getRequestId(request), length);
-            return onRequestContent(proxyRequest, request, buffer, offset, length);
+            return onRequestContent(request, proxyRequest, buffer, offset, length);
         }
 
-        protected ByteBuffer onRequestContent(Request proxyRequest, final HttpServletRequest request, byte[] buffer, int offset, int length)
+        protected ByteBuffer onRequestContent(HttpServletRequest request, Request proxyRequest, byte[] buffer, int offset, int length)
         {
             return super.onRead(buffer, offset, length);
         }
@@ -337,7 +243,7 @@
         @Override
         protected void onReadFailure(Throwable failure)
         {
-            onClientRequestFailure(proxyRequest, request, failure);
+            onClientRequestFailure(request, proxyRequest, response, failure);
         }
     }
 }
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java
index 430b635..71d641a 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncMiddleManServletTest.java
@@ -631,6 +631,17 @@
     @Test
     public void testLargeChunkedBufferedDownstreamTransformation() throws Exception
     {
+        testLargeChunkedBufferedDownstreamTransformation(false);
+    }
+
+    @Test
+    public void testLargeChunkedGzippedBufferedDownstreamTransformation() throws Exception
+    {
+        testLargeChunkedBufferedDownstreamTransformation(true);
+    }
+
+    private void testLargeChunkedBufferedDownstreamTransformation(final boolean gzipped) throws Exception
+    {
         // Tests the race between a incomplete write performed from ProxyResponseListener.onSuccess()
         // and ProxyResponseListener.onComplete() being called before the write has completed.
 
@@ -639,10 +650,18 @@
             @Override
             protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
             {
-                ServletOutputStream output = response.getOutputStream();
+                OutputStream output = response.getOutputStream();
+                if (gzipped)
+                {
+                    output = new GZIPOutputStream(output);
+                    response.setHeader(HttpHeader.CONTENT_ENCODING.asString(), "gzip");
+                }
+
+                Random random = new Random();
                 byte[] chunk = new byte[1024 * 1024];
                 for (int i = 0; i < 16; ++i)
                 {
+                    random.nextBytes(chunk);
                     output.write(chunk);
                     output.flush();
                 }
@@ -653,7 +672,10 @@
             @Override
             protected ContentTransformer newServerResponseContentTransformer(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Response serverResponse)
             {
-                return new BufferingContentTransformer();
+                ContentTransformer transformer = new BufferingContentTransformer();
+                if (gzipped)
+                    transformer = new GZIPContentTransformer(transformer);
+                return transformer;
             }
         });
         startClient();
@@ -1097,7 +1119,6 @@
         // Send only part of the content; the proxy will idle timeout.
         final byte[] data = new byte[]{'c', 'a', 'f', 'e'};
         ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort())
-                .header(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())
                 .content(new BytesContentProvider(data)
                 {
                     @Override
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java
index 51147b7..accdf60 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java
@@ -24,6 +24,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EchoHttpServlet.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EchoHttpServlet.java
index 7d4bf1c..6e5ef81 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EchoHttpServlet.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EchoHttpServlet.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.proxy;
 
 import java.io.IOException;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EmptyHttpServlet.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EmptyHttpServlet.java
index 987fd4c..bfcd1b3 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EmptyHttpServlet.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/EmptyHttpServlet.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.proxy;
 
 import java.io.IOException;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletFailureTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletFailureTest.java
index a00f83c..100a203 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletFailureTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletFailureTest.java
@@ -30,6 +30,7 @@
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -262,17 +263,20 @@
             proxyServlet = new AsyncProxyServlet()
             {
                 @Override
-                protected ContentProvider proxyRequestContent(Request proxyRequest, HttpServletRequest request) throws IOException
+                protected ContentProvider proxyRequestContent(HttpServletRequest request, HttpServletResponse response, Request proxyRequest) throws IOException
                 {
-                    return new DeferredContentProvider()
+                    DeferredContentProvider provider = new DeferredContentProvider()
                     {
                         @Override
                         public boolean offer(ByteBuffer buffer, Callback callback)
                         {
-                            // Ignore all content to trigger the test condition.
-                            return true;
+                            // Send less content to trigger the test condition.
+                            buffer.limit(buffer.limit() - 1);
+                            return super.offer(buffer.slice(), callback);
                         }
                     };
+                    request.getInputStream().setReadListener(newReadListener(request, response, proxyRequest, provider));
+                    return provider;
                 }
             };
         }
@@ -281,7 +285,7 @@
             proxyServlet = new ProxyServlet()
             {
                 @Override
-                protected ContentProvider proxyRequestContent(Request proxyRequest, HttpServletRequest request) throws IOException
+                protected ContentProvider proxyRequestContent(HttpServletRequest request, HttpServletResponse response, Request proxyRequest) throws IOException
                 {
                     return new BytesContentProvider(content)
                     {
@@ -411,9 +415,4 @@
             ((StdErrLog)Log.getLogger(ServletHandler.class)).setHideStacks(false);
         }
     }
-
-    private interface Function<T, R>
-    {
-        public R apply(T arg);
-    }
 }
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
index 53369cf..4d6ab55 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java
@@ -141,7 +141,7 @@
 
     private void startProxy() throws Exception
     {
-        startProxy(new HashMap<String, String>());
+        startProxy(new HashMap<>());
     }
 
     private void startProxy(Map<String, String> initParams) throws Exception
@@ -672,7 +672,7 @@
         testTransparentProxyWithQuery("", "/proxy", "");
     }
 
-    private void testTransparentProxyWithQuery(final String proxyToContext, String prefix, final String target) throws Exception
+    private void testTransparentProxyWithQuery(String proxyToContext, String prefix, String target) throws Exception
     {
         final String query = "a=1&b=2";
         startServer(new HttpServlet()
diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
index b234310..fdec63f 100644
--- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
+++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyTunnellingTest.java
@@ -26,6 +26,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
@@ -278,6 +279,59 @@
     }
 
     @Test
+    public void testShortIdleTimeoutOverriddenByRequest() throws Exception
+    {
+        // Short idle timeout for HttpClient.
+        long idleTimeout = 500;
+
+        startSSLServer(new ServerHandler());
+        startProxy(new ConnectHandler()
+        {
+            @Override
+            protected void handleConnect(Request baseRequest, HttpServletRequest request, HttpServletResponse response, String serverAddress)
+            {
+                try
+                {
+                    // Make sure the proxy remains idle enough.
+                    Thread.sleep(2 * idleTimeout);
+                    super.handleConnect(baseRequest, request, response, serverAddress);
+                }
+                catch (InterruptedException x)
+                {
+                    onConnectFailure(request, response, null, x);
+                }
+            }
+        });
+
+        HttpClient httpClient = new HttpClient(sslContextFactory);
+        httpClient.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", proxyPort()));
+        // Short idle timeout for HttpClient.
+        httpClient.setIdleTimeout(idleTimeout);
+        httpClient.start();
+
+        try
+        {
+            String host = "localhost";
+            String body = "BODY";
+            ContentResponse response = httpClient.newRequest(host, serverConnector.getLocalPort())
+                    .scheme(HttpScheme.HTTPS.asString())
+                    .method(HttpMethod.GET)
+                    .path("/echo?body=" + URLEncoder.encode(body, "UTF-8"))
+                    // Long idle timeout for the request.
+                    .idleTimeout(10 * idleTimeout, TimeUnit.MILLISECONDS)
+                    .send();
+
+            assertEquals(HttpStatus.OK_200, response.getStatus());
+            String content = response.getContentAsString();
+            assertEquals(body, content);
+        }
+        finally
+        {
+            httpClient.stop();
+        }
+    }
+
+    @Test
     public void testProxyDown() throws Exception
     {
         startSSLServer(new ServerHandler());
diff --git a/jetty-quickstart/pom.xml b/jetty-quickstart/pom.xml
index 8aee9e2..8e35ba3 100644
--- a/jetty-quickstart/pom.xml
+++ b/jetty-quickstart/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.eclipse.jetty</groupId>
@@ -10,6 +10,9 @@
   <name>Jetty :: Quick Start</name>
   <description>Jetty Quick Start</description>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.quickstart</bundle-symbolic-name>
+  </properties>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
@@ -82,23 +85,6 @@
   </dependencies>
   <build>
     <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/jetty-quickstart/src/main/config/etc/example-quickstart.xml b/jetty-quickstart/src/main/config/etc/example-quickstart.xml
index 3f02e60..ddeedf9 100644
--- a/jetty-quickstart/src/main/config/etc/example-quickstart.xml
+++ b/jetty-quickstart/src/main/config/etc/example-quickstart.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"  encoding="ISO-8859-1"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- An example context XML for a quickstart webapp
 A quick started webapp has all the jar scanning and fragment resolution done in a 
diff --git a/jetty-quickstart/src/main/config/modules/quickstart.mod b/jetty-quickstart/src/main/config/modules/quickstart.mod
index 89db9fd..4e59dd0 100644
--- a/jetty-quickstart/src/main/config/modules/quickstart.mod
+++ b/jetty-quickstart/src/main/config/modules/quickstart.mod
@@ -7,6 +7,5 @@
 plus
 annotations
 
-
 [lib]
 lib/jetty-quickstart-${jetty.version}.jar
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java
index b5df0f0..2884ba9 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.java
@@ -30,7 +30,6 @@
     private static final Logger LOG = Log.getLogger(PreconfigureQuickStartWar.class);
     static final boolean ORIGIN=LOG.isDebugEnabled();
     
-
     public static void main(String... args) throws Exception
     {
         Resource war = null;
@@ -45,6 +44,7 @@
 
             case 1:
                 dir = Resource.newResource(args[0]);
+                break;
 
             case 2:
                 war = Resource.newResource(args[0]);
@@ -80,7 +80,7 @@
      * @param war The war (or directory) to preconfigure
      * @param dir The directory to expand the war into (or null if war is a directory)
      * @param xml A context XML to apply (or null if none)
-     * @throws Exception
+     * @throws Exception if unable to pre configure
      */
     public static void preconfigure(Resource war, Resource dir, Resource xml) throws Exception 
     {
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
index 29946fb..3ed00c6 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
@@ -31,10 +31,9 @@
 
 /**
  * QuickStartConfiguration
- * 
+ * <p> 
  * Re-inflate a deployable webapp from a saved effective-web.xml
  * which combines all pre-parsed web xml descriptors and annotations.
- * 
  */
 public class QuickStartConfiguration extends WebInfConfiguration
 {
@@ -57,7 +56,7 @@
         Resource webApp = context.newResource(war);
 
         // Accept aliases for WAR files
-        if (webApp.getAlias() != null)
+        if (webApp.isAlias())
         {
             LOG.debug(webApp + " anti-aliased to " + webApp.getAlias());
             webApp = context.newResource(webApp.getAlias());
@@ -83,9 +82,9 @@
     /**
      * Get the quickstart-web.xml file as a Resource.
      * 
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the web app context
+     * @return the Resource for the quickstart-web.xml
+     * @throws Exception if unable to find the quickstart xml
      */
     public Resource getQuickStartWebXml (WebAppContext context) throws Exception
     {
@@ -138,7 +137,7 @@
         context.getMetaData().addDescriptorProcessor(new QuickStartDescriptorProcessor());
         
         //add a decorator that will find introspectable annotations
-        context.addDecorator(new AnnotationDecorator(context)); //this must be the last Decorator because they are run in reverse order!
+        context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); //this must be the last Decorator because they are run in reverse order!
         
         //add a context bean that will run ServletContainerInitializers as the context starts
         ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZER_STARTER);
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
index 45c3a37..5db988d 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java
@@ -48,10 +48,10 @@
 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
 import org.eclipse.jetty.servlet.FilterHolder;
 import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
 import org.eclipse.jetty.servlet.ServletHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.eclipse.jetty.servlet.ServletMapping;
-import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
 import org.eclipse.jetty.util.QuotedStringTokenizer;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -62,11 +62,9 @@
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.eclipse.jetty.xml.XmlAppendable;
 
-
-
 /**
  * QuickStartDescriptorGenerator
- *
+ * <p>
  * Generate an effective web.xml from a WebAppContext, including all components 
  * from web.xml, web-fragment.xmls annotations etc.
  */
@@ -94,9 +92,9 @@
     
     /**
      * Perform the generation of the xml file
-     * @throws IOException 
-     * @throws FileNotFoundException 
-     * @throws Exception
+     * @param stream the stream to generate the quickstart-web.xml to
+     * @throws IOException if unable to generate the quickstart-web.xml
+     * @throws FileNotFoundException if unable to find the file 
      */
     public void generateQuickStartWebXml (OutputStream stream) throws FileNotFoundException, IOException 
     {   
@@ -668,9 +666,9 @@
     /**
      * Find the origin (web.xml, fragment, annotation etc) of a web artifact from MetaData.
      * 
-     * @param md
-     * @param name
-     * @return
+     * @param md the metadata
+     * @param name the name
+     * @return the origin map
      */
     public Map<String, String> origin(MetaData md, String name)
     {
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
index 7e62322..924b0dd 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorProcessor.java
@@ -44,9 +44,6 @@
  */
 public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor
 {
-    /**
-     * 
-     */
     public QuickStartDescriptorProcessor()
     {
         try
@@ -74,13 +71,7 @@
     public void end(WebAppContext context, Descriptor descriptor)
     { 
     }
-    
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitContextParam (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
             throws Exception
     {
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
index 91c1d09..e0ecb69 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartWebApp.java
@@ -104,6 +104,17 @@
             super.startWebapp();
     }
     
+    
+    
+    @Override
+    protected void stopWebapp() throws Exception
+    {
+        if (!_startWebapp)
+            return;
+        
+        super.stopWebapp();
+    }
+
     @Override
     protected void doStart() throws Exception
     {
diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml
index 31806c6..18a3892 100644
--- a/jetty-rewrite/pom.xml
+++ b/jetty-rewrite/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-rewrite</artifactId>
@@ -15,52 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml b/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
index 706a932..65a5dea 100644
--- a/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
+++ b/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Mixin the RewriteHandler                                        -->
@@ -8,34 +8,40 @@
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
-    <!-- =========================================================== -->
-    <!-- configure rewrite handler                                   -->
-    <!-- =========================================================== -->
-    <Get id="oldhandler" name="handler"/>
+  <!-- =========================================================== -->
+  <!-- configure rewrite handler                                   -->
+  <!-- =========================================================== -->
+  <Get id="oldhandler" name="handler"/>
 
-    <Set name="handler">
-     <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
+  <Set name="handler">
+    <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
       <Set name="handler"><Ref refid="oldhandler"/></Set>
-      <Set name="rewriteRequestURI"><Property name="rewrite.rewriteRequestURI" default="true"/></Set>
-      <Set name="rewritePathInfo"><Property name="rewrite.rewritePathInfo" default="false"/></Set>
-      <Set name="originalPathAttribute"><Property name="rewrite.originalPathAttribute" default="requestedPath"/></Set>
-     </New>
-    </Set>
+      <Set name="rewriteRequestURI"><Property name="jetty.rewrite.rewriteRequestURI" deprecated="rewrite.rewriteRequestURI" default="true"/></Set>
+      <Set name="rewritePathInfo"><Property name="jetty.rewrite.rewritePathInfo" deprecated="rewrite.rewritePathInfo" default="false"/></Set>
+      <Set name="originalPathAttribute"><Property name="jetty.rewrite.originalPathAttribute" deprecated="rewrite.originalPathAttribute" default="requestedPath"/></Set>
+   
+      <!-- Set DispatcherTypes  -->
+      <Set name="dispatcherTypes">
+        <Array type="javax.servlet.DispatcherType">
+          <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>REQUEST</Arg></Call></Item>
+          <Item><Call class="javax.servlet.DispatcherType" name="valueOf"><Arg>ASYNC</Arg></Call></Item>
+        </Array>
+      </Set>
 
-    <!-- example rule -->
-    <!--
-    <Call name="addRule">
-      <Arg>
-	<New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
-	  <Set name="pattern">/favicon.ico</Set>
-	  <Set name="name">Cache-Control</Set>
-	  <Set name="value">Max-Age=3600,public</Set>
-	  <Set name="terminating">true</Set>
-	</New>
-      </Arg>
-    </Call>
-    -->
+      <!-- example rule -->
+      <!--
+      <Call name="addRule">
+	<Arg>
+	  <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+	    <Set name="pattern">/favicon.ico</Set>
+	    <Set name="name">Cache-Control</Set>
+	    <Set name="value">Max-Age=3600,public</Set>
+	    <Set name="terminating">true</Set>
+	  </New>
+	</Arg>
+      </Call>
+      -->
 
-    <!-- for example rules see jetty-demo.xml -->
-
+    </New>
+  </Set>
 </Configure>
diff --git a/jetty-rewrite/src/main/config/modules/rewrite.mod b/jetty-rewrite/src/main/config/modules/rewrite.mod
index d2e00c8..c8a1750 100644
--- a/jetty-rewrite/src/main/config/modules/rewrite.mod
+++ b/jetty-rewrite/src/main/config/modules/rewrite.mod
@@ -10,3 +10,13 @@
 
 [xml]
 etc/jetty-rewrite.xml
+
+[ini-template]
+## Whether to rewrite the request URI
+# jetty.rewrite.rewriteRequestURI=true
+
+## Whether to rewrite the path info
+# jetty.rewrite.rewritePathInfo=false
+
+## Request attribute key under with the original path is stored
+# jetty.rewrite.originalPathAttribute=requestedPath
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java
index f78ec3a..7cf662a 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/CompactPathRule.java
@@ -43,7 +43,7 @@
         String uri = request.getRequestURI();
         if (uri.startsWith("/"))
             uri = URIUtil.compactPath(uri);
-        request.setRequestURI(uri);
+        request.setURIPathQuery(uri);
     }
 
     @Override
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java
index 46ea239..21c2f6b 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRule.java
@@ -116,6 +116,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Returns the add flag value.
+     * @return true if add flag set
      */
     public boolean isAdd()
     {
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRule.java
index 70f217e..981c092 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRule.java
@@ -109,7 +109,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns the add flag value.
+     * @return the add flag value.
      */
     public boolean isAdd()
     {
@@ -118,7 +118,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns the header contents.
+     * @return the header contents.
      */
     @Override
     public String toString()
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/LegacyRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/LegacyRule.java
deleted file mode 100644
index e95fb61..0000000
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/LegacyRule.java
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rewrite.handler;
-
-import java.io.IOException;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.util.URIUtil;
-
-/**
- * Rule implementing the legacy API of RewriteHandler
- * 
- *
- */
-public class LegacyRule extends Rule
-{
-    private PathMap _rewrite = new PathMap(true);
-    
-    public LegacyRule()
-    {
-        _handling = false;
-        _terminating = false;
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public String matchAndApply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
-    {
-        Map.Entry<?,?> rewrite =_rewrite.getMatch(target);
-        
-        if (rewrite!=null && rewrite.getValue()!=null)
-        {
-            target=URIUtil.addPaths(rewrite.getValue().toString(),
-                    PathMap.pathInfo(rewrite.getKey().toString(),target));
-
-            return target;
-        }
-        
-        return null;
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * Returns the map of rewriting rules.
-     * @return A {@link PathMap} of the rewriting rules.
-     */
-    public PathMap getRewrite()
-    {
-        return _rewrite;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Sets the map of rewriting rules.
-     * @param rewrite A {@link PathMap} of the rewriting rules. Only 
-     * prefix paths should be included.
-     */
-    public void setRewrite(PathMap rewrite)
-    {
-        _rewrite=rewrite;
-    }
-    
-    
-    /* ------------------------------------------------------------ */
-    /** Add a path rewriting rule
-     * @param pattern The path pattern to match. The pattern must start with / and may use
-     * a trailing /* as a wildcard.
-     * @param prefix The path prefix which will replace the matching part of the path.
-     */
-    public void addRewriteRule(String pattern, String prefix)
-    {
-        if (pattern==null || pattern.length()==0 || !pattern.startsWith("/"))
-            throw new IllegalArgumentException();
-        if (_rewrite==null)
-            _rewrite=new PathMap(true);
-        _rewrite.put(pattern,prefix);
-    }
-
-
-}
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRule.java
index 840f538..5b4096a 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRule.java
@@ -23,21 +23,26 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpStatus;
+
 /**
- * Redirects the response whenever the rule finds a match.
+ * Issues a (3xx) Redirect response whenever the rule finds a match.
+ * <p>
+ * All redirects are part of the <a href="http://tools.ietf.org/html/rfc7231#section-6.4"><code>3xx Redirection</code> status code set</a>.
+ * <p>
+ * Defaults to <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3"><code>302 Found</code></a>
  */
 public class RedirectPatternRule extends PatternRule
 {
     private String _location;
-
-    /* ------------------------------------------------------------ */
+    private int _statusCode = HttpStatus.FOUND_302;
+    
     public RedirectPatternRule()
     {
         _handling = true;
         _terminating = true;
     }
 
-    /* ------------------------------------------------------------ */
     /**
      * Sets the redirect location.
      * 
@@ -47,26 +52,46 @@
     {
         _location = value;
     }
-
-    /* ------------------------------------------------------------ */
-    /*
-     * (non-Javadoc)
-     * @see org.eclipse.jetty.server.server.handler.rules.RuleBase#apply(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+    
+    /**
+     * Sets the redirect status code.
+     * 
+     * @param statusCode the 3xx redirect status code
      */
+    public void setStatusCode(int statusCode)
+    {
+        if ((300 <= statusCode) || (statusCode >= 399))
+        {
+            _statusCode = statusCode;
+        }
+        else
+        {
+            throw new IllegalArgumentException("Invalid redirect status code " + statusCode + " (must be a value between 300 and 399)");
+        }
+    }
+
     @Override
     public String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
     {
-        response.sendRedirect(response.encodeRedirectURL(_location));
+        String location = response.encodeRedirectURL(_location);
+        response.setHeader("Location",RedirectUtil.toRedirectURL(request,location));
+        response.setStatus(_statusCode);
+        response.getOutputStream().flush(); // no output / content
+        response.getOutputStream().close();
         return target;
     }
 
-    /* ------------------------------------------------------------ */
     /**
-     * Returns the redirect location.
+     * Returns the redirect status code and location.
      */
     @Override
     public String toString()
     {
-        return super.toString()+"["+_location+"]";
+        StringBuilder str = new StringBuilder();
+        str.append(super.toString());
+        str.append('[').append(_statusCode);
+        str.append('>').append(_location);
+        str.append(']');
+        return str.toString();
     }
 }
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRule.java
index ba6428b..0d72002 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRule.java
@@ -24,13 +24,21 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpStatus;
+
 /**
- * Redirects the response by matching with a regular expression.
+ * Issues a (3xx) Redirect response whenever the rule finds a match via regular expression.
+ * <p>
  * The replacement string may use $n" to replace the nth capture group.
+ * <p>
+ * All redirects are part of the <a href="http://tools.ietf.org/html/rfc7231#section-6.4"><code>3xx Redirection</code> status code set</a>.
+ * <p>
+ * Defaults to <a href="http://tools.ietf.org/html/rfc7231#section-6.4.3"><code>302 Found</code></a>
  */
 public class RedirectRegexRule extends RegexRule
 {
-    private String _replacement;
+    protected String _replacement;
+    private int _statusCode = HttpStatus.FOUND_302;
     
     public RedirectRegexRule()
     {
@@ -48,6 +56,23 @@
         _replacement = replacement;
     }
     
+    /**
+     * Sets the redirect status code.
+     * 
+     * @param statusCode the 3xx redirect status code
+     */
+    public void setStatusCode(int statusCode)
+    {
+        if ((300 <= statusCode) || (statusCode >= 399))
+        {
+            _statusCode = statusCode;
+        }
+        else
+        {
+            throw new IllegalArgumentException("Invalid redirect status code " + statusCode + " (must be a value between 300 and 399)");
+        }
+    }
+    
     @Override
     protected String apply(String target, HttpServletRequest request, HttpServletResponse response, Matcher matcher)
             throws IOException
@@ -58,8 +83,27 @@
             String group = matcher.group(g);
             target=target.replaceAll("\\$"+g,group);
         }
-
-        response.sendRedirect(response.encodeRedirectURL(target));
+        
+        target = response.encodeRedirectURL(target);
+        response.setHeader("Location",RedirectUtil.toRedirectURL(request,target));
+        response.setStatus(_statusCode);
+        response.getOutputStream().flush(); // no output / content
+        response.getOutputStream().close();
         return target;
     }
+    
+    /**
+     * Returns the redirect status code and replacement.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder str = new StringBuilder();
+        str.append(super.toString());
+        str.append('[').append(_statusCode);
+        str.append('>').append(_replacement);
+        str.append(']');
+        return str.toString();
+    }
+
 }
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectUtil.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectUtil.java
new file mode 100644
index 0000000..2e8b893
--- /dev/null
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RedirectUtil.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.rewrite.handler;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.util.URIUtil;
+
+/**
+ * Utility for managing redirect based rules
+ */
+public final class RedirectUtil
+{
+    /**
+     * Common point to generate a proper "Location" header for redirects.
+     * 
+     * @param request
+     *            the request the redirect should be based on (needed when relative locations are provided, so that
+     *            server name, scheme, port can be built out properly)
+     * @param location
+     *            the location URL to redirect to (can be a relative path)
+     * @return the full redirect "Location" URL (including scheme, host, port, path, etc...)
+     */
+    public static String toRedirectURL(final HttpServletRequest request, String location)
+    {
+        if (!URIUtil.hasScheme(location))
+        {
+            StringBuilder url = new StringBuilder(128);
+            URIUtil.appendSchemeHostPort(url,request.getScheme(),request.getServerName(),request.getServerPort());
+
+            if (location.startsWith("/"))
+            {
+                // absolute in context
+                location = URIUtil.canonicalPath(location);
+            }
+            else
+            {
+                // relative to request
+                String path = request.getRequestURI();
+                String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path);
+                location = URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
+                if (!location.startsWith("/"))
+                    url.append('/');
+            }
+
+            if (location == null)
+                throw new IllegalStateException("path cannot be above root");
+            url.append(location);
+
+            location = url.toString();
+        }
+
+        return location;
+    }
+}
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRule.java
index c1802b4..89f0b7e 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ResponsePatternRule.java
@@ -53,7 +53,7 @@
      * Sets the reason for the response status code. Reasons will only reflect
      * if the code value is greater or equal to 400.
      * 
-     * @param reason
+     * @param reason the reason
      */
     public void setReason(String reason)
     {
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java
index fcbb021..5d403a4 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java
@@ -54,7 +54,6 @@
  * <li> {@link RewritePatternRule} - rewrites the requested URI. </li>
  * <li> {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching. </li>
  * <li> {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6. </li>
- * <li> {@link LegacyRule} - the old version of rewrite. </li>
  * <li> {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present. </li>
  * <li> {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.</li>
  * </ul>
@@ -174,7 +173,7 @@
 public class RewriteHandler extends HandlerWrapper
 {
     private RuleContainer _rules;
-    private EnumSet<DispatcherType> _dispatchTypes = EnumSet.of(DispatcherType.REQUEST);
+    private EnumSet<DispatcherType> _dispatchTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC);
 
     /* ------------------------------------------------------------ */
     public RewriteHandler()
@@ -184,19 +183,6 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
-     * originalPathAttribute
-     *
-     * @param legacyRule old style rewrite rule
-     */
-    @Deprecated
-    public void setLegacyRule(LegacyRule legacyRule)
-    {
-        _rules.setLegacyRule(legacyRule);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
      * Returns the list of rules.
      * @return an array of {@link Rule}.
      */
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java
index 6315c51..bced576 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewritePatternRule.java
@@ -23,7 +23,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.http.PathMap;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.URIUtil;
@@ -57,12 +56,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.eclipse.jetty.server.handler.rules.RuleBase#apply(javax.servlet.http.HttpServletRequest,
-     * javax.servlet.http.HttpServletResponse)
-     */
     @Override
     public String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
     {
@@ -74,21 +67,21 @@
     /**
      * This method will add _query to the requests's queryString and also combine it with existing queryStrings in
      * the request. However it won't take care for duplicate. E.g. if request.getQueryString contains a parameter
-     * "param1 = true" and _query will contain "param1=false" the result will be param1=true&param1=false.
+     * <code>param1 = true</code> and _query will contain <code>param1=false</code> the result will be <code>param1=true&amp;param1=false</code>.
      * To cover this use case some more complex pattern matching is necessary. We can implement this if there's use
      * cases.
      *
-     * @param request
-     * @param oldURI
-     * @param newURI
-     * @throws IOException
+     * @param request the request
+     * @param oldURI the old URI
+     * @param newURI the new URI
+     * @throws IOException if unable to apply the URI
      */
     @Override
     public void applyURI(Request request, String oldURI, String newURI) throws IOException
     {
         if (_query == null)
         {
-            request.setRequestURI(newURI);
+            request.setURIPathQuery(newURI);
         }
         else
         {
@@ -97,9 +90,7 @@
                 queryString = queryString + "&" + _query;
             else
                 queryString = _query;
-            HttpURI uri = new HttpURI(newURI + "?" + queryString);
-            request.setUri(uri);
-            request.setRequestURI(newURI);
+            request.setURIPathQuery(newURI);
             request.setQueryString(queryString);
         }
     }
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java
index 2caa948..c7f0df3 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRule.java
@@ -24,7 +24,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.server.Request;
 
 /**
@@ -100,7 +99,7 @@
     {
         if (_query==null)
         {
-            request.setRequestURI(newURI);
+            request.setURIPathQuery(newURI);
         }
         else
         {
@@ -108,9 +107,7 @@
             
             if (!_queryGroup && request.getQueryString()!=null)
                 query=request.getQueryString()+"&"+query;
-            HttpURI uri=new HttpURI(newURI+"?"+query);
-            request.setUri(uri);
-            request.setRequestURI(newURI);
+            request.setURIPathQuery(newURI);
             request.setQueryString(query);
         }
     }
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/Rule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/Rule.java
index d24eb4f..3019491 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/Rule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/Rule.java
@@ -44,20 +44,18 @@
     /**
      * This method calls tests the rule against the request/response pair and if the Rule 
      * applies, then the rule's action is triggered.
-     * @param target The target of the request
-     * @param request
-     * @param response
      * 
+     * @param target The target of the request
+     * @param request the request
+     * @param response the response
      * @return The new target if the rule has matched, else null
-     * @throws IOException
+     * @throws IOException if unable to match the rule
      */
     public abstract String matchAndApply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException;   
     
     /**
      * Sets terminating to true or false.
-     * If true, this rule will terminate the loop if this rule has been applied.
-     * 
-     * @param terminating
+     * @param terminating If true, this rule will terminate the loop if this rule has been applied.
      */    
     public void setTerminating(boolean terminating)
     {
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
index 00e8071..727d838 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RuleContainer.java
@@ -23,7 +23,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.ArrayUtil;
 import org.eclipse.jetty.util.URIUtil;
@@ -33,48 +32,19 @@
 /**
  * Base container to group rules. Can be extended so that the contained rules
  * will only be applied under certain conditions
- * 
- * 
  */
-
 public class RuleContainer extends Rule
 {
+    public static final String ORIGINAL_QUERYSTRING_ATTRIBUTE_SUFFIX = ".QUERYSTRING";
     private static final Logger LOG = Log.getLogger(RuleContainer.class);
 
     protected Rule[] _rules;
     
     protected String _originalPathAttribute;
+    protected String _originalQueryStringAttribute;
     protected boolean _rewriteRequestURI=true;
     protected boolean _rewritePathInfo=true;
-    
-    protected LegacyRule _legacy;
-
-    /* ------------------------------------------------------------ */
-    @Deprecated
-    public LegacyRule getLegacyRule()
-    {
-        if (_legacy==null)
-        {
-            _legacy= new LegacyRule();
-            addRule(_legacy);
-        }
-        return _legacy;
-    }
-    
-
-    /* ------------------------------------------------------------ */
-    /**
-     * To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and
-     * originalPathAttribute
-     * 
-     * @param legacyRule old style rewrite rule
-     */
-    @Deprecated
-    public void setLegacyRule(LegacyRule legacyRule)
-    {
-        _legacy = legacyRule;
-    }
-
+     
     /* ------------------------------------------------------------ */
     /**
      * Returns the list of rules.
@@ -92,16 +62,7 @@
      */
     public void setRules(Rule[] rules)
     {
-        if (_legacy==null)
-            _rules = rules;
-        else
-        {
-            _rules=null;
-            addRule(_legacy);
-            if (rules!=null)
-                for (Rule rule:rules)
-                    addRule(rule);
-        }
+        _rules = rules;
     }
 
     /* ------------------------------------------------------------ */
@@ -173,6 +134,7 @@
     public void setOriginalPathAttribute(String originalPathAttribte)
     {
         _originalPathAttribute=originalPathAttribte;
+        _originalQueryStringAttribute = originalPathAttribte + ORIGINAL_QUERYSTRING_ATTRIBUTE_SUFFIX;
     }
     
     /**
@@ -192,22 +154,32 @@
      * @param target target field to pass on to the contained rules
      * @param request request object to pass on to the contained rules
      * @param response response object to pass on to the contained rules
+     * @return the target
+     * @throws IOException if unable to apply the rule
      */
     protected String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
     {
         boolean original_set=_originalPathAttribute==null;
+        
+        target = URIUtil.compactPath(target);
                 
         for (Rule rule : _rules)
         {
             String applied=rule.matchAndApply(target,request, response);
             if (applied!=null)
-            {       
+            {
+                applied = URIUtil.compactPath(applied);
+                
                 LOG.debug("applied {}",rule);
                 LOG.debug("rewrote {} to {}",target,applied);
                 if (!original_set)
                 {
                     original_set=true;
                     request.setAttribute(_originalPathAttribute, target);
+                    
+                    String query = request.getQueryString();
+                    if (query != null)
+                        request.setAttribute(_originalQueryStringAttribute,query);
                 }     
 
                 if (_rewriteRequestURI)
@@ -216,7 +188,7 @@
                     if (rule instanceof Rule.ApplyURI)
                         ((Rule.ApplyURI)rule).applyURI((Request)request,((Request)request).getRequestURI(), encoded);
                     else
-                        ((Request)request).setRequestURI(encoded);
+                        ((Request)request).setURIPathQuery(encoded);
                 }
 
                 if (_rewritePathInfo)
@@ -227,7 +199,7 @@
                 if (rule.isHandling())
                 {
                     LOG.debug("handling {}",rule);
-                    (request instanceof Request?(Request)request:HttpChannel.getCurrentHttpChannel().getRequest()).setHandled(true);
+                    Request.getBaseRequest(request).setHandled(true);
                 }
 
                 if (rule.isTerminating())
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRule.java
new file mode 100644
index 0000000..55283d8
--- /dev/null
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRule.java
@@ -0,0 +1,51 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.rewrite.handler;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * If this rule matches, terminate the processing of other rules.
+ * Allowing the request to be processed by the handlers after the rewrite rules.
+ */
+public class TerminatingPatternRule extends PatternRule
+{
+    public TerminatingPatternRule()
+    {
+        super.setTerminating(true);
+    }
+
+    @Override
+    public void setTerminating(boolean terminating)
+    {
+        if (!terminating)
+        {
+            throw new RuntimeException("Not allowed to disable terminating on a " + TerminatingPatternRule.class.getName());
+        }
+    }
+
+    @Override
+    protected String apply(String target, HttpServletRequest request, HttpServletResponse response) throws IOException
+    {
+        return target;
+    }
+}
\ No newline at end of file
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRule.java
new file mode 100644
index 0000000..32ac893
--- /dev/null
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRule.java
@@ -0,0 +1,52 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.rewrite.handler;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * If this rule matches, terminate the processing of other rules.
+ * Allowing the request to be processed by the handlers after the rewrite rules.
+ */
+public class TerminatingRegexRule extends RegexRule
+{
+    public TerminatingRegexRule()
+    {
+        super.setTerminating(true);
+    }
+
+    @Override
+    public void setTerminating(boolean terminating)
+    {
+        if (!terminating)
+        {
+            throw new RuntimeException("Not allowed to disable terminating on a " + TerminatingRegexRule.class.getName());
+        }
+    }
+
+    @Override
+    public String apply(String target, HttpServletRequest request, HttpServletResponse response, Matcher matcher) throws IOException
+    {
+        return target;
+    }
+}
\ No newline at end of file
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java
index c9b9034..26bb392 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ValidUrlRule.java
@@ -29,12 +29,13 @@
 
 /**
  * This rule can be used to protect against invalid unicode characters in a url making it into applications.
- *
+ * <p>
  * The logic is as follows.
- * 
- * - if decoded uri character is an iso control character return code/reason
- * - if no UnicodeBlock is found for character return code/reason
- * - if character is in UnicodeBlock.SPECIALS return code/reason
+ * <ul>
+ * <li>if decoded uri character is an iso control character return code/reason</li>
+ * <li>if no UnicodeBlock is found for character return code/reason</li>
+ * <li>if character is in UnicodeBlock.SPECIALS return code/reason</li>
+ * </ul>
  */
 public class ValidUrlRule extends Rule
 {
@@ -65,7 +66,7 @@
     /**
      * Sets the reason for the response status code. Reasons will only reflect if the code value is greater or equal to 400.
      * 
-     * @param reason
+     * @param reason the reason
      */
     public void setReason(String reason)
     {
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java
index 1313b13..9ca4009 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ForwardedSchemeHeaderRuleTest.java
@@ -73,11 +73,11 @@
         _rule.matchAndApply("/",_request,_response);
         assertEquals("https",_request.getScheme());
 
-        _request.setScheme(null);
+        _request.setScheme("other");
         // header value doesn't match rule's value
         setRequestHeader("Front-End-Https", "off");
         _rule.matchAndApply("/",_request,_response);
-        assertEquals(null,_request.getScheme());
+        assertEquals("other",_request.getScheme());
 
         _request.setScheme(null);
         // header value can be any value
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRuleTest.java
index 7ad8377..f3caa86 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderRegexRuleTest.java
@@ -18,13 +18,14 @@
 
 package org.eclipse.jetty.rewrite.handler;
 
-import org.junit.Before;
-import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.util.Iterator;
 
+import org.junit.Before;
+import org.junit.Test;
+
 public class HeaderRegexRuleTest extends AbstractRuleTestCase
 {
 
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java
deleted file mode 100644
index ec3f058..0000000
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/LegacyRuleTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rewrite.handler;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class LegacyRuleTest extends AbstractRuleTestCase
-{
-    private String[][] _tests=
-    {
-            {"/foo/bar","/*","/replace/foo/bar"},
-            {"/foo/bar","/foo/*","/replace/bar"},
-            {"/foo/bar","/foo/bar","/replace"}
-    };
-    private LegacyRule _rule;
-
-    @Before
-    public void init() throws Exception
-    {
-        start(false);
-        _rule = new LegacyRule();
-    }
-
-    @After
-    public void destroy()
-    {
-        _rule = null;
-    }
-
-    @Test
-    public void testMatchAndApply() throws Exception
-    {
-        for (String[] _test : _tests)
-        {
-            _rule.addRewriteRule(_test[1], "/replace");
-            String result = _rule.matchAndApply(_test[0], _request, _response);
-            assertEquals(_test[1], _test[2], result);
-        }
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testAddRewrite()
-    {
-        _rule.addRewriteRule("*.txt", "/replace");
-    }
-}
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java
index f2c2863..4d12e60 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/PatternRuleTest.java
@@ -25,6 +25,10 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.server.Request;
 import org.junit.After;
 import org.junit.Before;
@@ -138,7 +142,7 @@
         new Request(null,null)
         {
             {
-                setRequestURI(uri);
+                setMetaData(new MetaData.Request("GET",new HttpURI(uri),HttpVersion.HTTP_1_0,new HttpFields()));
             }
         }, null
         );
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java
index 19d6eda..c356f26 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectPatternRuleTest.java
@@ -18,39 +18,54 @@
 
 package org.eclipse.jetty.rewrite.handler;
 
-import static org.junit.Assert.assertEquals;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 import java.io.IOException;
 
 import org.eclipse.jetty.http.HttpHeader;
-import org.junit.After;
+import org.eclipse.jetty.http.HttpStatus;
 import org.junit.Before;
 import org.junit.Test;
 
 public class RedirectPatternRuleTest extends AbstractRuleTestCase
 {
-    private RedirectPatternRule _rule;
-
     @Before
     public void init() throws Exception
     {
         start(false);
-        _rule = new RedirectPatternRule();
-        _rule.setPattern("*");
     }
 
-    @After
-    public void destroy()
+    private void assertRedirectResponse(int expectedStatusCode, String expectedLocation) throws IOException
     {
-        _rule = null;
+        assertThat("Response status code",_response.getStatus(),is(expectedStatusCode));
+        assertThat("Response location",_response.getHeader(HttpHeader.LOCATION.asString()),is(expectedLocation));
     }
 
     @Test
-    public void testLocation() throws IOException
+    public void testGlobPattern() throws IOException
     {
         String location = "http://eclipse.com";
-        _rule.setLocation(location);
-        _rule.apply(null, _request, _response);
-        assertEquals(location, _response.getHeader(HttpHeader.LOCATION.asString()));
+
+        RedirectPatternRule rule = new RedirectPatternRule();
+        rule.setPattern("*");
+        rule.setLocation(location);
+
+        rule.apply("/",_request,_response);
+        assertRedirectResponse(HttpStatus.FOUND_302,location);
+    }
+
+    @Test
+    public void testPrefixPattern() throws IOException
+    {
+        String location = "http://api.company.com/";
+
+        RedirectPatternRule rule = new RedirectPatternRule();
+        rule.setPattern("/api/*");
+        rule.setLocation(location);
+        rule.setStatusCode(HttpStatus.MOVED_PERMANENTLY_301);
+
+        rule.apply("/api/rest?foo=1",_request,_response);
+        assertRedirectResponse(HttpStatus.MOVED_PERMANENTLY_301,location);
     }
 }
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java
index 9f77d64..66a60cd 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RedirectRegexRuleTest.java
@@ -18,62 +18,88 @@
 
 package org.eclipse.jetty.rewrite.handler;
 
-import static org.junit.Assert.assertEquals;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 import java.io.IOException;
 
 import org.eclipse.jetty.http.HttpHeader;
-import org.junit.After;
+import org.eclipse.jetty.http.HttpStatus;
 import org.junit.Before;
 import org.junit.Test;
 
 public class RedirectRegexRuleTest extends AbstractRuleTestCase
 {
-    private RedirectRegexRule _rule;
-
     @Before
     public void init() throws Exception
     {
         start(false);
-        _rule = new RedirectRegexRule();
     }
-
-    @After
-    public void destroy()
+    
+    private void assertRedirectResponse(int expectedStatusCode, String expectedLocation) throws IOException
     {
-        _rule = null;
+        assertThat("Response status code", _response.getStatus(), is(expectedStatusCode));
+        assertThat("Response location", _response.getHeader(HttpHeader.LOCATION.asString()), is(expectedLocation));
     }
 
     @Test
     public void testLocationWithReplacementGroupEmpty() throws IOException
     {
-        _rule.setRegex("/my/dir/file/(.*)$");
-        _rule.setReplacement("http://www.mortbay.org/$1");
+        RedirectRegexRule rule = new RedirectRegexRule();
+        rule.setRegex("/my/dir/file/(.*)$");
+        rule.setReplacement("http://www.mortbay.org/$1");
 
         // Resource is dir
-        _rule.matchAndApply("/my/dir/file/", _request, _response);
-        assertEquals("http://www.mortbay.org/", _response.getHeader(HttpHeader.LOCATION.asString()));
+        rule.matchAndApply("/my/dir/file/", _request, _response);
+        assertRedirectResponse(HttpStatus.FOUND_302,"http://www.mortbay.org/");
+    }
+    
+    @Test
+    public void testLocationWithPathReplacement() throws IOException
+    {
+        RedirectRegexRule rule = new RedirectRegexRule();
+        rule.setRegex("/documentation/(.*)$");
+        rule.setReplacement("/docs/$1");
+
+        // Resource is dir
+        rule.matchAndApply("/documentation/top.html", _request, _response);
+        assertRedirectResponse(HttpStatus.FOUND_302,"http://0.0.0.0/docs/top.html");
     }
 
     @Test
     public void testLocationWithReplacmentGroupSimple() throws IOException
     {
-        _rule.setRegex("/my/dir/file/(.*)$");
-        _rule.setReplacement("http://www.mortbay.org/$1");
+        RedirectRegexRule rule = new RedirectRegexRule();
+        rule.setRegex("/my/dir/file/(.*)$");
+        rule.setReplacement("http://www.mortbay.org/$1");
 
         // Resource is an image
-        _rule.matchAndApply("/my/dir/file/image.png", _request, _response);
-        assertEquals("http://www.mortbay.org/image.png", _response.getHeader(HttpHeader.LOCATION.asString()));
+        rule.matchAndApply("/my/dir/file/image.png", _request, _response);
+        assertRedirectResponse(HttpStatus.FOUND_302,"http://www.mortbay.org/image.png");
     }
 
     @Test
     public void testLocationWithReplacementGroupDeepWithParams() throws IOException
     {
-        _rule.setRegex("/my/dir/file/(.*)$");
-        _rule.setReplacement("http://www.mortbay.org/$1");
+        RedirectRegexRule rule = new RedirectRegexRule();
+        rule.setRegex("/my/dir/file/(.*)$");
+        rule.setReplacement("http://www.mortbay.org/$1");
 
         // Resource is api with parameters
-        _rule.matchAndApply("/my/dir/file/api/rest/foo?id=100&sort=date", _request, _response);
-        assertEquals("http://www.mortbay.org/api/rest/foo?id=100&sort=date", _response.getHeader(HttpHeader.LOCATION.asString()));
+        rule.matchAndApply("/my/dir/file/api/rest/foo?id=100&sort=date", _request, _response);
+        assertRedirectResponse(HttpStatus.FOUND_302,"http://www.mortbay.org/api/rest/foo?id=100&sort=date");
+    }
+    
+    @Test
+    public void testMovedPermanently() throws IOException
+    {
+        RedirectRegexRule rule = new RedirectRegexRule();
+        rule.setRegex("/api/(.*)$");
+        rule.setReplacement("http://api.company.com/$1");
+        rule.setStatusCode(HttpStatus.MOVED_PERMANENTLY_301);
+
+        // Resource is api with parameters
+        rule.matchAndApply("/api/rest/foo?id=100&sort=date", _request, _response);
+        assertRedirectResponse(HttpStatus.MOVED_PERMANENTLY_301,"http://api.company.com/rest/foo?id=100&sort=date");
     }
 }
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java
index a663a08..96b150f 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteHandlerTest.java
@@ -85,7 +85,7 @@
         _handler.setOriginalPathAttribute("/before");
         _handler.setRewriteRequestURI(true);
         _handler.setRewritePathInfo(true);
-        _request.setRequestURI("/xxx/bar");
+        _request.setURIPathQuery("/xxx/bar");
         _request.setPathInfo("/xxx/bar");
         _handler.handle("/xxx/bar",_request,_request, _response);
         assertEquals(201,_response.getStatus());
@@ -99,7 +99,7 @@
         _handler.setOriginalPathAttribute("/before");
         _handler.setRewriteRequestURI(false);
         _handler.setRewritePathInfo(false);
-        _request.setRequestURI("/foo/bar");
+        _request.setURIPathQuery("/foo/bar");
         _request.setPathInfo("/foo/bar");
         
         _handler.handle("/foo/bar",_request,_request, _response);
@@ -112,7 +112,7 @@
         _response.setStatus(200);
         _request.setHandled(false);
         _handler.setOriginalPathAttribute(null);
-        _request.setRequestURI("/aaa/bar");
+        _request.setURIPathQuery("/aaa/bar");
         _request.setPathInfo("/aaa/bar");
         _handler.handle("/aaa/bar",_request,_request, _response);
         assertEquals(201,_response.getStatus());
@@ -126,7 +126,7 @@
         _handler.setOriginalPathAttribute("before");
         _handler.setRewriteRequestURI(true);
         _handler.setRewritePathInfo(true);
-        _request.setRequestURI("/aaa/bar");
+        _request.setURIPathQuery("/aaa/bar");
         _request.setPathInfo("/aaa/bar");
         _handler.handle("/aaa/bar",_request,_request, _response);
         assertEquals(201,_response.getStatus());
@@ -138,7 +138,7 @@
         _response.setStatus(200);
         _request.setHandled(false);
         _rule2.setTerminating(true);
-        _request.setRequestURI("/aaa/bar");
+        _request.setURIPathQuery("/aaa/bar");
         _request.setPathInfo("/aaa/bar");
         _handler.handle("/aaa/bar",_request,_request, _response);
         assertEquals(201,_response.getStatus());
@@ -154,7 +154,7 @@
         _request.setAttribute("target",null);
         _request.setAttribute("URI",null);
         _request.setAttribute("info",null);
-        _request.setRequestURI("/aaa/bar");
+        _request.setURIPathQuery("/aaa/bar");
         _request.setPathInfo("/aaa/bar");
         _handler.handle("/aaa/bar",_request,_request, _response);
         assertEquals(200,_response.getStatus());
@@ -174,7 +174,7 @@
         _handler.setOriginalPathAttribute("/before");
         _handler.setRewriteRequestURI(true);
         _handler.setRewritePathInfo(false);
-        _request.setRequestURI("/ccc/x%20y");
+        _request.setURIPathQuery("/ccc/x%20y");
         _request.setPathInfo("/ccc/x y");
         _handler.handle("/ccc/x y",_request,_request, _response);
         assertEquals(201,_response.getStatus());
@@ -193,7 +193,7 @@
         _handler.setOriginalPathAttribute("/before");
         _handler.setRewriteRequestURI(true);
         _handler.setRewritePathInfo(false);
-        _request.setRequestURI("/xxx/x%20y");
+        _request.setURIPathQuery("/xxx/x%20y");
         _request.setPathInfo("/xxx/x y");
         _handler.handle("/xxx/x y",_request,_request, _response);
         assertEquals(201,_response.getStatus());
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java
index a021679..77ac4fb 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewritePatternRuleTest.java
@@ -23,7 +23,6 @@
 
 import java.io.IOException;
 
-import org.eclipse.jetty.http.HttpURI;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -88,7 +87,7 @@
     {
         String replacement = "/replace";
         String queryString = "request=parameter";
-        _request.setUri(new HttpURI("/old/context"));
+        _request.setURIPathQuery("/old/context");
         _request.setQueryString(queryString);
 
         RewritePatternRule rewritePatternRule = new RewritePatternRule();
@@ -111,7 +110,7 @@
         String[] split = replacement.split("\\?", 2);
         String path = split[0];
         String queryString = split[1];
-        _request.setUri(new HttpURI("/old/context"));
+        _request.setURIPathQuery("/old/context");
         _request.setQueryString(requestQueryString);
 
         RewritePatternRule rewritePatternRule = new RewritePatternRule();
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
index 9eca638..4c2a479 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/RewriteRegexRuleTest.java
@@ -23,7 +23,6 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 
-import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.util.MultiMap;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.UrlEncoded;
@@ -66,15 +65,13 @@
         for (String[] test : _tests)
         {
             reset();
-            _request.setRequestURI(null);
+            _request.setURIPathQuery(null);
             
             String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3];
             _rule.setRegex(test[2]);
             _rule.setReplacement(test[3]);
 
-            _request.setUri(new HttpURI(test[0]+(test[1]==null?"":("?"+test[1]))));
-            _request.getRequestURI();
-
+            _request.setURIPathQuery(test[0]+(test[1]==null?"":("?"+test[1])));
             
             String result = _rule.matchAndApply(test[0], _request, _response);
             assertEquals(t, test[4], result);
@@ -89,7 +86,7 @@
             if (test[5]!=null)
             {
                 MultiMap<String> params=new MultiMap<String>();
-                UrlEncoded.decodeTo(test[5],params, StandardCharsets.UTF_8,-1);
+                UrlEncoded.decodeTo(test[5],params, StandardCharsets.UTF_8);
                                
                 for (String n:params.keySet())
                     assertEquals(params.getString(n),_request.getParameter(n));
@@ -110,7 +107,7 @@
             _rule.setRegex(test[2]);
             _rule.setReplacement(test[3]);
 
-            _request.setRequestURI(test[0]);
+            _request.setURIPathQuery(test[0]);
             _request.setQueryString(test[1]);
             _request.getAttributes().clearAttributes();
             
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRuleTest.java
new file mode 100644
index 0000000..7927b60
--- /dev/null
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingPatternRuleTest.java
@@ -0,0 +1,103 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.rewrite.handler;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TerminatingPatternRuleTest extends AbstractRuleTestCase
+{
+    private RewriteHandler rewriteHandler;
+
+    @Before
+    public void init() throws Exception
+    {
+        rewriteHandler = new RewriteHandler();
+        rewriteHandler.setServer(_server);
+        rewriteHandler.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
+                    ServletException
+            {
+                response.setStatus(HttpStatus.CREATED_201);
+                request.setAttribute("target",target);
+                request.setAttribute("URI",request.getRequestURI());
+                request.setAttribute("info",request.getPathInfo());
+            }
+        });
+        rewriteHandler.start();
+
+        TerminatingPatternRule rule1 = new TerminatingPatternRule();
+        rule1.setPattern("/login.jsp");
+        rewriteHandler.addRule(rule1);
+        RedirectRegexRule rule2 = new RedirectRegexRule();
+        rule2.setRegex("^/login.*$");
+        rule2.setReplacement("http://login.company.com/");
+        rewriteHandler.addRule(rule2);
+
+        start(false);
+    }
+
+    private void assertIsRedirect(int expectedStatus, String expectedLocation)
+    {
+        assertThat("Response Status",_response.getStatus(),is(expectedStatus));
+        assertThat("Response Location Header",_response.getHeader(HttpHeader.LOCATION.asString()),is(expectedLocation));
+    }
+
+    private void assertIsRequest(String expectedRequestPath)
+    {
+        assertThat("Response Status",_response.getStatus(),is(HttpStatus.CREATED_201));
+        assertThat("Request Target",_request.getAttribute("target"),is(expectedRequestPath));
+    }
+
+    @Test
+    public void testTerminatingEarly() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login.jsp",_request,_request,_response);
+        assertIsRequest("/login.jsp");
+    }
+
+    @Test
+    public void testNoTerminationDo() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login.do",_request,_request,_response);
+        assertIsRedirect(HttpStatus.MOVED_TEMPORARILY_302,"http://login.company.com/");
+    }
+
+    @Test
+    public void testNoTerminationDir() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login/",_request,_request,_response);
+        assertIsRedirect(HttpStatus.MOVED_TEMPORARILY_302,"http://login.company.com/");
+    }
+}
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRuleTest.java
new file mode 100644
index 0000000..adbc674
--- /dev/null
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/TerminatingRegexRuleTest.java
@@ -0,0 +1,103 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.rewrite.handler;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TerminatingRegexRuleTest extends AbstractRuleTestCase
+{
+    private RewriteHandler rewriteHandler;
+
+    @Before
+    public void init() throws Exception
+    {
+        rewriteHandler = new RewriteHandler();
+        rewriteHandler.setServer(_server);
+        rewriteHandler.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
+                    ServletException
+            {
+                response.setStatus(HttpStatus.CREATED_201);
+                request.setAttribute("target",target);
+                request.setAttribute("URI",request.getRequestURI());
+                request.setAttribute("info",request.getPathInfo());
+            }
+        });
+        rewriteHandler.start();
+
+        TerminatingRegexRule rule1 = new TerminatingRegexRule();
+        rule1.setRegex("^/login.jsp$");
+        rewriteHandler.addRule(rule1);
+        RedirectRegexRule rule2 = new RedirectRegexRule();
+        rule2.setRegex("^/login.*$");
+        rule2.setReplacement("http://login.company.com/");
+        rewriteHandler.addRule(rule2);
+
+        start(false);
+    }
+
+    private void assertIsRedirect(int expectedStatus, String expectedLocation)
+    {
+        assertThat("Response Status",_response.getStatus(),is(expectedStatus));
+        assertThat("Response Location Header",_response.getHeader(HttpHeader.LOCATION.asString()),is(expectedLocation));
+    }
+
+    private void assertIsRequest(String expectedRequestPath)
+    {
+        assertThat("Response Status",_response.getStatus(),is(HttpStatus.CREATED_201));
+        assertThat("Request Target",_request.getAttribute("target"),is(expectedRequestPath));
+    }
+
+    @Test
+    public void testTerminatingEarly() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login.jsp",_request,_request,_response);
+        assertIsRequest("/login.jsp");
+    }
+
+    @Test
+    public void testNoTerminationDo() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login.do",_request,_request,_response);
+        assertIsRedirect(HttpStatus.MOVED_TEMPORARILY_302,"http://login.company.com/");
+    }
+
+    @Test
+    public void testNoTerminationDir() throws IOException, ServletException
+    {
+        rewriteHandler.handle("/login/",_request,_request,_response);
+        assertIsRedirect(HttpStatus.MOVED_TEMPORARILY_302,"http://login.company.com/");
+    }
+}
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
index b8c908d..f7eb522 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ValidUrlRuleTest.java
@@ -41,7 +41,7 @@
     public void testValidUrl() throws Exception
     {
         _rule.setCode("404");
-        _request.setRequestURI("/valid/uri.html");
+        _request.setURIPathQuery("/valid/uri.html");
         
         _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
@@ -52,7 +52,7 @@
     public void testInvalidUrl() throws Exception
     {
         _rule.setCode("404");
-        _request.setRequestURI("/invalid%0c/uri.html");
+        _request.setURIPathQuery("/invalid%0c/uri.html");
         
         String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
@@ -64,7 +64,7 @@
     {
         _rule.setCode("405");
         _rule.setReason("foo");
-        _request.setRequestURI("/%00/");
+        _request.setURIPathQuery("/%00/");
         
         String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
@@ -77,7 +77,7 @@
     {
         _rule.setCode("405");
         _rule.setReason("foo");
-        _request.setRequestURI("/jsp/bean1.jsp%00");
+        _request.setURIPathQuery("/jsp/bean1.jsp%00");
         
         String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
@@ -91,7 +91,7 @@
     {
         _rule.setCode("405");
         _rule.setReason("foo");
-        _request.setRequestURI("/jsp/shamrock-%00%E2%98%98.jsp");
+        _request.setURIPathQuery("/jsp/shamrock-%00%E2%98%98.jsp");
         
         String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
@@ -105,7 +105,7 @@
     {
         _rule.setCode("405");
         _rule.setReason("foo");
-        _request.setRequestURI("/jsp/shamrock-%E2%98%98.jsp");
+        _request.setURIPathQuery("/jsp/shamrock-%E2%98%98.jsp");
         
         String result = _rule.matchAndApply(_request.getRequestURI(), _request, _response);
 
diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java
index adfbbb9..6bff15b 100644
--- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java
+++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/VirtualHostRuleContainerTest.java
@@ -49,7 +49,7 @@
         _fooContainerRule.setRules(new Rule[] { _fooRule });
 
         start(false);
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         
         _handler.setServer(_server);
         _handler.start();
@@ -58,7 +58,7 @@
     @Test
     public void testArbitraryHost() throws Exception
     {
-        _request.setServerName("cheese.com");
+        _request.setAuthority("cheese.com",0);
         _handler.setRules(new Rule[] { _rule, _fooContainerRule });
         handleRequest();
         assertEquals("{_rule, _fooContainerRule, Host: cheese.com}: applied _rule", "/rule/bar", _request.getRequestURI());
@@ -67,7 +67,7 @@
     @Test
     public void testVirtualHost() throws Exception
     {
-        _request.setServerName("foo.com");
+        _request.setAuthority("foo.com",0);
         _handler.setRules(new Rule[] { _fooContainerRule });
         handleRequest();
         assertEquals("{_fooContainerRule, Host: foo.com}: applied _fooRule", "/cheese/fooRule", _request.getRequestURI());
@@ -76,8 +76,8 @@
     @Test
     public void testCascadingRules() throws Exception
     {
-        _request.setServerName("foo.com");
-        _request.setRequestURI("/cheese/bar");
+        _request.setAuthority("foo.com",0);
+        _request.setURIPathQuery("/cheese/bar");
 
         _rule.setTerminating(false);
         _fooRule.setTerminating(false);
@@ -87,17 +87,17 @@
         handleRequest();
         assertEquals("{_rule, _fooContainerRule}: applied _rule, didn't match _fooRule", "/rule/bar", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _handler.setRules(new Rule[] { _fooContainerRule, _rule });
         handleRequest();
         assertEquals("{_fooContainerRule, _rule}: applied _fooRule, _rule","/rule/fooRule", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _fooRule.setTerminating(true);
         handleRequest();
         assertEquals("{_fooContainerRule, _rule}: (_fooRule is terminating); applied _fooRule, _rule", "/rule/fooRule", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _fooRule.setTerminating(false);
         _fooContainerRule.setTerminating(true);
         handleRequest();
@@ -107,7 +107,7 @@
     @Test
     public void testCaseInsensitiveHostname() throws Exception
     {
-        _request.setServerName("Foo.com");
+        _request.setAuthority("Foo.com",0);
         _fooContainerRule.setVirtualHosts(new String[] {"foo.com"} );
 
         _handler.setRules(new Rule[]{ _fooContainerRule });
@@ -118,21 +118,21 @@
     @Test
     public void testEmptyVirtualHost() throws Exception
     {
-        _request.setServerName("cheese.com");
+        _request.setAuthority("cheese.com",0);
 
         _handler.setRules(new Rule[] { _fooContainerRule });
         _fooContainerRule.setVirtualHosts(null);
         handleRequest();
         assertEquals("{_fooContainerRule: virtual hosts array is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _fooContainerRule.setVirtualHosts(new String[] {});
         handleRequest();
         assertEquals("{_fooContainerRule: virtual hosts array is empty, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _fooContainerRule.setVirtualHosts(new String[] {null});
         handleRequest();
         assertEquals("{_fooContainerRule: virtual host is null, Host: cheese.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI());
@@ -142,14 +142,14 @@
     @Test
     public void testMultipleVirtualHosts() throws Exception
     {
-        _request.setServerName("foo.com");
+        _request.setAuthority("foo.com",0);
         _handler.setRules(new Rule[] {_fooContainerRule });
 
         _fooContainerRule.setVirtualHosts(new String[]{ "cheese.com" });
         handleRequest();
         assertEquals("{_fooContainerRule: vhosts[cheese.com], Host: foo.com}: no effect", "/cheese/bar", _request.getRequestURI());
 
-        _request.setRequestURI("/cheese/bar");
+        _request.setURIPathQuery("/cheese/bar");
         _fooContainerRule.addVirtualHost( "foo.com" );
         handleRequest();
         assertEquals("{_fooContainerRule: vhosts[cheese.com, foo.com], Host: foo.com}: apply _fooRule", "/cheese/fooRule", _request.getRequestURI());
@@ -182,8 +182,8 @@
 
         for(String host: requestHosts)
         {
-            _request.setServerName(host);
-            _request.setRequestURI("/cheese/bar");
+            _request.setAuthority(host,0);
+            _request.setURIPathQuery("/cheese/bar");
             handleRequest();
             if(succeed)
                 assertEquals("{_fooContainerRule, Host: "+host+"}: should apply _fooRule", "/cheese/fooRule", _request.getRequestURI());
diff --git a/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml b/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
index b54d24f..9ac5109 100644
--- a/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
+++ b/jetty-rewrite/src/test/resources/org.mortbay.jetty.rewrite.handler/jetty-rewrite.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the Jetty Server                                      -->
@@ -39,12 +39,9 @@
     <Call name="addConnector">
       <Arg>
           <New class="org.eclipse.jetty.server.ServerConnector">
-            <Set name="host"><SystemProperty name="jetty.host" /></Set>
-            <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
+            <Set name="host"><SystemProperty name="jetty.http.host" /></Set>
+            <Set name="port"><SystemProperty name="jetty.http.port" default="8080"/></Set>
             <Set name="idleTimeout">30000</Set>
-            <Set name="Acceptors">2</Set>
-            <Set name="statsOn">false</Set>
-            <Set name="confidentialPort">8443</Set>
           </New>
       </Arg>
     </Call>
@@ -259,7 +256,7 @@
     <Ref refid="RequestLog">
       <Set name="requestLog">
         <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
-          <Set name="filename"><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
+          <Set name="filename"><SystemProperty name="jetty.requestlog.dir" default="./logs"/>/yyyy_mm_dd.request.log</Set>
           <Set name="filenameDateFormat">yyyy_MM_dd</Set>
           <Set name="retainDays">90</Set>
           <Set name="append">true</Set>
diff --git a/jetty-rhttp/README.TXT b/jetty-rhttp/README.TXT
deleted file mode 100644
index 46ca4e7..0000000
--- a/jetty-rhttp/README.TXT
+++ /dev/null
@@ -1,33 +0,0 @@
-Reverse HTTP
-
-The HTTP server paradigm is a valuable abstraction for browsing and accessing data and applications in a RESTful fashion from thin clients or
-other applications.  However, when it comes to mobile devices, the server paradigm is often not available because those devices exist on
-restricted networks that do not allow inbound connections.    These devices (eg. phones, tablets, industrial controllers, etc.) often have
-signficant content (eg. photos, video, music, contacts, etc.) and services (eg. GPS, phone, modem, camera, sound) that are worthwile to access
-remotely and often the HTTP server model is very applicable.
-
-The Jetty reverse HTTP module provides a gateway that efficiently allows HTTP connectivety to servers running in outbound-only networks.  There are two key components:
-
-The reverse HTTP connector is a jetty connector (like the HTTP, SSL, AJP connectors) that accepts HTTP requests for the Jetty server instance.  However, the reverse HTTP connector does not accept inbound TCP/IP connections.  Instead it makes an outbound HTTP connection to the reverse HTTP gateway and uses a long polling mechanism to efficiently and asynchronously fetch requests and send responses.
-
-The reverse HTTP gateway is a jetty server that accepts inbound connections from one or more Reverse HTTP connectors and makes them available as normal HTTP targets.
-
-To demonstrate this from a source release, first run a gateway instance:
-
-    cd jetty-reverse-http/reverse-http-gateway
-    mvn exec:java
-
-In another window, you can run 3 test servers with reverse connectors with:
-
-    cd jetty-reverse-http/reverse-http-connector
-    mvn exec:java
-
-
-The three servers are using context path ID's at the gateway (virtual host and cookie based mappings can also be done), so you can access the
-three servers via the gateway at:
-
-    http://localhost:8080/gw/A
-    http://localhost:8080/gw/B
-    http://localhost:8080/gw/C
-
-
diff --git a/jetty-rhttp/jetty-rhttp-client/pom.xml b/jetty-rhttp/jetty-rhttp-client/pom.xml
deleted file mode 100644
index 14dc5b3..0000000
--- a/jetty-rhttp/jetty-rhttp-client/pom.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.rhttp</groupId>
-        <artifactId>jetty-rhttp-project</artifactId>
-        <version>9.0.0-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>reverse-http-client</artifactId>
-    <packaging>jar</packaging>
-    <name>Jetty :: Reverse HTTP :: Client</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.rhttp.client</bundle-symbolic-name>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                 <Import-Package>*</Import-Package>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-            <plugin>
-              <!--
-              Required for OSGI
-              -->
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-jar-plugin</artifactId>
-              <configuration>
-                  <archive>
-                      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-                  </archive>
-              </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-util</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-io</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-http</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-            <version>4.0</version>
-        </dependency>
-        <dependency>
-            <groupId>net.jcip</groupId>
-            <artifactId>jcip-annotations</artifactId>
-            <version>1.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-          <groupId>org.eclipse.jetty.toolchain</groupId>
-          <artifactId>jetty-test-helper</artifactId>
-          <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/AbstractClient.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/AbstractClient.java
deleted file mode 100644
index afabf37..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/AbstractClient.java
+++ /dev/null
@@ -1,270 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.eclipse.jetty.util.component.AbstractLifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * @version $Revision$ $Date$
- */
-public abstract class AbstractClient extends AbstractLifeCycle implements RHTTPClient
-{
-    private final Logger logger = Log.getLogger("org.mortbay.jetty.rhttp.client");
-    private final List<RHTTPListener> listeners = new CopyOnWriteArrayList<RHTTPListener>();
-    private final List<ClientListener> clientListeners = new CopyOnWriteArrayList<ClientListener>();
-    private final String targetId;
-    private volatile Status status = Status.DISCONNECTED;
-
-    public AbstractClient(String targetId)
-    {
-        this.targetId = targetId;
-    }
-
-    public String getGatewayURI()
-    {
-        return "http://"+getHost()+":"+getPort()+getPath();
-    }
-
-    public String getTargetId()
-    {
-        return targetId;
-    }
-
-    public Logger getLogger()
-    {
-        return logger;
-    }
-
-    public void addListener(RHTTPListener listener)
-    {
-        listeners.add(listener);
-    }
-
-    public void removeListener(RHTTPListener listener)
-    {
-        listeners.remove(listener);
-    }
-
-    public void addClientListener(ClientListener listener)
-    {
-        clientListeners.add(listener);
-    }
-
-    public void removeClientListener(ClientListener listener)
-    {
-        clientListeners.remove(listener);
-    }
-
-    protected void notifyRequests(List<RHTTPRequest> requests)
-    {
-        for (RHTTPRequest request : requests)
-        {
-            for (RHTTPListener listener : listeners)
-            {
-                try
-                {
-                    listener.onRequest(request);
-                }
-                catch (Throwable x)
-                {
-                    logger.warn("Listener " + listener + " threw", x);
-                    try
-                    {
-                        deliver(newExceptionResponse(request.getId(), x));
-                    }
-                    catch (IOException xx)
-                    {
-                        logger.debug("Could not deliver exception response", xx);
-                    }
-                }
-            }
-        }
-    }
-
-    protected RHTTPResponse newExceptionResponse(int requestId, Throwable x)
-    {
-        try
-        {
-            int statusCode = 500;
-            String statusMessage = "Internal Server Error";
-            Map<String, String> headers = new HashMap<String, String>();
-            byte[] body = x.toString().getBytes("UTF-8");
-            return new RHTTPResponse(requestId, statusCode, statusMessage, headers, body);
-        }
-        catch (UnsupportedEncodingException xx)
-        {
-            throw new AssertionError(xx);
-        }
-    }
-
-    protected void notifyConnectRequired()
-    {
-        for (ClientListener listener : clientListeners)
-        {
-            try
-            {
-                listener.connectRequired();
-            }
-            catch (Throwable x)
-            {
-                logger.warn("ClientListener " + listener + " threw", x);
-            }
-        }
-    }
-
-    protected void notifyConnectException()
-    {
-        for (ClientListener listener : clientListeners)
-        {
-            try
-            {
-                listener.connectException();
-            }
-            catch (Throwable x)
-            {
-                logger.warn("ClientListener " + listener + " threw", x);
-            }
-        }
-    }
-
-    protected void notifyConnectClosed()
-    {
-        for (ClientListener listener : clientListeners)
-        {
-            try
-            {
-                listener.connectClosed();
-            }
-            catch (Throwable xx)
-            {
-                logger.warn("ClientListener " + listener + " threw", xx);
-            }
-        }
-    }
-
-    protected void notifyDeliverException(RHTTPResponse response)
-    {
-        for (ClientListener listener : clientListeners)
-        {
-            try
-            {
-                listener.deliverException(response);
-            }
-            catch (Throwable x)
-            {
-                logger.warn("ClientListener " + listener + " threw", x);
-            }
-        }
-    }
-
-    protected String urlEncode(String value)
-    {
-        try
-        {
-            return URLEncoder.encode(value, "UTF-8");
-        }
-        catch (UnsupportedEncodingException x)
-        {
-            getLogger().debug("", x);
-            return null;
-        }
-    }
-
-    protected boolean isConnected()
-    {
-        return status == Status.CONNECTED;
-    }
-
-    protected boolean isDisconnecting()
-    {
-        return status == Status.DISCONNECTING;
-    }
-
-    protected boolean isDisconnected()
-    {
-        return status == Status.DISCONNECTED;
-    }
-
-    public void connect() throws IOException
-    {
-        if (isDisconnected())
-            status = Status.CONNECTING;
-
-        syncHandshake();
-        this.status = Status.CONNECTED;
-
-        asyncConnect();
-    }
-
-    public void disconnect() throws IOException
-    {
-        if (isConnected())
-        {
-            status = Status.DISCONNECTING;
-            try
-            {
-                syncDisconnect();
-            }
-            finally
-            {
-                status = Status.DISCONNECTED;
-            }
-        }
-    }
-
-    public void deliver(RHTTPResponse response) throws IOException
-    {
-        asyncDeliver(response);
-    }
-
-    protected abstract void syncHandshake() throws IOException;
-
-    protected abstract void asyncConnect();
-
-    protected abstract void syncDisconnect() throws IOException;
-
-    protected abstract void asyncDeliver(RHTTPResponse response);
-
-    protected void connectComplete(byte[] responseContent) throws IOException
-    {
-        List<RHTTPRequest> requests = RHTTPRequest.fromFrameBytes(responseContent);
-        getLogger().debug("Client {} connect returned from gateway, requests {}", getTargetId(), requests);
-
-        // Requests are arrived, reconnect while we process them
-        if (!isDisconnecting() && !isDisconnected())
-            asyncConnect();
-
-        notifyRequests(requests);
-    }
-
-    protected enum Status
-    {
-        CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ApacheClient.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ApacheClient.java
deleted file mode 100644
index f55b8cb..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ApacheClient.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.NoHttpResponseException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.util.EntityUtils;
-
-/**
- * Implementation of {@link RHTTPClient} that uses Apache's HttpClient.
- *
- * @version $Revision$ $Date$
- */
-public class ApacheClient extends AbstractClient
-{
-    private final HttpClient httpClient;
-    private final String gatewayPath;
-
-    public ApacheClient(HttpClient httpClient, String gatewayPath, String targetId)
-    {
-        super(targetId);
-        this.httpClient = httpClient;
-        this.gatewayPath = gatewayPath;
-    }
-
-    public String getHost()
-    {
-        return ((HttpHost)httpClient.getParams().getParameter("http.default-host")).getHostName();
-    }
-
-    public int getPort()
-    {
-        return ((HttpHost)httpClient.getParams().getParameter("http.default-host")).getPort();
-    }
-    
-    public String getPath()
-    {
-        return gatewayPath;
-    }
-
-    protected void syncHandshake() throws IOException
-    {
-        HttpPost handshake = new HttpPost(gatewayPath + "/" + urlEncode(getTargetId()) + "/handshake");
-        HttpResponse response = httpClient.execute(handshake);
-        int statusCode = response.getStatusLine().getStatusCode();
-        HttpEntity entity = response.getEntity();
-        if (entity != null)
-            entity.consumeContent();
-        if (statusCode != HttpStatus.SC_OK)
-            throw new IOException("Handshake failed");
-        getLogger().debug("Client {} handshake returned from gateway", getTargetId(), null);
-    }
-
-    protected void asyncConnect()
-    {
-        new Thread()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    HttpPost connect = new HttpPost(gatewayPath + "/" + urlEncode(getTargetId()) + "/connect");
-                    getLogger().debug("Client {} connect sent to gateway", getTargetId(), null);
-                    HttpResponse response = httpClient.execute(connect);
-                    int statusCode = response.getStatusLine().getStatusCode();
-                    HttpEntity entity = response.getEntity();
-                    byte[] responseContent = EntityUtils.toByteArray(entity);
-                    if (statusCode == HttpStatus.SC_OK)
-                        connectComplete(responseContent);
-                    else if (statusCode == HttpStatus.SC_UNAUTHORIZED)
-                        notifyConnectRequired();
-                    else
-                        notifyConnectException();
-                }
-                catch (NoHttpResponseException x)
-                {
-                    notifyConnectClosed();
-                }
-                catch (IOException x)
-                {
-                    getLogger().debug("", x);
-                    notifyConnectException();
-                }
-            }
-        }.start();
-    }
-
-    protected void syncDisconnect() throws IOException
-    {
-        HttpPost disconnect = new HttpPost(gatewayPath + "/" + urlEncode(getTargetId()) + "/disconnect");
-        HttpResponse response = httpClient.execute(disconnect);
-        int statusCode = response.getStatusLine().getStatusCode();
-        HttpEntity entity = response.getEntity();
-        if (entity != null)
-            entity.consumeContent();
-        if (statusCode != HttpStatus.SC_OK)
-            throw new IOException("Disconnect failed");
-        getLogger().debug("Client {} disconnect returned from gateway", getTargetId(), null);
-    }
-
-    protected void asyncDeliver(final RHTTPResponse response)
-    {
-        new Thread()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    HttpPost deliver = new HttpPost(gatewayPath + "/" + urlEncode(getTargetId()) + "/deliver");
-                    deliver.setEntity(new ByteArrayEntity(response.getFrameBytes()));
-                    getLogger().debug("Client {} deliver sent to gateway, response {}", getTargetId(), response);
-                    HttpResponse httpResponse = httpClient.execute(deliver);
-                    int statusCode = httpResponse.getStatusLine().getStatusCode();
-                    HttpEntity entity = httpResponse.getEntity();
-                    if (entity != null)
-                        entity.consumeContent();
-                    if (statusCode == HttpStatus.SC_UNAUTHORIZED)
-                        notifyConnectRequired();
-                    else if (statusCode != HttpStatus.SC_OK)
-                        notifyDeliverException(response);
-                }
-                catch (IOException x)
-                {
-                    getLogger().debug("", x);
-                    notifyDeliverException(response);
-                }
-            }
-        }.start();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ClientListener.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ClientListener.java
deleted file mode 100644
index bbdac17..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/ClientListener.java
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-/**
- * A listener for network-related events happening on the gateway client.
- *
- * @version $Revision$ $Date$
- */
-public interface ClientListener
-{
-    /**
-     * Called when the client detects that the server requested a new connect.
-     */
-    public void connectRequired();
-
-    /**
-     * Called when the client detects that the connection has been closed by the server.
-     */
-    public void connectClosed();
-
-    /**
-     * Called when the client detects a generic exception while trying to connect to the server.
-     */
-    public void connectException();
-
-    /**
-     * Called when the client detects a generic exception while tryint to deliver to the server.
-     * @param response the Response object that should have been sent to the server
-     */
-    public void deliverException(RHTTPResponse response);
-
-    public static class Adapter implements ClientListener
-    {
-        public void connectRequired()
-        {
-        }
-
-        public void connectClosed()
-        {
-        }
-
-        public void connectException()
-        {
-        }
-
-        public void deliverException(RHTTPResponse response)
-        {
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/JettyClient.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/JettyClient.java
deleted file mode 100644
index 6407efa..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/JettyClient.java
+++ /dev/null
@@ -1,306 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.http.HttpURI;
-import org.eclipse.jetty.io.Buffer;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.io.EofException;
-
-/**
- * Implementation of {@link RHTTPClient} that uses Jetty's HttpClient.
- *
- * @version $Revision$ $Date$
- */
-public class JettyClient extends AbstractClient
-{
-    private final HttpClient httpClient;
-    private final Address gatewayAddress;
-    private final String gatewayPath;
-
-    public JettyClient(HttpClient httpClient, Address gatewayAddress, String gatewayPath, String targetId)
-    {
-        super(targetId);
-        this.httpClient = httpClient;
-        this.gatewayAddress = gatewayAddress;
-        this.gatewayPath = gatewayPath;
-    }
-    
-    public JettyClient(HttpClient httpClient, String gatewayURI, String targetId)
-    {
-        super(targetId);
-        
-        HttpURI uri = new HttpURI(gatewayURI);
-        
-        this.httpClient = httpClient;
-        this.gatewayAddress = new Address(uri.getHost(),uri.getPort());
-        this.gatewayPath = uri.getPath();
-    }
-    
-    public String getHost()
-    {
-        return gatewayAddress.getHost();
-    }
-
-    public int getPort()
-    {
-        return gatewayAddress.getPort();
-    }
-
-    public String getPath()
-    {
-        return gatewayPath;
-    }
-    
-    @Override
-    protected void doStart() throws Exception
-    {
-        httpClient.start();
-        super.doStart();
-    }
-
-    @Override
-    protected void doStop() throws Exception
-    {
-        super.doStop();
-        httpClient.stop();
-    }
-
-    protected void syncHandshake() throws IOException
-    {
-        HandshakeExchange exchange = new HandshakeExchange();
-        exchange.setMethod(HttpMethods.POST);
-        exchange.setAddress(gatewayAddress);
-        exchange.setURI(gatewayPath + "/" + urlEncode(getTargetId()) + "/handshake");
-        httpClient.send(exchange);
-        getLogger().debug("Client {} handshake sent to gateway", getTargetId(), null);
-
-        try
-        {
-            int exchangeStatus = exchange.waitForDone();
-            if (exchangeStatus != HttpExchange.STATUS_COMPLETED)
-                throw new IOException("Handshake failed");
-            if (exchange.getResponseStatus() != 200)
-                throw new IOException("Handshake failed");
-            getLogger().debug("Client {} handshake returned from gateway", getTargetId(), null);
-        }
-        catch (InterruptedException x)
-        {
-            Thread.currentThread().interrupt();
-            throw newIOException(x);
-        }
-    }
-
-    private IOException newIOException(Throwable x)
-    {
-        return (IOException)new IOException().initCause(x);
-    }
-
-    protected void asyncConnect()
-    {
-        try
-        {
-            ConnectExchange exchange = new ConnectExchange();
-            exchange.setMethod(HttpMethods.POST);
-            exchange.setAddress(gatewayAddress);
-            exchange.setURI(gatewayPath + "/" + urlEncode(getTargetId()) + "/connect");
-            httpClient.send(exchange);
-            getLogger().debug("Client {} connect sent to gateway", getTargetId(), null);
-        }
-        catch (IOException x)
-        {
-            getLogger().debug("Could not send exchange", x);
-            throw new RuntimeException(x);
-        }
-    }
-
-    protected void syncDisconnect() throws IOException
-    {
-        DisconnectExchange exchange = new DisconnectExchange();
-        exchange.setMethod(HttpMethods.POST);
-        exchange.setAddress(gatewayAddress);
-        exchange.setURI(gatewayPath + "/" + urlEncode(getTargetId()) + "/disconnect");
-        httpClient.send(exchange);
-        getLogger().debug("Client {} disconnect sent to gateway", getTargetId(), null);
-        try
-        {
-            int status = exchange.waitForDone();
-            if (status != HttpExchange.STATUS_COMPLETED)
-                throw new IOException("Disconnect failed");
-            if (exchange.getResponseStatus() != 200)
-                throw new IOException("Disconnect failed");
-            getLogger().debug("Client {} disconnect returned from gateway", getTargetId(), null);
-        }
-        catch (InterruptedException x)
-        {
-            Thread.currentThread().interrupt();
-            throw newIOException(x);
-        }
-    }
-
-    protected void asyncDeliver(RHTTPResponse response)
-    {
-        try
-        {
-            DeliverExchange exchange = new DeliverExchange(response);
-            exchange.setMethod(HttpMethods.POST);
-            exchange.setAddress(gatewayAddress);
-            exchange.setURI(gatewayPath + "/" + urlEncode(getTargetId()) + "/deliver");
-            exchange.setRequestContent(new ByteArrayBuffer(response.getFrameBytes()));
-            httpClient.send(exchange);
-            getLogger().debug("Client {} deliver sent to gateway, response {}", getTargetId(), response);
-        }
-        catch (IOException x)
-        {
-            getLogger().debug("Could not send exchange", x);
-            throw new RuntimeException(x);
-        }
-    }
-
-    protected class HandshakeExchange extends ContentExchange
-    {
-        protected HandshakeExchange()
-        {
-            super(true);
-        }
-        
-        @Override
-        protected void onConnectionFailed(Throwable x)
-        {
-            getLogger().warn(x.toString());
-            getLogger().debug(x);
-        }
-    }
-
-    protected class ConnectExchange extends ContentExchange
-    {
-        private final ByteArrayOutputStream content = new ByteArrayOutputStream();
-
-        protected ConnectExchange()
-        {
-            super(true);
-        }
-
-        @Override
-        protected void onResponseContent(Buffer buffer) throws IOException
-        {
-            buffer.writeTo(content);
-        }
-
-        @Override
-        protected void onResponseComplete()
-        {
-            int responseStatus = getResponseStatus();
-            if (responseStatus == 200)
-            {
-                try
-                {
-                    connectComplete(content.toByteArray());
-                }
-                catch (IOException x)
-                {
-                    onException(x);
-                }
-            }
-            else if (responseStatus == 401)
-            {
-                notifyConnectRequired();
-            }
-            else
-            {
-                notifyConnectException();
-            }
-        }
-
-        @Override
-        protected void onException(Throwable x)
-        {
-            getLogger().debug(x);
-            if (x instanceof EofException || x instanceof EOFException)
-            {
-                notifyConnectClosed();
-            }
-            else
-            {
-                notifyConnectException();
-            }
-        }
-        
-        @Override
-        protected void onConnectionFailed(Throwable x)
-        {
-            getLogger().debug(x);
-        }
-    }
-
-    protected class DisconnectExchange extends ContentExchange
-    {
-        protected DisconnectExchange()
-        {
-            super(true);
-        }
-    }
-
-    protected class DeliverExchange extends ContentExchange
-    {
-        private final RHTTPResponse response;
-
-        protected DeliverExchange(RHTTPResponse response)
-        {
-            super(true);
-            this.response = response;
-        }
-
-        @Override
-        protected void onResponseComplete() throws IOException
-        {
-            int responseStatus = getResponseStatus();
-            if (responseStatus == 401)
-            {
-                notifyConnectRequired();
-            }
-            else if (responseStatus != 200)
-            {
-                notifyDeliverException(response);
-            }
-        }
-
-        @Override
-        protected void onException(Throwable x)
-        {
-            getLogger().debug(x);
-            notifyDeliverException(response);
-        }
-
-        @Override
-        protected void onConnectionFailed(Throwable x)
-        {
-            getLogger().debug(x);
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPClient.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPClient.java
deleted file mode 100644
index c76bae5..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPClient.java
+++ /dev/null
@@ -1,133 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-
-/**
- * <p><tt>RHTTPClient</tt> represent a client of the gateway server.</p>
- * <p>A <tt>Client</tt> has a server side counterpart with which communicates
- * using a comet protocol.<br /> The <tt>Client</tt>, its server-side
- * counterpart and the comet protocol form the <em>Half-Object plus Protocol</em>
- * pattern.</p>
- * <p>A <tt>Client</tt> must first connect to the gateway server, to let the gateway
- * server know its targetId, an identifier that uniquely distinguish this
- * <tt>Client</tt> from other <tt>Client</tt>s.</p>
- * <p>Once connected, the gateway server will use a comet procotol to notify the
- * <tt>Client</tt> of server-side events, and the <tt>Client</tt> can send
- * information to the gateway server to notify it of client-side events.</p>
- * <p>Server-side event are notified to {@link RHTTPListener}s, while relevant
- * network events are communicated to {@link ClientListener}s.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface RHTTPClient
-{
-    /**
-     * @return The gateway uri, typically "http://gatewayhost:gatewayport/gatewaypath".
-     */
-    public String getGatewayURI();
-    
-    /**
-     * @return The gateway host
-     */
-    public String getHost();
-    
-    /**
-     * @return The gateway port
-     */
-    public int getPort();
-    
-    /**
-     * @return The gateway path
-     */
-    public String getPath();
-    
-    /**
-     * @return the targetId that uniquely identifies this client.
-     */
-    public String getTargetId();
-
-    /**
-     * <p>Connects to the gateway server, establishing the long poll communication
-     * with the gateway server to be notified of server-side events.</p>
-     * <p>The connect is performed in two steps:
-     * <ul>
-     * <li>first, a connect message is sent to the gateway server; the gateway server
-     * will notice this is a first connect message and reply immediately with
-     * an empty response</li>
-     * <li>second, another connect message is sent to the gateway server which interprets
-     * it as a long poll request</li>
-     * </ul>
-     * The long poll request may return either because one or more server-side events
-     * happened, or because it expired. </p>
-     * <p>Any connect message after the first is treated as a long poll request.</p>
-     *
-     * @throws IOException if it is not possible to connect to the gateway server
-     * @see #disconnect()
-     */
-    public void connect() throws IOException;
-
-    /**
-     * <p>Disconnects from the gateway server.</p>
-     * <p>Just after the disconnect request is processed by to the gateway server, it will
-     * return the currently outstanding long poll request.</p>
-     * <p>If this client is not connected, it does nothing</p>
-     *
-     * @throws IOException if it is not possible to contact the gateway server to disconnect
-     * @see #connect()
-     */
-    public void disconnect() throws IOException;
-
-    /**
-     * <p>Sends a response to the gateway server.</p>
-     *
-     * @param response the response to send
-     * @throws IOException if it is not possible to contact the gateway server
-     */
-    public void deliver(RHTTPResponse response) throws IOException;
-
-    /**
-     * <p>Adds the given listener to this client.</p>
-     * @param listener the listener to add
-     * @see #removeListener(RHTTPListener)
-     */
-    public void addListener(RHTTPListener listener);
-
-    /**
-     * <p>Removes the given listener from this client.</p>
-     * @param listener the listener to remove
-     * @see #addListener(RHTTPListener)
-     */
-    public void removeListener(RHTTPListener listener);
-
-    /**
-     * <p>Adds the given client listener to this client.</p>
-     * @param listener the client listener to add
-     * @see #removeClientListener(ClientListener)
-     */
-    public void addClientListener(ClientListener listener);
-
-    /**
-     * <p>Removes the given client listener from this client.</p>
-     * @param listener the client listener to remove
-     * @see #addClientListener(ClientListener)
-     */
-    public void removeClientListener(ClientListener listener);
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPListener.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPListener.java
deleted file mode 100644
index f84f735..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPListener.java
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-/**
- * <p>Implementations of this class listen for requests arriving from the gateway server
- * and notified by {@link RHTTPClient}.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface RHTTPListener
-{
-    /**
-     * Callback method called by {@link RHTTPClient} to inform that the gateway server
-     * sent a request to the gateway client.
-     * @param request the request sent by the gateway server.
-     * @throws Exception allowed to be thrown by implementations
-     */
-    public void onRequest(RHTTPRequest request) throws Exception;
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPRequest.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPRequest.java
deleted file mode 100644
index 7d24961..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPRequest.java
+++ /dev/null
@@ -1,266 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.jetty.http.HttpParser;
-import org.eclipse.jetty.io.Buffer;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-
-/**
- * <p>Represents the external request information that is carried over the comet protocol.</p>
- * <p>Instances of this class are converted into an opaque byte array of the form:</p>
- * <pre>
- * &lt;request-id&gt; SPACE &lt;request-length&gt; CRLF
- * &lt;external-request&gt;
- * </pre>
- * <p>The byte array form is carried as body of a normal HTTP response returned by the gateway server
- * to the gateway client.</p>
- * @see RHTTPResponse
- * @version $Revision$ $Date$
- */
-public class RHTTPRequest
-{
-    private static final String CRLF = "\r\n";
-    private static final byte[] CRLF_BYTES = CRLF.getBytes();
-
-    private final int id;
-    private final byte[] requestBytes;
-    private final byte[] frameBytes;
-    private volatile String method;
-    private volatile String uri;
-    private volatile Map<String, String> headers;
-    private volatile byte[] body;
-
-    public static List<RHTTPRequest> fromFrameBytes(byte[] bytes)
-    {
-        List<RHTTPRequest> result = new ArrayList<RHTTPRequest>();
-        int start = 0;
-        while (start < bytes.length)
-        {
-            // Scan until we find the space
-            int end = start;
-            while (bytes[end] != ' ') ++end;
-            int requestId = Integer.parseInt(new String(bytes, start, end - start));
-            start = end + 1;
-
-            // Scan until end of line
-            while (bytes[end] != '\n') ++end;
-            int length = Integer.parseInt(new String(bytes, start, end - start - 1));
-            start = end + 1;
-
-            byte[] requestBytes = new byte[length];
-            System.arraycopy(bytes, start, requestBytes, 0, length);
-            RHTTPRequest request = fromRequestBytes(requestId, requestBytes);
-            result.add(request);
-            start += length;
-        }
-        return result;
-    }
-
-    public static RHTTPRequest fromRequestBytes(int requestId, byte[] requestBytes)
-    {
-        return new RHTTPRequest(requestId, requestBytes);
-    }
-
-    public RHTTPRequest(int id, String method, String uri, Map<String, String> headers, byte[] body)
-    {
-        this.id = id;
-        this.method = method;
-        this.uri = uri;
-        this.headers = headers;
-        this.body = body;
-        this.requestBytes = toRequestBytes();
-        this.frameBytes = toFrameBytes(requestBytes);
-    }
-
-    private RHTTPRequest(int id, byte[] requestBytes)
-    {
-        this.id = id;
-        this.requestBytes = requestBytes;
-        this.frameBytes = toFrameBytes(requestBytes);
-        // Other fields are lazily initialized
-    }
-
-    private void initialize()
-    {
-        try
-        {
-            final ByteArrayOutputStream body = new ByteArrayOutputStream();
-            HttpParser parser = new HttpParser(new ByteArrayBuffer(requestBytes), new HttpParser.EventHandler()
-            {
-                @Override
-                public void startRequest(Buffer method, Buffer uri, Buffer httpVersion) throws IOException
-                {
-                    RHTTPRequest.this.method = method.toString("UTF-8");
-                    RHTTPRequest.this.uri = uri.toString("UTF-8");
-                    RHTTPRequest.this.headers = new LinkedHashMap<String, String>();
-                }
-
-                @Override
-                public void startResponse(Buffer httpVersion, int statusCode, Buffer statusMessage) throws IOException
-                {
-                }
-
-                @Override
-                public void parsedHeader(Buffer name, Buffer value) throws IOException
-                {
-                    RHTTPRequest.this.headers.put(name.toString("UTF-8"), value.toString("UTF-8"));
-                }
-
-                @Override
-                public void content(Buffer content) throws IOException
-                {
-                    content.writeTo(body);
-                }
-            });
-            parser.parse();
-            this.body = body.toByteArray();
-        }
-        catch (IOException x)
-        {
-            // Cannot happen: we're parsing from a byte[], not from an I/O stream
-            throw new AssertionError(x);
-        }
-    }
-
-    public int getId()
-    {
-        return id;
-    }
-
-    public byte[] getRequestBytes()
-    {
-        return requestBytes;
-    }
-
-    public byte[] getFrameBytes()
-    {
-        return frameBytes;
-    }
-
-    public String getMethod()
-    {
-        if (method == null)
-            initialize();
-        return method;
-    }
-
-    public String getURI()
-    {
-        if (uri == null)
-            initialize();
-        return uri;
-    }
-
-    public Map<String, String> getHeaders()
-    {
-        if (headers == null)
-            initialize();
-        return headers;
-    }
-
-    public byte[] getBody()
-    {
-        if (body == null)
-            initialize();
-        return body;
-    }
-
-    private byte[] toRequestBytes()
-    {
-        try
-        {
-            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-            bytes.write(method.getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write(uri.getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write("HTTP/1.1".getBytes("UTF-8"));
-            bytes.write(CRLF_BYTES);
-            for (Map.Entry<String, String> entry : headers.entrySet())
-            {
-                bytes.write(entry.getKey().getBytes("UTF-8"));
-                bytes.write(':');
-                bytes.write(' ');
-                bytes.write(entry.getValue().getBytes("UTF-8"));
-                bytes.write(CRLF_BYTES);
-            }
-            bytes.write(CRLF_BYTES);
-            bytes.write(body);
-            bytes.close();
-            return bytes.toByteArray();
-        }
-        catch (IOException x)
-        {
-            throw new AssertionError(x);
-        }
-    }
-
-    private byte[] toFrameBytes(byte[] requestBytes)
-    {
-        try
-        {
-            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-            bytes.write(String.valueOf(id).getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write(String.valueOf(requestBytes.length).getBytes("UTF-8"));
-            bytes.write(CRLF_BYTES);
-            bytes.write(requestBytes);
-            bytes.close();
-            return bytes.toByteArray();
-        }
-        catch (IOException x)
-        {
-            throw new AssertionError(x);
-        }
-    }
-
-    @Override
-    public String toString()
-    {
-        // Use fields to avoid initialization
-        StringBuilder builder = new StringBuilder();
-        builder.append(id).append(" ");
-        builder.append(method).append(" ");
-        builder.append(uri).append(" ");
-        builder.append(requestBytes.length).append("/");
-        builder.append(frameBytes.length);
-        return builder.toString();
-    }
-
-    public String toLongString()
-    {
-        // Use getters to trigger initialization
-        StringBuilder builder = new StringBuilder();
-        builder.append(id).append(" ");
-        builder.append(getMethod()).append(" ");
-        builder.append(getURI()).append(CRLF);
-        for (Map.Entry<String, String> header : getHeaders().entrySet())
-            builder.append(header.getKey()).append(": ").append(header.getValue()).append(CRLF);
-        builder.append(getBody().length).append(" body bytes").append(CRLF);
-        return builder.toString();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPResponse.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPResponse.java
deleted file mode 100644
index 82d347f..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RHTTPResponse.java
+++ /dev/null
@@ -1,256 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.eclipse.jetty.http.HttpParser;
-import org.eclipse.jetty.io.Buffer;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-
-/**
- * <p>Represents the resource provider response information that is carried over the comet protocol.</p>
- * <p>Instances of this class are converted into an opaque byte array of the form:</p>
- * <pre>
- * &lt;request-id&gt; SPACE &lt;response-length&gt; CRLF
- * &lt;resource-response&gt;
- * </pre>
- * <p>The byte array form is carried as body of a normal HTTP request made by the gateway client to
- * the gateway server.</p>
- * @see RHTTPRequest
- * @version $Revision$ $Date$
- */
-public class RHTTPResponse
-{
-    private static final String CRLF = "\r\n";
-    private static final byte[] CRLF_BYTES = CRLF.getBytes();
-
-    private final int id;
-    private final byte[] responseBytes;
-    private final byte[] frameBytes;
-    private volatile int code;
-    private volatile String message;
-    private volatile Map<String, String> headers;
-    private volatile byte[] body;
-
-    public static RHTTPResponse fromFrameBytes(byte[] bytes)
-    {
-        int start = 0;
-        // Scan until we find the space
-        int end = start;
-        while (bytes[end] != ' ') ++end;
-        int responseId = Integer.parseInt(new String(bytes, start, end - start));
-        start = end + 1;
-
-        // Scan until end of line
-        while (bytes[end] != '\n') ++end;
-        int length = Integer.parseInt(new String(bytes, start, end - start - 1));
-        start = end + 1;
-
-        byte[] responseBytes = new byte[length];
-        System.arraycopy(bytes, start, responseBytes, 0, length);
-        return fromResponseBytes(responseId, responseBytes);
-    }
-
-    public static RHTTPResponse fromResponseBytes(int id, byte[] responseBytes)
-    {
-        return new RHTTPResponse(id, responseBytes);
-    }
-
-    public RHTTPResponse(int id, int code, String message, Map<String, String> headers, byte[] body)
-    {
-        this.id = id;
-        this.code = code;
-        this.message = message;
-        this.headers = headers;
-        this.body = body;
-        this.responseBytes = toResponseBytes();
-        this.frameBytes = toFrameBytes(responseBytes);
-    }
-
-    private RHTTPResponse(int id, byte[] responseBytes)
-    {
-        this.id = id;
-        this.responseBytes = responseBytes;
-        this.frameBytes = toFrameBytes(responseBytes);
-        // Other fields are lazily initialized
-    }
-
-    private void initialize()
-    {
-        try
-        {
-            final ByteArrayOutputStream body = new ByteArrayOutputStream();
-            HttpParser parser = new HttpParser(new ByteArrayBuffer(responseBytes), new HttpParser.EventHandler()
-            {
-                @Override
-                public void startRequest(Buffer method, Buffer uri, Buffer httpVersion) throws IOException
-                {
-                }
-
-                @Override
-                public void startResponse(Buffer httpVersion, int statusCode, Buffer statusMessage) throws IOException
-                {
-                    RHTTPResponse.this.code = statusCode;
-                    RHTTPResponse.this.message = statusMessage.toString("UTF-8");
-                    RHTTPResponse.this.headers = new LinkedHashMap<String, String>();
-                }
-
-                @Override
-                public void parsedHeader(Buffer name, Buffer value) throws IOException
-                {
-                    RHTTPResponse.this.headers.put(name.toString("UTF-8"), value.toString("UTF-8"));
-                }
-
-                @Override
-                public void content(Buffer content) throws IOException
-                {
-                    content.writeTo(body);
-                }
-            });
-            parser.parse();
-            this.body = body.toByteArray();
-        }
-        catch (IOException x)
-        {
-            // Cannot happen: we're parsing from a byte[], not from an I/O stream
-            throw new AssertionError(x);
-        }
-    }
-
-    public int getId()
-    {
-        return id;
-    }
-
-    public byte[] getResponseBytes()
-    {
-        return responseBytes;
-    }
-
-    public byte[] getFrameBytes()
-    {
-        return frameBytes;
-    }
-
-    public int getStatusCode()
-    {
-        if (code == 0)
-            initialize();
-        return code;
-    }
-
-    public String getStatusMessage()
-    {
-        if (message == null)
-            initialize();
-        return message;
-    }
-
-    public Map<String, String> getHeaders()
-    {
-        if (headers == null)
-            initialize();
-        return headers;
-    }
-
-    public byte[] getBody()
-    {
-        if (body == null)
-            initialize();
-        return body;
-    }
-
-    private byte[] toResponseBytes()
-    {
-        try
-        {
-            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-            bytes.write("HTTP/1.1".getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write(String.valueOf(code).getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write(message.getBytes("UTF-8"));
-            bytes.write(CRLF_BYTES);
-            for (Map.Entry<String, String> entry : headers.entrySet())
-            {
-                bytes.write(entry.getKey().getBytes("UTF-8"));
-                bytes.write(':');
-                bytes.write(' ');
-                bytes.write(entry.getValue().getBytes("UTF-8"));
-                bytes.write(CRLF_BYTES);
-            }
-            bytes.write(CRLF_BYTES);
-            bytes.write(body);
-            bytes.close();
-            return bytes.toByteArray();
-        }
-        catch (IOException x)
-        {
-            throw new AssertionError(x);
-        }
-    }
-
-    private byte[] toFrameBytes(byte[] responseBytes)
-    {
-        try
-        {
-            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-            bytes.write(String.valueOf(id).getBytes("UTF-8"));
-            bytes.write(' ');
-            bytes.write(String.valueOf(responseBytes.length).getBytes("UTF-8"));
-            bytes.write(CRLF_BYTES);
-            bytes.write(responseBytes);
-            return bytes.toByteArray();
-        }
-        catch (IOException x)
-        {
-            throw new AssertionError(x);
-        }
-    }
-
-    @Override
-    public String toString()
-    {
-        // Use fields to avoid initialization
-        StringBuilder builder = new StringBuilder();
-        builder.append(id).append(" ");
-        builder.append(code).append(" ");
-        builder.append(message).append(" ");
-        builder.append(responseBytes.length).append("/");
-        builder.append(frameBytes.length);
-        return builder.toString();
-    }
-
-    public String toLongString()
-    {
-        // Use getters to trigger initialization
-        StringBuilder builder = new StringBuilder();
-        builder.append(id).append(" ");
-        builder.append(getStatusCode()).append(" ");
-        builder.append(getStatusMessage()).append(CRLF);
-        for (Map.Entry<String, String> header : getHeaders().entrySet())
-            builder.append(header.getKey()).append(": ").append(header.getValue()).append(CRLF);
-        builder.append(getBody().length).append(" body bytes").append(CRLF);
-        return builder.toString();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RetryingApacheClient.java b/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RetryingApacheClient.java
deleted file mode 100644
index 04d8c6a..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/main/java/org/eclipse/jetty/rhttp/client/RetryingApacheClient.java
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-
-import org.apache.http.client.HttpClient;
-
-/**
- * @version $Revision$ $Date$
- */
-public class RetryingApacheClient extends ApacheClient
-{
-    public RetryingApacheClient(HttpClient httpClient, String gatewayURI, String targetId)
-    {
-        super(httpClient, gatewayURI, targetId);
-        addClientListener(new RetryClientListener());
-    }
-
-    @Override
-    protected void syncHandshake() throws IOException
-    {
-        while (true)
-        {
-            try
-            {
-                super.syncHandshake();
-                break;
-            }
-            catch (IOException x)
-            {
-                getLogger().debug("Handshake failed, backing off and retrying");
-                try
-                {
-                    Thread.sleep(1000);
-                }
-                catch (InterruptedException xx)
-                {
-                    throw (IOException)new IOException().initCause(xx);
-                }
-            }
-        }
-    }
-
-    private class RetryClientListener implements ClientListener
-    {
-        public void connectRequired()
-        {
-            getLogger().debug("Connect requested by server");
-            try
-            {
-                connect();
-            }
-            catch (IOException x)
-            {
-                // The connect() method is retried, so if it fails, it's a hard failure
-                getLogger().debug("Connect failed after server required connect, giving up");
-            }
-        }
-
-        public void connectClosed()
-        {
-            connectException();
-        }
-
-        public void connectException()
-        {
-            getLogger().debug("Connect failed, backing off and retrying");
-            try
-            {
-                Thread.sleep(1000);
-                asyncConnect();
-            }
-            catch (InterruptedException x)
-            {
-                // Ignore and stop retrying
-                Thread.currentThread().interrupt();
-            }
-        }
-
-        public void deliverException(RHTTPResponse response)
-        {
-            getLogger().debug("Deliver failed, backing off and retrying");
-            try
-            {
-                Thread.sleep(1000);
-                asyncDeliver(response);
-            }
-            catch (InterruptedException x)
-            {
-                // Ignore and stop retrying
-                Thread.currentThread().interrupt();
-            }
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ApacheClientTest.java b/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ApacheClientTest.java
deleted file mode 100644
index 0e7cf1c..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ApacheClientTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-
-import org.apache.http.HttpHost;
-import org.apache.http.client.HttpRequestRetryHandler;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HttpContext;
-import org.eclipse.jetty.rhttp.client.ApacheClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class ApacheClientTest extends ClientTest
-{
-    {
-        ((StdErrLog)Log.getLog()).setHideStacks(!Log.getLog().isDebugEnabled());
-    }
-    
-    private ClientConnectionManager connectionManager;
-
-    protected RHTTPClient createClient(int port, String targetId) throws Exception
-    {
-        SchemeRegistry schemeRegistry = new SchemeRegistry();
-        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), port));
-        connectionManager = new ThreadSafeClientConnManager(new BasicHttpParams(), schemeRegistry);
-        HttpParams httpParams = new BasicHttpParams();
-        httpParams.setParameter("http.default-host", new HttpHost("localhost", port));
-        DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager, httpParams);
-        httpClient.setHttpRequestRetryHandler(new NoRetryHandler());
-        return new ApacheClient(httpClient, "", targetId);
-    }
-
-    protected void destroyClient(RHTTPClient client) throws Exception
-    {
-        connectionManager.shutdown();
-    }
-
-    private class NoRetryHandler implements HttpRequestRetryHandler
-    {
-        public boolean retryRequest(IOException x, int failedAttempts, HttpContext httpContext)
-        {
-            return false;
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ClientTest.java b/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ClientTest.java
deleted file mode 100644
index 6889e95..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ClientTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.rhttp.client.ClientListener;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.bio.SocketConnector;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-import org.eclipse.jetty.util.log.Log;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public abstract class ClientTest extends TestCase
-{
-    protected abstract RHTTPClient createClient(int port, String targetId) throws Exception;
-
-    protected abstract void destroyClient(RHTTPClient client) throws Exception;
-
-    public void testConnectNoServer() throws Exception
-    {
-        RHTTPClient client = createClient(8080, "test1");
-        try
-        {
-            client.connect();
-            fail();
-        }
-        catch (IOException x)
-        {
-        }
-        finally
-        {
-            destroyClient(client);
-        }
-    }
-
-    public void testServerExceptionOnHandshake() throws Exception
-    {
-        final CountDownLatch serverLatch = new CountDownLatch(1);
-
-        Server server = new Server();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.setHandler(new AbstractHandler()
-        {
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (target.endsWith("/handshake"))
-                {
-                    serverLatch.countDown();
-                    throw new TestException();
-                }
-            }
-        });
-        server.start();
-        try
-        {
-            RHTTPClient client = createClient(connector.getLocalPort(), "test2");
-            try
-            {
-                try
-                {
-                    client.connect();
-                    fail();
-                }
-                catch (IOException x)
-                {
-                }
-
-                assertTrue(serverLatch.await(1000, TimeUnit.MILLISECONDS));
-            }
-            finally
-            {
-                destroyClient(client);
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-
-    public void testServerExceptionOnConnect() throws Exception
-    {
-        final CountDownLatch serverLatch = new CountDownLatch(1);
-
-        Server server = new Server();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.setHandler(new AbstractHandler()
-        {
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (target.endsWith("/connect"))
-                {
-                    serverLatch.countDown();
-                    throw new TestException();
-                }
-            }
-        });
-        server.start();
-        try
-        {
-            RHTTPClient client = createClient(connector.getLocalPort(), "test3");
-            try
-            {
-                final CountDownLatch connectLatch = new CountDownLatch(1);
-                client.addClientListener(new ClientListener.Adapter()
-                {
-                    @Override
-                    public void connectException()
-                    {
-                        connectLatch.countDown();
-                    }
-                });
-                client.connect();
-
-                assertTrue(serverLatch.await(1000, TimeUnit.MILLISECONDS));
-                assertTrue(connectLatch.await(1000, TimeUnit.MILLISECONDS));
-            }
-            finally
-            {
-                destroyClient(client);
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-
-    public void testServerExceptionOnDeliver() throws Exception
-    {
-        final CountDownLatch serverLatch = new CountDownLatch(1);
-
-        Server server = new Server();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.setHandler(new AbstractHandler()
-        {
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (target.endsWith("/connect"))
-                {
-                    serverLatch.countDown();
-                    try
-                    {
-                        // Simulate a long poll timeout
-                        Thread.sleep(10000);
-                    }
-                    catch (InterruptedException x)
-                    {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-                else if (target.endsWith("/deliver"))
-                {
-                    // Throw an exception on deliver
-                    throw new TestException();
-                }
-            }
-        });
-        server.start();
-        try
-        {
-            RHTTPClient client = createClient(connector.getLocalPort(), "test4");
-            try
-            {
-                final CountDownLatch deliverLatch = new CountDownLatch(1);
-                client.addClientListener(new ClientListener.Adapter()
-                {
-                    @Override
-                    public void deliverException(RHTTPResponse response)
-                    {
-                        deliverLatch.countDown();
-                    }
-                });
-                client.connect();
-
-                assertTrue(serverLatch.await(1000, TimeUnit.MILLISECONDS));
-
-                client.deliver(new RHTTPResponse(1, 200, "OK", new LinkedHashMap<String, String>(), new byte[0]));
-
-                assertTrue(deliverLatch.await(1000, TimeUnit.MILLISECONDS));
-            }
-            finally
-            {
-                destroyClient(client);
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-
-    public void testServerShutdownAfterConnect() throws Exception
-    {
-        final CountDownLatch connectLatch = new CountDownLatch(1);
-        final CountDownLatch stopLatch = new CountDownLatch(1);
-
-        Server server = new Server();
-        Connector connector = new SocketConnector();
-        server.addConnector(connector);
-        server.setHandler(new AbstractHandler()
-        {
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (target.endsWith("/connect"))
-                {
-                    connectLatch.countDown();
-                    try
-                    {
-                        Thread.sleep(10000);
-                    }
-                    catch (InterruptedException e)
-                    {
-                        stopLatch.countDown();
-                    }
-                }
-            }
-        });
-        server.start();
-        try
-        {
-            RHTTPClient client = createClient(connector.getLocalPort(), "test5");
-            try
-            {
-                final CountDownLatch serverLatch = new CountDownLatch(1);
-                client.addClientListener(new ClientListener.Adapter()
-                {
-                    @Override
-                    public void connectClosed()
-                    {
-                        serverLatch.countDown();
-                    }
-                });
-                client.connect();
-
-                assertTrue(connectLatch.await(2000, TimeUnit.MILLISECONDS));
-
-                server.stop();
-                assertTrue(stopLatch.await(2000, TimeUnit.MILLISECONDS));
-
-                assertTrue(serverLatch.await(2000, TimeUnit.MILLISECONDS));
-            }
-            finally
-            {
-                destroyClient(client);
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-    
-    public static class TestException extends NullPointerException
-    {
-        
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/JettyClientTest.java b/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/JettyClientTest.java
deleted file mode 100644
index 58b2980..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/JettyClientTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class JettyClientTest extends ClientTest
-{
-    {
-        ((StdErrLog)Log.getLog()).setHideStacks(!Log.getLog().isDebugEnabled());
-    }
-    
-    private HttpClient httpClient;
-
-    protected RHTTPClient createClient(int port, String targetId) throws Exception
-    {
-        ((StdErrLog)Log.getLog()).setSource(true);
-        httpClient = new HttpClient();
-        httpClient.start();
-        return new JettyClient(httpClient, new Address("localhost", port), "", targetId);
-    }
-
-    protected void destroyClient(RHTTPClient client) throws Exception
-    {
-        httpClient.stop();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/RequestTest.java b/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/RequestTest.java
deleted file mode 100644
index 848a09b..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/RequestTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-
-import junit.framework.TestCase;
-
-/**
- * @version $Revision$ $Date$
- */
-public class RequestTest extends TestCase
-{
-    public void testRequestConversions() throws Exception
-    {
-        int id = 1;
-        String method = "GET";
-        String uri = "/test";
-        Map<String, String> headers = new LinkedHashMap<String, String>();
-        headers.put("X", "X");
-        headers.put("Y", "Y");
-        headers.put("Z", "Z");
-        byte[] body = "BODY".getBytes("UTF-8");
-        headers.put("Content-Length", String.valueOf(body.length));
-        RHTTPRequest request1 = new RHTTPRequest(id, method, uri, headers, body);
-        byte[] requestBytes1 = request1.getRequestBytes();
-        RHTTPRequest request2 = RHTTPRequest.fromRequestBytes(id, requestBytes1);
-        assertEquals(id, request2.getId());
-        assertEquals(method, request2.getMethod());
-        assertEquals(uri, request2.getURI());
-        assertEquals(headers, request2.getHeaders());
-        assertTrue(Arrays.equals(request2.getBody(), body));
-
-        byte[] requestBytes2 = request2.getRequestBytes();
-        assertTrue(Arrays.equals(requestBytes1, requestBytes2));
-    }
-
-    public void testFrameConversions() throws Exception
-    {
-        int id = 1;
-        String method = "GET";
-        String uri = "/test";
-        Map<String, String> headers = new LinkedHashMap<String, String>();
-        headers.put("X", "X");
-        headers.put("Y", "Y");
-        headers.put("Z", "Z");
-        byte[] body = "BODY".getBytes("UTF-8");
-        headers.put("Content-Length", String.valueOf(body.length));
-        RHTTPRequest request1 = new RHTTPRequest(id, method, uri, headers, body);
-        byte[] frameBytes1 = request1.getFrameBytes();
-        List<RHTTPRequest> requests = RHTTPRequest.fromFrameBytes(frameBytes1);
-        assertNotNull(requests);
-        assertEquals(1, requests.size());
-        RHTTPRequest request2 = requests.get(0);
-        assertEquals(id, request2.getId());
-        assertEquals(method, request2.getMethod());
-        assertEquals(uri, request2.getURI());
-        assertEquals(headers, request2.getHeaders());
-        assertTrue(Arrays.equals(request2.getBody(), body));
-
-        byte[] frameBytes2 = request2.getFrameBytes();
-        assertTrue(Arrays.equals(frameBytes1, frameBytes2));
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ResponseTest.java b/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ResponseTest.java
deleted file mode 100644
index ccff4e2..0000000
--- a/jetty-rhttp/jetty-rhttp-client/src/test/java/org/eclipse/jetty/rhttp/client/ResponseTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.client;
-
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-
-import junit.framework.TestCase;
-
-/**
- * @version $Revision$ $Date$
- */
-public class ResponseTest extends TestCase
-{
-    {
-        ((StdErrLog)Log.getLog()).setHideStacks(!Log.getLog().isDebugEnabled());
-    }
-    
-    public void testResponseConversions() throws Exception
-    {
-        int id = 1;
-        int statusCode = 200;
-        String statusMessage = "OK";
-        Map<String, String> headers = new LinkedHashMap<String, String>();
-        headers.put("X", "X");
-        headers.put("Y", "Y");
-        headers.put("Z", "Z");
-        byte[] body = "BODY".getBytes("UTF-8");
-        RHTTPResponse response1 = new RHTTPResponse(id, statusCode, statusMessage, headers, body);
-        byte[] responseBytes1 = response1.getResponseBytes();
-        RHTTPResponse response2 = RHTTPResponse.fromResponseBytes(id, responseBytes1);
-        assertEquals(id, response2.getId());
-        assertEquals(statusCode, response2.getStatusCode());
-        assertEquals(statusMessage, response2.getStatusMessage());
-        assertEquals(headers, response2.getHeaders());
-        assertTrue(Arrays.equals(response2.getBody(), body));
-
-        byte[] responseBytes2 = response2.getResponseBytes();
-        assertTrue(Arrays.equals(responseBytes1, responseBytes2));
-    }
-
-    public void testFrameConversions() throws Exception
-    {
-        int id = 1;
-        int statusCode = 200;
-        String statusMessage = "OK";
-        Map<String, String> headers = new LinkedHashMap<String, String>();
-        headers.put("X", "X");
-        headers.put("Y", "Y");
-        headers.put("Z", "Z");
-        byte[] body = "BODY".getBytes("UTF-8");
-        RHTTPResponse response1 = new RHTTPResponse(id, statusCode, statusMessage, headers, body);
-        byte[] frameBytes1 = response1.getFrameBytes();
-        RHTTPResponse response2 = RHTTPResponse.fromFrameBytes(frameBytes1);
-        assertEquals(id, response2.getId());
-        assertEquals(statusCode, response2.getStatusCode());
-        assertEquals(response2.getStatusMessage(), statusMessage);
-        assertEquals(headers, response2.getHeaders());
-        assertTrue(Arrays.equals(response2.getBody(), body));
-
-        byte[] frameBytes2 = response2.getFrameBytes();
-        assertTrue(Arrays.equals(frameBytes1, frameBytes2));
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-connector/pom.xml b/jetty-rhttp/jetty-rhttp-connector/pom.xml
deleted file mode 100644
index b248c48..0000000
--- a/jetty-rhttp/jetty-rhttp-connector/pom.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.rhttp</groupId>
-    <artifactId>jetty-rhttp-project</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
-  </parent>
-
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>reverse-http-connector</artifactId>
-  <packaging>jar</packaging>
-  <name>Jetty :: Reverse HTTP :: Connector</name>
-
-  <properties>
-      <bundle-symbolic-name>${project.groupId}.rhttp.connector</bundle-symbolic-name>
-  </properties>
-
-  <build>
-      <plugins>
-          <plugin>
-              <groupId>org.codehaus.mojo</groupId>
-              <artifactId>exec-maven-plugin</artifactId>
-              <configuration>
-                <classpathScope>test</classpathScope>
-                <mainClass>org.eclipse.jetty.rhttp.connector.TestReverseServer</mainClass>
-              </configuration>
-          </plugin>
-          <plugin>
-              <groupId>org.apache.felix</groupId>
-              <artifactId>maven-bundle-plugin</artifactId>
-              <extensions>true</extensions>
-              <executions>
-                  <execution>
-                      <goals>
-                          <goal>manifest</goal>
-                      </goals>
-                      <configuration>
-                          <instructions>
-                               <Import-Package>*</Import-Package>
-                          </instructions>
-                        </configuration>
-                     </execution>
-                </executions>
-            </plugin>
-            <plugin>
-              <!--
-              Required for OSGI
-              -->
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-jar-plugin</artifactId>
-              <configuration>
-                  <archive>
-                      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-                  </archive>
-              </configuration>
-            </plugin>
-      </plugins>
-  </build>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>reverse-http-client</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-util</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-io</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-server</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>example-jetty-embedded</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.toolchain</groupId>
-      <artifactId>jetty-test-helper</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>javax.servlet-api</artifactId>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-</project>
diff --git a/jetty-rhttp/jetty-rhttp-connector/src/main/config/etc/jetty-rhttp.xml b/jetty-rhttp/jetty-rhttp-connector/src/main/config/etc/jetty-rhttp.xml
deleted file mode 100644
index 2141794..0000000
--- a/jetty-rhttp/jetty-rhttp-connector/src/main/config/etc/jetty-rhttp.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<!-- =============================================================== -->
-<!-- Configure the Jetty Reverse HTTP Connector                      -->
-<!-- =============================================================== -->
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-  <Call name="addConnector">
-    <Arg>
-      <New class="org.eclipse.jetty.rhttp.connector.ReverseHTTPConnector">
-        <New class="org.eclipse.jetty.rhttp.client.JettyClient">
-	  <Arg>
-	    <New class="HttpClient">
-	    </New>
-	  </Arg>
-	  <Arg>http://localhost:8888/</Arg>
-	  <Arg>nodeA</Arg>
-        </New>
-      </New>
-    </Arg>
-  </Call>
-</Configure>
diff --git a/jetty-rhttp/jetty-rhttp-connector/src/main/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnector.java b/jetty-rhttp/jetty-rhttp-connector/src/main/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnector.java
deleted file mode 100644
index 10d3ebb..0000000
--- a/jetty-rhttp/jetty-rhttp-connector/src/main/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnector.java
+++ /dev/null
@@ -1,170 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.connector;
-
-import java.io.IOException;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import org.eclipse.jetty.io.ByteArrayEndPoint;
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.server.AbstractConnector;
-import org.eclipse.jetty.server.AbstractHttpConnection;
-import org.eclipse.jetty.server.BlockingHttpConnection;
-import org.eclipse.jetty.util.component.LifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * An implementation of a Jetty connector that uses a {@link RHTTPClient} connected
- * to a gateway server to receive requests, feed them to the Jetty server, and
- * forward responses from the Jetty server to the gateway server.
- *
- * @version $Revision$ $Date$
- */
-public class ReverseHTTPConnector extends AbstractConnector implements RHTTPListener
-{
-    private static final Logger LOG = Log.getLogger(ReverseHTTPConnector.class);
-
-    private final BlockingQueue<RHTTPRequest> requests = new LinkedBlockingQueue<RHTTPRequest>();
-    private final RHTTPClient client;
-
-    public ReverseHTTPConnector(RHTTPClient client)
-    {
-        this.client = client;
-        super.setHost(client.getHost());
-        super.setPort(client.getPort());
-    }
-
-    @Override
-    public void setHost(String host)
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setPort(int port)
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected void doStart() throws Exception
-    {
-        if (client instanceof LifeCycle)
-            ((LifeCycle)client).start();
-        super.doStart();
-        client.connect();
-    }
-
-    @Override
-    protected void doStop() throws Exception
-    {
-        client.disconnect();
-        super.doStop();
-        if (client instanceof LifeCycle)
-            ((LifeCycle)client).stop();
-    }
-
-    public void open()
-    {
-        client.addListener(this);
-    }
-
-    public void close()
-    {
-        client.removeListener(this);
-    }
-
-    public int getLocalPort()
-    {
-        return -1;
-    }
-
-    public Object getConnection()
-    {
-        return this;
-    }
-
-    @Override
-    protected void accept(int acceptorId) throws IOException, InterruptedException
-    {
-        RHTTPRequest request = requests.take();
-        IncomingRequest incomingRequest = new IncomingRequest(request);
-        getThreadPool().dispatch(incomingRequest);
-    }
-
-    @Override
-    public void persist(EndPoint endpoint) throws IOException
-    {
-        // Signals that the connection should not be closed
-        // Do nothing in this case, as we run from memory
-    }
-
-    public void onRequest(RHTTPRequest request) throws Exception
-    {
-        requests.add(request);
-    }
-
-    private class IncomingRequest implements Runnable
-    {
-        private final RHTTPRequest request;
-
-        private IncomingRequest(RHTTPRequest request)
-        {
-            this.request = request;
-        }
-
-        public void run()
-        {
-            byte[] requestBytes = request.getRequestBytes();
-
-            ByteArrayEndPoint endPoint = new ByteArrayEndPoint(requestBytes, 1024);
-            endPoint.setGrowOutput(true);
-
-            AbstractHttpConnection connection = new BlockingHttpConnection(ReverseHTTPConnector.this, endPoint, getServer());
-            
-            connectionOpened(connection);
-            try
-            {
-                // Loop over the whole content, since handle() only
-                // reads up to the connection buffer's capacities
-                while (endPoint.getIn().length() > 0)
-                    connection.handle();
-
-                byte[] responseBytes = endPoint.getOut().asArray();
-                RHTTPResponse response = RHTTPResponse.fromResponseBytes(request.getId(), responseBytes);
-                client.deliver(response);
-            }
-            catch (Exception x)
-            {
-                LOG.debug(x);
-            }
-            finally
-            {
-                connectionClosed(connection);
-            }
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnectorTest.java b/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnectorTest.java
deleted file mode 100644
index 704d33a..0000000
--- a/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/ReverseHTTPConnectorTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.connector;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.rhttp.client.ClientListener;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.rhttp.connector.ReverseHTTPConnector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
-/**
- * @version $Revision$ $Date$
- */
-public class ReverseHTTPConnectorTest extends TestCase
-{
-    public void testGatewayConnectorWithoutRequestBody() throws Exception
-    {
-        testGatewayConnector(false);
-    }
-
-    public void testGatewayConnectorWithRequestBody() throws Exception
-    {
-        testGatewayConnector(true);
-    }
-
-    private void testGatewayConnector(boolean withRequestBody) throws Exception
-    {
-        Server server = new Server();
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        CountDownLatch clientLatch = new CountDownLatch(1);
-        AtomicReference<RHTTPResponse> responseRef = new AtomicReference<RHTTPResponse>();
-        ReverseHTTPConnector connector = new ReverseHTTPConnector(new TestClient(clientLatch, responseRef));
-        server.addConnector(connector);
-        final String method = "POST";
-        final String uri = "/test";
-        final byte[] requestBody = withRequestBody ? "REQUEST-BODY".getBytes("UTF-8") : new byte[0];
-        final int statusCode = HttpServletResponse.SC_CREATED;
-        final String headerName = "foo";
-        final String headerValue = "bar";
-        final byte[] responseBody = "RESPONSE-BODY".getBytes("UTF-8");
-        server.setHandler(new AbstractHandler()
-        {
-            public void handle(String pathInfo, org.eclipse.jetty.server.Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
-            {
-                assertEquals(method, httpRequest.getMethod());
-                assertEquals(uri, httpRequest.getRequestURI());
-                assertEquals(headerValue, httpRequest.getHeader(headerName));
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                InputStream input = httpRequest.getInputStream();
-                int read;
-                while ((read = input.read()) >= 0)
-                    baos.write(read);
-                baos.close();
-                assertTrue(Arrays.equals(requestBody, baos.toByteArray()));
-
-                httpResponse.setStatus(statusCode);
-                httpResponse.setHeader(headerName, headerValue);
-                OutputStream output = httpResponse.getOutputStream();
-                output.write(responseBody);
-                output.flush();
-                request.setHandled(true);
-                handlerLatch.countDown();
-            }
-        });
-        server.start();
-
-        HashMap<String, String> headers = new HashMap<String, String>();
-        headers.put("Host", "localhost");
-        headers.put(headerName, headerValue);
-        headers.put("Content-Length", String.valueOf(requestBody.length));
-        RHTTPRequest request = new RHTTPRequest(1, method, uri, headers, requestBody);
-        request = RHTTPRequest.fromRequestBytes(request.getId(), request.getRequestBytes());
-        connector.onRequest(request);
-
-        assertTrue(handlerLatch.await(1000, TimeUnit.MILLISECONDS));
-        assertTrue(clientLatch.await(1000, TimeUnit.MILLISECONDS));
-        RHTTPResponse response = responseRef.get();
-        assertEquals(request.getId(), response.getId());
-        assertEquals(statusCode, response.getStatusCode());
-        assertEquals(headerValue, response.getHeaders().get(headerName));
-        assertTrue(Arrays.equals(response.getBody(), responseBody));
-    }
-
-    private class TestClient implements RHTTPClient
-    {
-        private final CountDownLatch latch;
-        private final AtomicReference<RHTTPResponse> responseRef;
-
-        private TestClient(CountDownLatch latch, AtomicReference<RHTTPResponse> response)
-        {
-            this.latch = latch;
-            this.responseRef = response;
-        }
-
-        public String getTargetId()
-        {
-            return null;
-        }
-
-        public void connect() throws IOException
-        {
-        }
-
-        public void disconnect() throws IOException
-        {
-        }
-
-        public void deliver(RHTTPResponse response) throws IOException
-        {
-            responseRef.set(response);
-            latch.countDown();
-        }
-
-        public void addListener(RHTTPListener listener)
-        {
-        }
-
-        public void removeListener(RHTTPListener listener)
-        {
-        }
-
-        public void addClientListener(ClientListener listener)
-        {
-        }
-
-        public void removeClientListener(ClientListener listener)
-        {
-        }
-
-        public String getHost()
-        {
-            return null;
-        }
-
-        public int getPort()
-        {
-            return 0;
-        }
-
-        public String getGatewayURI()
-        {
-            // TODO Auto-generated method stub
-            return null;
-        }
-
-        public String getPath()
-        {
-            // TODO Auto-generated method stub
-            return null;
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/TestReverseServer.java b/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/TestReverseServer.java
deleted file mode 100644
index 8d08767..0000000
--- a/jetty-rhttp/jetty-rhttp-connector/src/test/java/org/eclipse/jetty/rhttp/connector/TestReverseServer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.connector;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.embedded.HelloHandler;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.connector.ReverseHTTPConnector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.util.log.Log;
-
-/**
- * A Test content server that uses a {@link ReverseHTTPConnector}.
- * The main of this class starts 3 TestReversionServers with IDs A, B and C.
- */
-public class TestReverseServer extends Server
-{
-    TestReverseServer(String targetId)
-    {
-        setHandler(new HelloHandler("Hello "+targetId,"Hi from "+targetId));
-        
-        HttpClient httpClient = new HttpClient();
-        RHTTPClient client = new JettyClient(httpClient,"http://localhost:8080/__rhttp",targetId);
-        ReverseHTTPConnector connector = new ReverseHTTPConnector(client);
-        
-        addConnector(connector);
-    }
-    
-    public static void main(String... args) throws Exception
-    {
-        Log.getLogger("org.mortbay.jetty.rhttp.client").setDebugEnabled(true);
-        
-        TestReverseServer[] node = new TestReverseServer[] { new TestReverseServer("A"),new TestReverseServer("B"),new TestReverseServer("C") };
-        
-        for (TestReverseServer s : node)
-            s.start();
-
-        for (TestReverseServer s : node)
-            s.join();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/pom.xml b/jetty-rhttp/jetty-rhttp-gateway/pom.xml
deleted file mode 100644
index 054bbd5..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/pom.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.rhttp</groupId>
-        <artifactId>jetty-rhttp-project</artifactId>
-        <version>9.0.0-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>reverse-http-gateway</artifactId>
-    <packaging>jar</packaging>
-    <name>Jetty :: Reverse HTTP :: Gateway</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.rhttp.gateway</bundle-symbolic-name>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>exec-maven-plugin</artifactId>
-                <configuration>
-                  <mainClass>org.mortbay.jetty.rhttp.gateway.Main</mainClass>
-                  <arguments>
-                  </arguments>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                 <Import-Package>*</Import-Package>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-            <plugin>
-              <!--
-              Required for OSGI
-              -->
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-jar-plugin</artifactId>
-              <configuration>
-                  <archive>
-                      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-                  </archive>
-              </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>reverse-http-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-io</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-continuation</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-servlet</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-client</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.toolchain</groupId>
-            <artifactId>jetty-test-helper</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ClientDelegate.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ClientDelegate.java
deleted file mode 100644
index 3f2ed43..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ClientDelegate.java
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-
-
-/**
- * <p>A <tt>ClientDelegate</tt> is the server-side counterpart of a gateway client.</p>
- * <p>The gateway client, the comet protocol and the <tt>ClientDelegate</tt> form the
- * <em>Half-Object plus Protocol</em> pattern that is used between the gateway server
- * and the gateway client.</p>
- * <p><tt>ClientDelegate</tt> offers a server-side API on top of the comet communication.<br />
- * The API allows to enqueue server-side events to the gateway client, allows to
- * flush them to the gateway client, and allows to close and dispose server-side
- * resources when the gateway client disconnects.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface ClientDelegate
-{
-    /**
-     * @return the targetId that uniquely identifies this client delegate.
-     */
-    public String getTargetId();
-
-    /**
-     * <p>Enqueues the given request to the delivery queue so that it will be sent to the
-     * gateway client on the first flush occasion.</p>
-     * <p>Requests may fail to be queued, for example because the gateway client disconnected
-     * concurrently.</p>
-     *
-     * @param request the request to add to the delivery queue
-     * @return whether the request has been queued or not
-     * @see #process(HttpServletRequest)
-     */
-    public boolean enqueue(RHTTPRequest request);
-
-    /**
-     * <p>Flushes the requests that have been {@link #enqueue(RHTTPRequest) enqueued}.</p>
-     * <p>If no requests have been enqueued, then this method may suspend the current request for
-     * the long poll timeout. <br />
-     * The request is suspended only if all these conditions holds true:
-     * <ul>
-     * <li>it is not the first time that this method is called for this client delegate</li>
-     * <li>no requests have been enqueued</li>
-     * <li>this client delegate is not closed</li>
-     * <li>the previous call to this method did not suspend the request</li>
-     * </ul>
-     * In all other cases, a response if sent to the gateway client, possibly containing no requests.
-     *
-     * @param httpRequest the HTTP request for the long poll request from the gateway client
-     * @return the list of requests to send to the gateway client, or null if no response should be sent
-     * to the gateway client
-     * @throws IOException in case of I/O exception while flushing content to the gateway client
-     * @see #enqueue(RHTTPRequest)
-     */
-    public List<RHTTPRequest> process(HttpServletRequest httpRequest) throws IOException;
-
-    /**
-     * <p>Closes this client delegate, in response to a gateway client request to disconnect.</p>
-     * @see #isClosed()
-     */
-    public void close();
-
-    /**
-     * @return whether this delegate client is closed
-     * @see #close()
-     */
-    public boolean isClosed();
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ConnectorServlet.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ConnectorServlet.java
deleted file mode 100644
index 99a00d9..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ConnectorServlet.java
+++ /dev/null
@@ -1,224 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * The servlet that handles the communication with the gateway clients.
- * @version $Revision$ $Date$
- */
-public class ConnectorServlet extends HttpServlet
-{
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final TargetIdRetriever targetIdRetriever = new StandardTargetIdRetriever();
-    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
-    private final ConcurrentMap<String, Future<?>> expirations = new ConcurrentHashMap<String, Future<?>>();
-    private final Gateway gateway;
-    private long clientTimeout=15000;
-
-    public ConnectorServlet(Gateway gateway)
-    {
-        this.gateway = gateway;
-    }
-
-    @Override
-    public void init() throws ServletException 
-    {
-        String t = getInitParameter("clientTimeout");
-        if (t!=null && !"".equals(t))
-            clientTimeout=Long.parseLong(t);
-    }
-
-    @Override
-    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String targetId = targetIdRetriever.retrieveTargetId(request);
-
-        String uri = request.getRequestURI();
-        String path = uri.substring(request.getServletPath().length());
-        String[] segments = path.split("/");
-        if (segments.length < 3)
-            throw new ServletException("Invalid request to " + getClass().getSimpleName() + ": " + uri);
-
-        String action = segments[2];
-        if ("handshake".equals(action))
-            serviceHandshake(targetId, request, response);
-        else if ("connect".equals(action))
-            serviceConnect(targetId, request, response);
-        else if ("deliver".equals(action))
-            serviceDeliver(targetId, request, response);
-        else if ("disconnect".equals(action))
-            serviceDisconnect(targetId, request, response);
-        else
-            throw new ServletException("Invalid request to " + getClass().getSimpleName() + ": " + uri);
-    }
-
-    private void serviceHandshake(String targetId, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
-    {
-        ClientDelegate client = gateway.getClientDelegate(targetId);
-        if (client != null)
-            throw new IOException("Client with targetId " + targetId + " is already connected");
-
-        client = gateway.newClientDelegate(targetId);
-        ClientDelegate existing = gateway.addClientDelegate(targetId, client);
-        if (existing != null)
-            throw new IOException("Client with targetId " + targetId + " is already connected");
-
-        flush(client, httpRequest, httpResponse);
-    }
-
-    private void flush(ClientDelegate client, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
-    {
-        List<RHTTPRequest> requests = client.process(httpRequest);
-        if (requests != null)
-        {
-            // Schedule before sending the requests, to avoid that the remote client
-            // reconnects before we have scheduled the expiration timeout.
-            if (!client.isClosed())
-                schedule(client);
-
-            ServletOutputStream output = httpResponse.getOutputStream();
-            for (RHTTPRequest request : requests)
-                output.write(request.getFrameBytes());
-            // I could count the framed bytes of all requests and set a Content-Length header,
-            // but the implementation of ServletOutputStream takes care of everything:
-            // if the request was HTTP/1.1, then flushing result in a chunked response, but the
-            // client know how to handle it; if the request was HTTP/1.0, then no chunking.
-            // To avoid chunking in HTTP/1.1 I must set the Content-Length header.
-            output.flush();
-            logger.debug("Delivered to device {} requests {} ", client.getTargetId(), requests);
-        }
-    }
-
-    private void schedule(ClientDelegate client)
-    {
-        Future<?> task = scheduler.schedule(new ClientExpirationTask(client), clientTimeout, TimeUnit.MILLISECONDS);
-        Future<?> existing = expirations.put(client.getTargetId(), task);
-        assert existing == null;
-    }
-
-    private void unschedule(String targetId)
-    {
-        Future<?> task = expirations.remove(targetId);
-        if (task != null)
-            task.cancel(false);
-    }
-
-    private void serviceConnect(String targetId, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
-    {
-        unschedule(targetId);
-
-        ClientDelegate client = gateway.getClientDelegate(targetId);
-        if (client == null)
-        {
-            // Expired client tries to connect without handshake
-            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
-        }
-
-        flush(client, httpRequest, httpResponse);
-
-        if (client.isClosed())
-            gateway.removeClientDelegate(targetId);
-    }
-
-    private void expireConnect(ClientDelegate client, long time)
-    {
-        String targetId = client.getTargetId();
-        logger.info("Client with targetId {} missing, last seen {} ms ago, closing it", targetId, System.currentTimeMillis() - time);
-        client.close();
-        // If the client expired, means that it did not connect,
-        // so there no request to resume, and we cleanup here
-        // (while normally this cleanup is done in serviceConnect())
-        unschedule(targetId);
-        gateway.removeClientDelegate(targetId);
-    }
-
-    private void serviceDeliver(String targetId, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException
-    {
-        if (gateway.getClientDelegate(targetId) == null)
-        {
-            // Expired client tries to deliver without handshake
-            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
-        }
-
-        byte[] body = Utils.read(httpRequest.getInputStream());
-
-        RHTTPResponse response = RHTTPResponse.fromFrameBytes(body);
-
-        ExternalRequest externalRequest = gateway.removeExternalRequest(response.getId());
-        if (externalRequest != null)
-        {
-            externalRequest.respond(response);
-            logger.debug("Deliver request from device {}, gateway request {}, response {}", new Object[] {targetId, externalRequest, response});
-        }
-        else
-        {
-            // We can arrive here for a race with the continuation expiration, which expired just before
-            // the gateway client responded with a valid response; log this case ignore it.
-            logger.debug("Deliver request from device {}, missing gateway request, response {}", targetId, response);
-        }
-    }
-
-    private void serviceDisconnect(String targetId, HttpServletRequest request, HttpServletResponse response)
-    {
-        // Do not remove the ClientDelegate from the gateway here,
-        // since closing the ClientDelegate will resume the connect request
-        // and we remove the ClientDelegate from the gateway there
-        ClientDelegate client = gateway.getClientDelegate(targetId);
-        if (client != null)
-            client.close();
-    }
-
-    private class ClientExpirationTask implements Runnable
-    {
-        private final long time = System.currentTimeMillis();
-        private final ClientDelegate client;
-
-        public ClientExpirationTask(ClientDelegate client)
-        {
-            this.client = client;
-        }
-
-        public void run()
-        {
-            expireConnect(client, time);
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalRequest.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalRequest.java
deleted file mode 100644
index d55d5ae..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalRequest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-
-
-/**
- * <p><tt>ExternalRequest</tt> represent an external request made to the gateway server.</p>
- * <p><tt>ExternalRequest</tt>s that arrive to the gateway server are suspended, waiting
- * for a response from the corresponding gateway client.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface ExternalRequest
-{
-    /**
-     * <p>Suspends this <tt>ExternalRequest</tt> waiting for a response from the gateway client.</p>
-     * @return true if the <tt>ExternalRequest</tt> has been suspended, false if the
-     * <tt>ExternalRequest</tt> has already been responded.
-     */
-    public boolean suspend();
-
-    /**
-     * <p>Responds to the original external request with the response arrived from the gateway client.</p>
-     * @param response the response arrived from the gateway client
-     * @throws IOException if responding to the original external request fails
-     */
-    public void respond(RHTTPResponse response) throws IOException;
-
-    /**
-     * @return the request to be sent to the gateway client
-     */
-    public RHTTPRequest getRequest();
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalServlet.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalServlet.java
deleted file mode 100644
index 702757e..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/ExternalServlet.java
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * The servlet that handles external requests.
- *
- * @version $Revision$ $Date$
- */
-public class ExternalServlet extends HttpServlet
-{
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final Gateway gateway;
-    private TargetIdRetriever targetIdRetriever;
-
-    public ExternalServlet(Gateway gateway, TargetIdRetriever targetIdRetriever)
-    {
-        this.gateway = gateway;
-        this.targetIdRetriever = targetIdRetriever;
-    }
-
-    public TargetIdRetriever getTargetIdRetriever()
-    {
-        return targetIdRetriever;
-    }
-
-    public void setTargetIdRetriever(TargetIdRetriever targetIdRetriever)
-    {
-        this.targetIdRetriever = targetIdRetriever;
-    }
-
-    @Override
-    protected void service(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException
-    {
-        logger.debug("External http request: {}", httpRequest.getRequestURL());
-
-        String targetId = targetIdRetriever.retrieveTargetId(httpRequest);
-        if (targetId == null)
-            throw new ServletException("Invalid request to " + getClass().getSimpleName() + ": " + httpRequest.getRequestURI());
-
-        ClientDelegate client = gateway.getClientDelegate(targetId);
-        if (client == null) throw new ServletException("Client with targetId " + targetId + " is not connected");
-
-        ExternalRequest externalRequest = gateway.newExternalRequest(httpRequest, httpResponse);
-        RHTTPRequest request = externalRequest.getRequest();
-        ExternalRequest existing = gateway.addExternalRequest(request.getId(), externalRequest);
-        assert existing == null;
-        logger.debug("External request {} for device {}", request, targetId);
-
-        boolean delivered = client.enqueue(request);
-        if (delivered)
-        {
-            externalRequest.suspend();
-        }
-        else
-        {
-            // TODO: improve this: we can temporarly queue this request elsewhere and wait for the client to reconnect ?
-            throw new ServletException("Could not enqueue request to client with targetId " + targetId);
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Gateway.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Gateway.java
deleted file mode 100644
index a14351f..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Gateway.java
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * <p>Gateway instances are responsible of holding the state of the gateway server.</p>
- * <p>The state is composed by:
- * <ul>
- * <li>{@link ExternalRequest external requests} that are suspended waiting for the response</li>
- * <li>{@link ClientDelegate gateway clients} that are connected with the gateway server</li>
- * </ul></p>
- * <p>Instances of this class are created by the {@link GatewayServer}.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface Gateway
-{
-    /**
-     * <p>Returns the {@link ClientDelegate} with the given targetId.<br />
-     * If there is no such ClientDelegate returns null.</p>
-     *
-     * @param targetId the targetId of the ClientDelegate to return
-     * @return the ClientDelegate associated with the given targetId
-     */
-    public ClientDelegate getClientDelegate(String targetId);
-
-    /**
-     * <p>Creates and configures a new {@link ClientDelegate} with the given targetId.</p>
-     * @param targetId the targetId of the ClientDelegate to create
-     * @return a newly created ClientDelegate
-     * @see #addClientDelegate(String, ClientDelegate)
-     */
-    public ClientDelegate newClientDelegate(String targetId);
-
-    /**
-     * <p>Maps the given ClientDelegate to the given targetId.</p>
-     * @param targetId the targetId of the given ClientDelegate
-     * @param client the ClientDelegate to map
-     * @return the previously existing ClientDelegate mapped to the same targetId
-     * @see #removeClientDelegate(String)
-     */
-    public ClientDelegate addClientDelegate(String targetId, ClientDelegate client);
-
-    /**
-     * <p>Removes the {@link ClientDelegate} associated with the given targetId.</p>
-     * @param targetId the targetId of the ClientDelegate to remove
-     * @return the removed ClientDelegate, or null if no ClientDelegate was removed
-     * @see #addClientDelegate(String, ClientDelegate)
-     */
-    public ClientDelegate removeClientDelegate(String targetId);
-
-    /**
-     * <p>Creates a new {@link ExternalRequest} from the given HTTP request and HTTP response.</p>
-     * @param httpRequest the HTTP request of the external request
-     * @param httpResponse the HTTP response of the external request
-     * @return a newly created ExternalRequest
-     * @throws IOException in case of failures creating the ExternalRequest
-     * @see #addExternalRequest(int, ExternalRequest)
-     */
-    public ExternalRequest newExternalRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException;
-
-    /**
-     * Maps the given ExternalRequest with the given requestId into the gateway state.
-     * @param requestId the id of the ExternalRequest
-     * @param externalRequest the ExternalRequest to map
-     * @return the previously existing ExternalRequest mapped to the same requestId
-     * @see #removeExternalRequest(int)
-     */
-    public ExternalRequest addExternalRequest(int requestId, ExternalRequest externalRequest);
-
-    /**
-     * Removes the ExternalRequest mapped to the given requestId from the gateway state.
-     * @param requestId the id of the ExternalRequest
-     * @return the removed ExternalRequest
-     * @see #addExternalRequest(int, ExternalRequest)
-     */
-    public ExternalRequest removeExternalRequest(int requestId);
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayProxyServer.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayProxyServer.java
deleted file mode 100644
index 5311d80..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayProxyServer.java
+++ /dev/null
@@ -1,228 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.io.Buffer;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>This class combines a gateway server and a gateway client to obtain the functionality of a simple proxy server.</p>
- * <p>This gateway proxy server starts on port 8080 and can be set as http proxy in browsers such as Firefox, and used
- * to browse the internet.</p>
- * <p>Its functionality is limited (for example, it only supports http, and not https).</p>
- * @version $Revision$ $Date$
- */
-public class GatewayProxyServer
-{
-    private static final Logger logger = Log.getLogger(GatewayProxyServer.class.toString());
-
-    public static void main(String[] args) throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-
-        Connector plainConnector = new SelectChannelConnector();
-        plainConnector.setPort(8080);
-        server.addConnector(plainConnector);
-
-        ((StandardGateway)server.getGateway()).setExternalTimeout(180000);
-        ((StandardGateway)server.getGateway()).setGatewayTimeout(20000);
-        server.setTargetIdRetriever(new ProxyTargetIdRetriever());
-        server.start();
-
-        HttpClient httpClient = new HttpClient();
-        httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
-        httpClient.start();
-
-        RHTTPClient client = new JettyClient(httpClient, new Address("localhost", plainConnector.getPort()), server.getContext().getContextPath() + "/gw", "proxy");
-        client.addListener(new ProxyListener(httpClient, client));
-        client.connect();
-
-        Runtime.getRuntime().addShutdownHook(new Shutdown(server, httpClient, client));
-        logger.info("{} started", GatewayProxyServer.class.getSimpleName());
-    }
-
-    private static class Shutdown extends Thread
-    {
-        private final GatewayServer server;
-        private final HttpClient httpClient;
-        private final RHTTPClient client;
-
-        public Shutdown(GatewayServer server, HttpClient httpClient, RHTTPClient client)
-        {
-            this.server = server;
-            this.httpClient = httpClient;
-            this.client = client;
-        }
-
-        @Override
-        public void run()
-        {
-            try
-            {
-                client.disconnect();
-                httpClient.stop();
-                server.stop();
-                logger.info("{} stopped", GatewayProxyServer.class.getSimpleName());
-            }
-            catch (Exception x)
-            {
-                logger.debug("Exception while stopping " + GatewayProxyServer.class.getSimpleName(), x);
-            }
-        }
-    }
-
-    private static class ProxyListener implements RHTTPListener
-    {
-        private final HttpClient httpClient;
-        private final RHTTPClient client;
-
-        private ProxyListener(HttpClient httpClient, RHTTPClient client)
-        {
-            this.httpClient = httpClient;
-            this.client = client;
-        }
-
-        public void onRequest(RHTTPRequest request) throws Exception
-        {
-            ProxyExchange exchange = new ProxyExchange();
-            Address address = Address.from(request.getHeaders().get("Host"));
-            if (address.getPort() == 0) address = new Address(address.getHost(), 80);
-            exchange.setAddress(address);
-            exchange.setMethod(request.getMethod());
-            exchange.setURI(request.getURI());
-            for (Map.Entry<String, String> header : request.getHeaders().entrySet())
-                exchange.setRequestHeader(header.getKey(), header.getValue());
-            exchange.setRequestContent(new ByteArrayBuffer(request.getBody()));
-            int status = syncSend(exchange);
-            if (status == HttpExchange.STATUS_COMPLETED)
-            {
-                int statusCode = exchange.getResponseStatus();
-                String statusMessage = exchange.getResponseMessage();
-                Map<String, String> responseHeaders = exchange.getResponseHeaders();
-                byte[] responseBody = exchange.getResponseBody();
-                RHTTPResponse response = new RHTTPResponse(request.getId(), statusCode, statusMessage, responseHeaders, responseBody);
-                client.deliver(response);
-            }
-            else
-            {
-                int statusCode = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
-                String statusMessage = "Gateway error";
-                HashMap<String, String> responseHeaders = new HashMap<String, String>();
-                responseHeaders.put("Connection", "close");
-                byte[] responseBody = new byte[0];
-                RHTTPResponse response = new RHTTPResponse(request.getId(), statusCode, statusMessage, responseHeaders, responseBody);
-                client.deliver(response);
-            }
-        }
-
-        private int syncSend(ProxyExchange exchange) throws Exception
-        {
-            long start = System.nanoTime();
-            httpClient.send(exchange);
-            int status = exchange.waitForDone();
-            long end = System.nanoTime();
-            long millis = TimeUnit.NANOSECONDS.toMillis(end - start);
-            long micros = TimeUnit.NANOSECONDS.toMicros(end - start - TimeUnit.MILLISECONDS.toNanos(millis));
-            logger.debug("Proxied request took {}.{} ms", millis, micros);
-            return status;
-        }
-    }
-
-    private static class ProxyExchange extends ContentExchange
-    {
-        private String responseMessage;
-        private Map<String, String> responseHeaders = new HashMap<String, String>();
-        private ByteArrayOutputStream responseBody = new ByteArrayOutputStream();
-
-        private ProxyExchange()
-        {
-            super(true);
-        }
-
-        public String getResponseMessage()
-        {
-            return responseMessage;
-        }
-
-        public Map<String, String> getResponseHeaders()
-        {
-            return responseHeaders;
-        }
-
-        public byte[] getResponseBody()
-        {
-            return responseBody.toByteArray();
-        }
-
-        @Override
-        protected void onResponseStatus(Buffer version, int code, Buffer message) throws IOException
-        {
-            super.onResponseStatus(version, code, message);
-            this.responseMessage = message.toString("UTF-8");
-        }
-
-        @Override
-        protected void onResponseHeader(Buffer nameBuffer, Buffer valueBuffer) throws IOException
-        {
-            super.onResponseHeader(nameBuffer, valueBuffer);
-            String name = nameBuffer.toString("UTF-8");
-            String value = valueBuffer.toString("UTF-8");
-            // Skip chunked header, since we read the whole body and will not re-chunk it
-            if (!name.equalsIgnoreCase("Transfer-Encoding") || !value.equalsIgnoreCase("chunked"))
-                responseHeaders.put(name, value);
-        }
-
-        @Override
-        protected void onResponseContent(Buffer buffer) throws IOException
-        {
-            responseBody.write(buffer.asArray());
-            super.onResponseContent(buffer);
-        }
-    }
-
-    public static class ProxyTargetIdRetriever implements TargetIdRetriever
-    {
-        public String retrieveTargetId(HttpServletRequest httpRequest)
-        {
-            return "proxy";
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java
deleted file mode 100644
index 4ed504b..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/GatewayServer.java
+++ /dev/null
@@ -1,171 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>The gateway server is a server component that acts as intermediary between
- * <em>external clients</em> which perform requests for resources, and the
- * <em>resource providers</em>.</p>
- * <p>The particularity of the gateway server is that the resource providers
- * connect to the gateway using a comet protocol. <br />
- * The comet procotol functionality is implemented by a gateway client. <br />
- * This is quite different from a normal proxy server where it is the proxy that
- * connects to the resource providers.</p>
- * <p>Schematically, this is how the gateway server works:</p>
- * <pre>
- * External Client       Gateway Server         Gateway Client         Resource Provider
- *                              |                      |
- *                              | &lt;-- comet req. 1 --- |
- *        | --- ext. req. 1 --&gt; |                      |
- *        |                     | --- comet res. 1 --&gt; |
- *        |                     | &lt;-- comet req. 2 --- |
- *        |                                            | --- ext. req. 1 --&gt; |
- *                                                                           |
- *        |                                            | &lt;-- ext. res. 1 --- |
- *        |                     | &lt;-- ext.  res. 1 --- |
- *        | &lt;-- ext. res. 1 --- |
- *
- *        | --- ext. req. 2 --&gt; |
- *        |                     | --- comet res. 2 --&gt; |
- *        .                     .                      .
- * </pre>
- * <p>The gateway server is made of two servlets:
- * <ul>
- * <li>the external servlet, that handles external requests</li>
- * <li>the gateway servlet, that handles the communication with the gateway client</li>
- * </ul>
- * </p>
- * <p>External requests are suspended using Jetty continuations until a response for
- * that request arrives from the resource provider, or a
- * {@link #getExternalTimeout() configurable timeout} expires. <br />
- * Comet requests made by the gateway client also expires after a (different)
- * {@link #getGatewayTimeout() configurable timeout}.</p>
- * <p>External requests are packed into {@link RHTTPRequest} objects, converted into an
- * opaque byte array and sent as the body of the comet reponse to the gateway
- * {@link RHTTPClient}.</p>
- * <p>The gateway client uses a notification mechanism to alert listeners interested
- * in external requests that have been forwarded through the gateway. It is up to the
- * listeners to connect to the resource provider however they like.</p>
- * <p>When the gateway client receives a response from the resource provider, it packs
- * the response into a {@link RHTTPResponse} object, converts it into an opaque byte array
- * and sends it as the body of a normal HTTP request to the gateway server.</p>
- * <p>It is possible to connect more than one gateway client to a gateway server; each
- * gateway client is identified by a unique <em>targetId</em>. <br />
- * External requests must specify a targetId that allows the gateway server to forward
- * the requests to the specific gateway client; how the targetId is retrieved from an
- * external request is handled by {@link TargetIdRetriever} implementations.</p>
- *
- * @version $Revision$ $Date$
- */
-public class GatewayServer extends Server
-{
-    public final static String DFT_EXT_PATH="/gw";
-    public final static String DFT_CONNECT_PATH="/__rhttp";
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final Gateway gateway;
-    private final ServletHolder externalServletHolder;
-    private final ServletHolder connectorServletHolder;
-    private final ServletContextHandler context;
-    
-    public GatewayServer()
-    {
-        this("",DFT_EXT_PATH,DFT_CONNECT_PATH,new StandardTargetIdRetriever());
-    }
-
-    public GatewayServer(String contextPath, String externalServletPath,String gatewayServletPath, TargetIdRetriever targetIdRetriever)
-    {
-        HandlerCollection handlers = new HandlerCollection();
-        setHandler(handlers);
-        context = new ServletContextHandler(handlers, contextPath, ServletContextHandler.SESSIONS);
-        
-        // Setup the gateway
-        gateway = createGateway();
-        
-        // Setup external servlet
-        ExternalServlet externalServlet = new ExternalServlet(gateway, targetIdRetriever);
-        externalServletHolder = new ServletHolder(externalServlet);
-        context.addServlet(externalServletHolder, externalServletPath + "/*");
-        logger.debug("External servlet mapped to {}/*", externalServletPath);
-
-        // Setup gateway servlet
-        ConnectorServlet gatewayServlet = new ConnectorServlet(gateway);
-        connectorServletHolder = new ServletHolder(gatewayServlet);
-        connectorServletHolder.setInitParameter("clientTimeout", "15000");
-        context.addServlet(connectorServletHolder, gatewayServletPath + "/*");
-        logger.debug("Gateway servlet mapped to {}/*", gatewayServletPath);
-    }
-
-    /**
-     * Creates and configures a {@link Gateway} object.
-     * @return the newly created and configured Gateway object.
-     */
-    protected Gateway createGateway()
-    {
-        StandardGateway gateway = new StandardGateway();
-        return gateway;
-    }
-    
-    public ServletContextHandler getContext()
-    {
-        return context;
-    }
-    
-    public Gateway getGateway()
-    {
-        return gateway;
-    }
-    
-    public ServletHolder getExternalServlet()
-    {
-        return externalServletHolder;
-    }
-    
-    public ServletHolder getConnectorServlet()
-    {
-        return connectorServletHolder;
-    }
-
-    public void setTargetIdRetriever(TargetIdRetriever retriever)
-    {
-        ((ExternalServlet)externalServletHolder.getServletInstance()).setTargetIdRetriever(retriever);
-    }
-
-    public TargetIdRetriever getTargetIdRetriever()
-    {
-        return ((ExternalServlet)externalServletHolder.getServletInstance()).getTargetIdRetriever();
-    }
-    
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetriever.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetriever.java
deleted file mode 100644
index 6f6a299..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetriever.java
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * @version $Revision$ $Date$
- */
-public class HostTargetIdRetriever implements TargetIdRetriever
-{
-    private final String suffix;
-
-    public HostTargetIdRetriever(String suffix)
-    {
-        this.suffix = suffix;
-    }
-
-    public String retrieveTargetId(HttpServletRequest httpRequest)
-    {
-        String host = httpRequest.getHeader("Host");
-        if (host != null)
-        {
-            // Strip the port
-            int colon = host.indexOf(':');
-            if (colon > 0)
-            {
-                host = host.substring(0, colon);
-            }
-
-            if (suffix != null && host.endsWith(suffix))
-            {
-                return host.substring(0, host.length() - suffix.length());
-            }
-        }
-        return host;
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Main.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Main.java
deleted file mode 100644
index 8030e90..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Main.java
+++ /dev/null
@@ -1,128 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletHolder;
-
-/**
- * <p>Main class that starts the gateway server.</p>
- * <p>This class supports the following arguments:</p>
- * <ul>
- * <li>--port=&lt;port&gt; specifies the port on which the gateway server listens to, by default 8080</li>
- * <li>--retriever=&lt;retriever&gt; specifies the
- * {@link GatewayServer#setTargetIdRetriever(TargetIdRetriever) target id retriever}</li>
- * <li>--resources=&lt;resources file path&gt; specifies the resource file path for the gateway</li>
- * </ul>
- * <p>Examples</p>
- * <p> <tt>java --port=8080</tt> </p>
- * <p> <tt>java --port=8080 --resources=/tmp/gateway-resources</tt> </p>
- * <p> <tt>java --port=8080 --retriever=standard</tt> </p>
- * <p> <tt>java --port=8080 --retriever=host,.rhttp.example.com</tt> </p>
- * <p>The latter example specifies the {@link HostTargetIdRetriever} with a suffix of <tt>.rhttp.example.com</tt></p>
- *
- * @see GatewayServer
- * @version $Revision$ $Date$
- */
-public class Main
-{
-    private static final String PORT_ARG = "port";
-    private static final String RESOURCES_ARG = "resources";
-    private static final String RETRIEVER_ARG = "retriever";
-
-    public static void main(String[] args) throws Exception
-    {
-        Map<String, Object> arguments = parse(args);
-
-        int port = 8080;
-        if (arguments.containsKey(PORT_ARG))
-            port = (Integer)arguments.get(PORT_ARG);
-
-        String resources = null;
-        if (arguments.containsKey(RESOURCES_ARG))
-            resources = (String)arguments.get(RESOURCES_ARG);
-
-        TargetIdRetriever retriever = null;
-        if (arguments.containsKey(RETRIEVER_ARG))
-            retriever = (TargetIdRetriever)arguments.get(RETRIEVER_ARG);
-
-        GatewayServer server = new GatewayServer();
-
-        Connector connector = new SelectChannelConnector();
-        connector.setPort(port);
-        server.addConnector(connector);
-
-        if (resources != null)
-        {
-            server.getContext().setResourceBase(resources);
-            ServletHolder resourcesServletHolder = server.getContext().addServlet(DefaultServlet.class,"__r/*");
-            resourcesServletHolder.setInitParameter("dirAllowed", "true");
-        }
-
-        if (retriever != null)
-            server.setTargetIdRetriever(retriever);
-
-        server.start();
-    }
-
-    private static Map<String, Object> parse(String[] args)
-    {
-        Map<String, Object> result = new HashMap<String, Object>();
-
-        Pattern pattern = Pattern.compile("--([^=]+)=(.+)");
-        for (String arg : args)
-        {
-            Matcher matcher = pattern.matcher(arg);
-            if (matcher.matches())
-            {
-                String argName = matcher.group(1);
-                if (PORT_ARG.equals(argName))
-                {
-                    result.put(PORT_ARG, Integer.parseInt(matcher.group(2)));
-                }
-                else if (RESOURCES_ARG.equals(argName))
-                {
-                    String argValue = matcher.group(2);
-                    result.put(RESOURCES_ARG, argValue);
-                }
-                else if (RETRIEVER_ARG.equals(argName))
-                {
-                    String argValue = matcher.group(2);
-                    if (argValue.startsWith("host,"))
-                    {
-                        String[] typeAndSuffix = StringUtil.split(argValue);
-                        if (typeAndSuffix.length != 2)
-                            throw new IllegalArgumentException("Invalid option " + arg + ", must be of the form --" + RETRIEVER_ARG + "=host,suffix");
-
-                        result.put(RETRIEVER_ARG, new HostTargetIdRetriever(typeAndSuffix[1]));
-                    }
-                }
-            }
-        }
-
-        return result;
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardClientDelegate.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardClientDelegate.java
deleted file mode 100644
index 4832db4..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardClientDelegate.java
+++ /dev/null
@@ -1,172 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationSupport;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>Default implementation of {@link ClientDelegate}.</p>
- *
- * @version $Revision$ $Date$
- */
-public class StandardClientDelegate implements ClientDelegate
-{
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final Object lock = new Object();
-    private final List<RHTTPRequest> requests = new ArrayList<RHTTPRequest>();
-    private final String targetId;
-    private volatile boolean firstFlush = true;
-    private volatile long timeout;
-    private volatile boolean closed;
-    private Continuation continuation;
-
-    public StandardClientDelegate(String targetId)
-    {
-        this.targetId = targetId;
-    }
-
-    public String getTargetId()
-    {
-        return targetId;
-    }
-
-    public long getTimeout()
-    {
-        return timeout;
-    }
-
-    public void setTimeout(long timeout)
-    {
-        this.timeout = timeout;
-    }
-
-    public boolean enqueue(RHTTPRequest request)
-    {
-        if (isClosed())
-            return false;
-
-        synchronized (lock)
-        {
-            requests.add(request);
-            resume();
-        }
-
-        return true;
-    }
-
-    private void resume()
-    {
-        synchronized (lock)
-        {
-            // Continuation may be null in several cases:
-            // 1. there always is something to deliver so we never suspend
-            // 2. concurrent calls to add() and close()
-            // 3. concurrent close() with a long poll that expired
-            // 4. concurrent close() with a long poll that resumed
-            if (continuation != null)
-            {
-                continuation.resume();
-                // Null the continuation, as there is no point is resuming multiple times
-                continuation = null;
-            }
-        }
-    }
-
-    public List<RHTTPRequest> process(HttpServletRequest httpRequest) throws IOException
-    {
-        // We want to respond in the following cases:
-        // 1. It's the first time we process: the client will wait for a response before issuing another connect.
-        // 2. The client disconnected, so we want to return from this connect before it times out.
-        // 3. We've been woken up because there are responses to send.
-        // 4. The continuation was suspended but timed out.
-        //    The timeout case is different from a non-first connect, in that we want to return
-        //    a (most of the times empty) response and we do not want to wait again.
-        // The order of these if statements is important, as the continuation timed out only if
-        // the client is not closed and there are no responses to send
-        List<RHTTPRequest> result = Collections.emptyList();
-        if (firstFlush)
-        {
-            firstFlush = false;
-            logger.debug("Connect request (first) from device {}, delivering requests {}", targetId, result);
-        }
-        else
-        {
-            // Synchronization is crucial here, since we don't want to suspend if there is something to deliver
-            synchronized (lock)
-            {
-                int size = requests.size();
-                if (size > 0)
-                {
-                    assert continuation == null;
-                    result = new ArrayList<RHTTPRequest>(size);
-                    result.addAll(requests);
-                    requests.clear();
-                    logger.debug("Connect request (resumed) from device {}, delivering requests {}", targetId, result);
-                }
-                else
-                {
-                    if (continuation != null)
-                    {
-                        continuation = null;
-                        logger.debug("Connect request (expired) from device {}, delivering requests {}", targetId, result);
-                    }
-                    else
-                    {
-                        if (isClosed())
-                        {
-                            logger.debug("Connect request (closed) from device {}, delivering requests {}", targetId, result);
-                        }
-                        else
-                        {
-                            // Here we need to suspend
-                            continuation = ContinuationSupport.getContinuation(httpRequest);
-                            continuation.setTimeout(getTimeout());
-                            continuation.suspend();
-                            result = null;
-                            logger.debug("Connect request (suspended) from device {}", targetId);
-                        }
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    public void close()
-    {
-        closed = true;
-        resume();
-    }
-
-    public boolean isClosed()
-    {
-        return closed;
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardExternalRequest.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardExternalRequest.java
deleted file mode 100644
index 4da1d3e..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardExternalRequest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.Map;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
-import org.eclipse.jetty.continuation.ContinuationSupport;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * Default implementation of {@link ExternalRequest}.
- *
- * @version $Revision$ $Date$
- */
-public class StandardExternalRequest implements ExternalRequest
-{
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final RHTTPRequest request;
-    private final HttpServletRequest httpRequest;
-    private final HttpServletResponse httpResponse;
-    private final Gateway gateway;
-    private final Object lock = new Object();
-    private volatile long timeout;
-    private Continuation continuation;
-    private boolean responded;
-
-    public StandardExternalRequest(RHTTPRequest request, HttpServletRequest httpRequest, HttpServletResponse httpResponse, Gateway gateway)
-    {
-        this.request = request;
-        this.httpRequest = httpRequest;
-        this.httpResponse = httpResponse;
-        this.gateway = gateway;
-    }
-
-    public long getTimeout()
-    {
-        return timeout;
-    }
-
-    public void setTimeout(long timeout)
-    {
-        this.timeout = timeout;
-    }
-
-    public boolean suspend()
-    {
-        synchronized (lock)
-        {
-            // We suspend only if we have no responded yet
-            if (!responded)
-            {
-                assert continuation == null;
-                continuation = ContinuationSupport.getContinuation(httpRequest);
-                continuation.setTimeout(getTimeout());
-                continuation.addContinuationListener(new TimeoutListener());
-                continuation.suspend(httpResponse);
-                logger.debug("Request {} suspended", getRequest());
-            }
-            else
-            {
-                logger.debug("Request {} already responded", getRequest());
-            }
-            return !responded;
-        }
-    }
-
-    public void respond(RHTTPResponse response) throws IOException
-    {
-        responseCompleted(response);
-    }
-
-    private void responseCompleted(RHTTPResponse response) throws IOException
-    {
-        synchronized (lock)
-        {
-            // Could be that we complete exactly when the response is being expired
-            if (!responded)
-            {
-                httpResponse.setStatus(response.getStatusCode());
-
-                for (Map.Entry<String, String> header : response.getHeaders().entrySet())
-                    httpResponse.setHeader(header.getKey(), header.getValue());
-
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(response.getBody());
-                output.flush();
-
-                // It may happen that the continuation is null,
-                // because the response arrived before we had the chance to suspend
-                if (continuation != null)
-                {
-                    continuation.complete();
-                    continuation = null;
-                }
-
-                // Mark as responded, so we know we don't have to suspend
-                // or respond with an expired response
-                responded = true;
-
-                if (logger.isDebugEnabled())
-                {
-                    String eol = System.getProperty("line.separator");
-                    logger.debug("Request {} responded {}{}{}{}{}", new Object[]{request, response, eol, request.toLongString(), eol, response.toLongString()});
-                }
-            }
-        }
-    }
-
-    private void responseExpired() throws IOException
-    {
-        synchronized (lock)
-        {
-            // Could be that we expired exactly when the response is being completed
-            if (!responded)
-            {
-                httpResponse.sendError(HttpServletResponse.SC_GATEWAY_TIMEOUT, "Gateway Time-out");
-
-                continuation.complete();
-                continuation = null;
-
-                // Mark as responded, so we know we don't have to respond with a completed response
-                responded = true;
-
-                logger.debug("Request {} expired", getRequest());
-            }
-        }
-    }
-
-    public RHTTPRequest getRequest()
-    {
-        return request;
-    }
-
-    @Override
-    public String toString()
-    {
-        return request.toString();
-    }
-
-    private class TimeoutListener implements ContinuationListener
-    {
-        public void onComplete(Continuation continuation)
-        {
-        }
-
-        public void onTimeout(Continuation continuation)
-        {
-            ExternalRequest externalRequest = gateway.removeExternalRequest(getRequest().getId());
-            // The gateway request can be null for a race with delivery
-            if (externalRequest != null)
-            {
-                try
-                {
-                    responseExpired();
-                }
-                catch (Exception x)
-                {
-                    logger.warn("Request " + getRequest() + " expired but failed", x);
-                }
-            }
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardGateway.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardGateway.java
deleted file mode 100644
index f006b13..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardGateway.java
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * Default implementation of {@link Gateway}.
- *
- * @version $Revision$ $Date$
- */
-public class StandardGateway implements Gateway
-{
-    private final Logger logger = Log.getLogger(getClass().toString());
-    private final ConcurrentMap<String, ClientDelegate> clients = new ConcurrentHashMap<String, ClientDelegate>();
-    private final ConcurrentMap<Integer, ExternalRequest> requests = new ConcurrentHashMap<Integer, ExternalRequest>();
-    private final AtomicInteger requestIds = new AtomicInteger();
-    private volatile long gatewayTimeout=20000;
-    private volatile long externalTimeout=60000;
-
-    public long getGatewayTimeout()
-    {
-        return gatewayTimeout;
-    }
-
-    public void setGatewayTimeout(long timeout)
-    {
-        this.gatewayTimeout = timeout;
-    }
-
-    public long getExternalTimeout()
-    {
-        return externalTimeout;
-    }
-
-    public void setExternalTimeout(long externalTimeout)
-    {
-        this.externalTimeout = externalTimeout;
-    }
-
-    public ClientDelegate getClientDelegate(String targetId)
-    {
-        return clients.get(targetId);
-    }
-
-    public ClientDelegate newClientDelegate(String targetId)
-    {
-        StandardClientDelegate client = new StandardClientDelegate(targetId);
-        client.setTimeout(getGatewayTimeout());
-        return client;
-    }
-
-    public ClientDelegate addClientDelegate(String targetId, ClientDelegate client)
-    {
-        return clients.putIfAbsent(targetId, client);
-    }
-
-    public ClientDelegate removeClientDelegate(String targetId)
-    {
-        return clients.remove(targetId);
-    }
-
-    public ExternalRequest newExternalRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
-    {
-        int requestId = requestIds.incrementAndGet();
-        RHTTPRequest request = convertHttpRequest(requestId, httpRequest);
-        StandardExternalRequest gatewayRequest = new StandardExternalRequest(request, httpRequest, httpResponse, this);
-        gatewayRequest.setTimeout(getExternalTimeout());
-        return gatewayRequest;
-    }
-
-    protected RHTTPRequest convertHttpRequest(int requestId, HttpServletRequest httpRequest) throws IOException
-    {
-        Map<String, String> headers = new HashMap<String, String>();
-        for (Enumeration headerNames = httpRequest.getHeaderNames(); headerNames.hasMoreElements();)
-        {
-            String name = (String)headerNames.nextElement();
-            // TODO: improve by supporting getHeaders(name)
-            String value = httpRequest.getHeader(name);
-            headers.put(name, value);
-        }
-
-        byte[] body = Utils.read(httpRequest.getInputStream());
-        return new RHTTPRequest(requestId, httpRequest.getMethod(), httpRequest.getRequestURI(), headers, body);
-    }
-
-    public ExternalRequest addExternalRequest(int requestId, ExternalRequest externalRequest)
-    {
-        ExternalRequest existing = requests.putIfAbsent(requestId, externalRequest);
-        if (existing == null)
-            logger.debug("Added external request {}/{} - {}", new Object[]{requestId, requests.size(), externalRequest});
-        return existing;
-    }
-
-    public ExternalRequest removeExternalRequest(int requestId)
-    {
-        ExternalRequest externalRequest = requests.remove(requestId);
-        if (externalRequest != null)
-            logger.debug("Removed external request {}/{} - {}", new Object[]{requestId, requests.size(), externalRequest});
-        return externalRequest;
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardTargetIdRetriever.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardTargetIdRetriever.java
deleted file mode 100644
index e0ba56b..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/StandardTargetIdRetriever.java
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>This implementation retrieves the targetId from the request URI following this pattern:</p>
- * <pre>
- * /contextPath/servletPath/&lt;targetId&gt;/other/paths
- * </pre>
- * @version $Revision$ $Date$
- */
-public class StandardTargetIdRetriever implements TargetIdRetriever
-{
-    public String retrieveTargetId(HttpServletRequest httpRequest)
-    {
-        String uri = httpRequest.getRequestURI();
-        String path = uri.substring(httpRequest.getServletPath().length());
-        String[] segments = path.split("/");
-        if (segments.length < 2) return null;
-        return segments[1];
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/TargetIdRetriever.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/TargetIdRetriever.java
deleted file mode 100644
index 6502e4c..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/TargetIdRetriever.java
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>Implementations should retrieve a <em>targetId</em> from an external request.</p>
- * <p>Implementations of this class may return a fixed value, or inspect the request
- * looking for URL patterns (e.g. "/&lt;targetId&gt;/resource.jsp"), or looking for request
- * parameters (e.g. "/resource.jsp?targetId=&lt;targetId&gt;), or looking for virtual host
- * naming patterns (e.g. "http://&lt;targetId&gt;.host.com/resource.jsp"), etc.</p>
- *
- * @version $Revision$ $Date$
- */
-public interface TargetIdRetriever
-{
-    /**
-     * Extracts and returns the targetId.
-     * @param httpRequest the external request from where the targetId could be extracted
-     * @return the extracted targetId
-     */
-    public String retrieveTargetId(HttpServletRequest httpRequest);
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Utils.java b/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Utils.java
deleted file mode 100644
index 0aa1263..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/main/java/org/eclipse/jetty/rhttp/gateway/Utils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * @version $Revision$ $Date$
- */
-class Utils
-{
-    static byte[] read(InputStream input) throws IOException
-    {
-        ByteArrayOutputStream body = new ByteArrayOutputStream();
-        byte[] buffer = new byte[1024];
-        int read;
-        while ((read = input.read(buffer)) >= 0)
-            body.write(buffer, 0, read);
-        body.close();
-        return body.toByteArray();
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ClientTimeoutTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ClientTimeoutTest.java
deleted file mode 100644
index 307ffef..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ClientTimeoutTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.ClientListener;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardGateway;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class ClientTimeoutTest extends TestCase
-{
-    public void testClientTimeout() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        final long clientTimeout = 2000L;
-        server.getConnectorServlet().setInitParameter("clientTimeout",""+clientTimeout);
-        final long gatewayTimeout = 4000L;
-        ((StandardGateway)server.getGateway()).setGatewayTimeout(gatewayTimeout);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                String targetId = "1";
-                final RHTTPClient client = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId)
-                {
-                    private final AtomicInteger connects = new AtomicInteger();
-
-                    @Override
-                    protected void asyncConnect()
-                    {
-                        if (connects.incrementAndGet() == 2)
-                        {
-                            try
-                            {
-                                // Wait here instead of connecting, so that the client expires on the server
-                                Thread.sleep(clientTimeout * 2);
-                            }
-                            catch (InterruptedException x)
-                            {
-                                throw new RuntimeException(x);
-                            }
-                        }
-                        super.asyncConnect();
-                    }
-                };
-
-                final CountDownLatch connectLatch = new CountDownLatch(1);
-                client.addClientListener(new ClientListener.Adapter()
-                {
-                    @Override
-                    public void connectRequired()
-                    {
-                        connectLatch.countDown();
-                    }
-                });
-                client.connect();
-                try
-                {
-                    assertTrue(connectLatch.await(gatewayTimeout + clientTimeout * 3, TimeUnit.MILLISECONDS));
-                }
-                finally
-                {
-                    client.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DisconnectClientTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DisconnectClientTest.java
deleted file mode 100644
index b97b633..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DisconnectClientTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class DisconnectClientTest extends TestCase
-{
-    public void testDifferentClientDisconnects() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                final CountDownLatch latch = new CountDownLatch(1);
-                String targetId = "1";
-                final RHTTPClient client1 = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId)
-                {
-                    @Override
-                    protected void connectComplete(byte[] responseContent) throws IOException
-                    {
-                        // If the other client can disconnect this one, this method is called soon after it disconnected
-                        latch.countDown();
-                        super.connectComplete(responseContent);
-                    }
-                };
-                client1.connect();
-                try
-                {
-                    final RHTTPClient client2 = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                    // Disconnect client 2, this should not disconnect client1
-                    client2.disconnect();
-
-                    // We want the await() to expire, it means it has not disconnected
-                    assertFalse(latch.await(1000, TimeUnit.MILLISECONDS));
-                }
-                finally
-                {
-                    client1.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DuplicateClientTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DuplicateClientTest.java
deleted file mode 100644
index fd139c0..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/DuplicateClientTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class DuplicateClientTest extends TestCase
-{
-    public void testDuplicateClient() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                String targetId = "1";
-                final RHTTPClient client1 = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                client1.connect();
-                try
-                {
-                    final RHTTPClient client2 = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                    try
-                    {
-                        client2.connect();
-                        fail();
-                    }
-                    catch (IOException x)
-                    {
-                    }
-                }
-                finally
-                {
-                    client1.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalRequestNotSuspendedTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalRequestNotSuspendedTest.java
deleted file mode 100644
index f29f7f6..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalRequestNotSuspendedTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.rhttp.gateway.ExternalRequest;
-import org.eclipse.jetty.rhttp.gateway.Gateway;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardGateway;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class ExternalRequestNotSuspendedTest extends TestCase
-{
-    public void testExternalRequestNotSuspended() throws Exception
-    {
-        final CountDownLatch respondLatch = new CountDownLatch(1);
-        final CountDownLatch suspendLatch = new CountDownLatch(1);
-        final AtomicBoolean suspended = new AtomicBoolean(true);
-        GatewayServer server = new GatewayServer()
-        {
-            @Override
-            protected Gateway createGateway()
-            {
-                StandardGateway gateway = new StandardGateway()
-                {
-                    @Override
-                    public ExternalRequest newExternalRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
-                    {
-                        return new SlowToSuspendExternalRequest(super.newExternalRequest(httpRequest, httpResponse), respondLatch, suspendLatch, suspended);
-                    }
-                };
-                return gateway;
-            }
-        };
-        SelectChannelConnector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                String targetId = "1";
-                final RHTTPClient client = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                final AtomicReference<Exception> exception = new AtomicReference<Exception>();
-                client.addListener(new RHTTPListener()
-                {
-                    public void onRequest(RHTTPRequest request)
-                    {
-                        try
-                        {
-                            RHTTPResponse response = new RHTTPResponse(request.getId(), 200, "OK", new HashMap<String, String>(), request.getBody());
-                            client.deliver(response);
-                        }
-                        catch (Exception x)
-                        {
-                            exception.set(x);
-                        }
-                    }
-                });
-
-                client.connect();
-                try
-                {
-                    // Make a request to the gateway and check response
-                    ContentExchange exchange = new ContentExchange(true);
-                    exchange.setMethod(HttpMethods.POST);
-                    exchange.setAddress(address);
-                    exchange.setURI(server.getContext().getContextPath()+GatewayServer.DFT_EXT_PATH + "/" + URLEncoder.encode(targetId, "UTF-8"));
-                    String requestContent = "body";
-                    exchange.setRequestContent(new ByteArrayBuffer(requestContent.getBytes("UTF-8")));
-                    httpClient.send(exchange);
-
-                    int status = exchange.waitForDone();
-                    assertEquals(HttpExchange.STATUS_COMPLETED, status);
-                    assertEquals(HttpServletResponse.SC_OK, exchange.getResponseStatus());
-                    assertNull(exception.get());
-
-                    suspendLatch.await();
-                    assertFalse(suspended.get());
-                }
-                finally
-                {
-                    client.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-
-    private class SlowToSuspendExternalRequest implements ExternalRequest
-    {
-        private final ExternalRequest delegate;
-        private final CountDownLatch respondLatch;
-        private final CountDownLatch suspendLatch;
-        private final AtomicBoolean suspended;
-
-        private SlowToSuspendExternalRequest(ExternalRequest delegate, CountDownLatch respondLatch, CountDownLatch suspendLatch, AtomicBoolean suspended)
-        {
-            this.delegate = delegate;
-            this.respondLatch = respondLatch;
-            this.suspendLatch = suspendLatch;
-            this.suspended = suspended;
-        }
-
-        public boolean suspend()
-        {
-            try
-            {
-                respondLatch.await();
-                boolean result = delegate.suspend();
-                suspended.set(result);
-                suspendLatch.countDown();
-                return result;
-            }
-            catch (InterruptedException x)
-            {
-                throw new AssertionError(x);
-            }
-        }
-
-        public void respond(RHTTPResponse response) throws IOException
-        {
-            delegate.respond(response);
-            respondLatch.countDown();
-        }
-
-        public RHTTPRequest getRequest()
-        {
-            return delegate.getRequest();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalTimeoutTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalTimeoutTest.java
deleted file mode 100644
index 58c0a66..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/ExternalTimeoutTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardGateway;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class ExternalTimeoutTest extends TestCase
-{
-    public void testExternalTimeout() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        SelectChannelConnector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        final long externalTimeout = 5000L;
-        ((StandardGateway)server.getGateway()).setExternalTimeout(externalTimeout);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                String targetId = "1";
-                final RHTTPClient client = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                final AtomicReference<Integer> requestId = new AtomicReference<Integer>();
-                final AtomicReference<Exception> exceptionRef = new AtomicReference<Exception>();
-                client.addListener(new RHTTPListener()
-                {
-                    public void onRequest(RHTTPRequest request)
-                    {
-                        try
-                        {
-                            // Save the request id
-                            requestId.set(request.getId());
-
-                            // Wait until external timeout expires
-                            Thread.sleep(externalTimeout + 1000L);
-                            RHTTPResponse response = new RHTTPResponse(request.getId(), 200, "OK", new HashMap<String, String>(), request.getBody());
-                            client.deliver(response);
-                        }
-                        catch (Exception x)
-                        {
-                            exceptionRef.set(x);
-                        }
-                    }
-                });
-
-                client.connect();
-                try
-                {
-                    // Make a request to the gateway and check response
-                    ContentExchange exchange = new ContentExchange(true);
-                    exchange.setMethod(HttpMethods.POST);
-                    exchange.setAddress(address);
-                    exchange.setURI(server.getContext().getContextPath()+GatewayServer.DFT_EXT_PATH + "/" + URLEncoder.encode(targetId, "UTF-8"));
-                    String requestContent = "body";
-                    exchange.setRequestContent(new ByteArrayBuffer(requestContent.getBytes("UTF-8")));
-                    httpClient.send(exchange);
-
-                    int status = exchange.waitForDone();
-                    assertEquals(HttpExchange.STATUS_COMPLETED, status);
-                    assertEquals(HttpServletResponse.SC_GATEWAY_TIMEOUT, exchange.getResponseStatus());
-                    assertNull(exceptionRef.get());
-
-                    assertNull(server.getGateway().removeExternalRequest(requestId.get()));
-                }
-                finally
-                {
-                    client.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoServer.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoServer.java
deleted file mode 100644
index cc62bbc..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoServer.java
+++ /dev/null
@@ -1,109 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.util.HashMap;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.TargetIdRetriever;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class GatewayEchoServer
-{
-    private volatile GatewayServer server;
-    private volatile Address address;
-    private volatile String uri;
-    private volatile HttpClient httpClient;
-    private volatile RHTTPClient client;
-
-    public void start() throws Exception
-    {
-        server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        server.setTargetIdRetriever(new EchoTargetIdRetriever());
-        server.start();
-        server.dumpStdErr();
-        address = new Address("localhost", connector.getLocalPort());
-        uri = server.getContext().getContextPath()+GatewayServer.DFT_EXT_PATH;
-
-        httpClient = new HttpClient();
-        httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-        httpClient.start();
-
-        client = new JettyClient(httpClient, new Address("localhost", connector.getLocalPort()), server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, "echo");
-        client.addListener(new EchoListener(client));
-        client.connect();
-    }
-
-    public void stop() throws Exception
-    {
-        client.disconnect();
-        httpClient.stop();
-        server.stop();
-    }
-
-    public Address getAddress()
-    {
-        return address;
-    }
-
-    public String getURI()
-    {
-        return uri;
-    }
-
-    public static class EchoTargetIdRetriever implements TargetIdRetriever
-    {
-        public String retrieveTargetId(HttpServletRequest httpRequest)
-        {
-            return "echo";
-        }
-    }
-
-    private static class EchoListener implements RHTTPListener
-    {
-        private final RHTTPClient client;
-
-        public EchoListener(RHTTPClient client)
-        {
-            this.client = client;
-        }
-
-        public void onRequest(RHTTPRequest request) throws Exception
-        {
-            RHTTPResponse response = new RHTTPResponse(request.getId(), 200, "OK", new HashMap<String, String>(), request.getBody());
-            client.deliver(response);
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoTest.java
deleted file mode 100644
index 956fbe9..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayEchoTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-
-/**
- * @version $Revision$ $Date$
- */
-public class GatewayEchoTest extends TestCase
-{
-    /**
-     * Tests that the basic functionality of the gateway works,
-     * by issuing a request and by replying with the same body.
-     *
-     * @throws Exception in case of test exceptions
-     */
-    public void testEcho() throws Exception
-    {
-        GatewayEchoServer server = new GatewayEchoServer();
-        server.start();
-        try
-        {
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                // Make a request to the gateway and check response
-                ContentExchange exchange = new ContentExchange(true);
-                exchange.setMethod(HttpMethods.POST);
-                exchange.setAddress(server.getAddress());
-                exchange.setURI(server.getURI() + "/");
-                String requestBody = "body";
-                exchange.setRequestContent(new ByteArrayBuffer(requestBody.getBytes("UTF-8")));
-                httpClient.send(exchange);
-                int status = exchange.waitForDone();
-                assertEquals(HttpExchange.STATUS_COMPLETED, status);
-                assertEquals(HttpServletResponse.SC_OK, exchange.getResponseStatus());
-                String responseContent = exchange.getResponseContent();
-                assertEquals(responseContent, requestBody);
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayLoadTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayLoadTest.java
deleted file mode 100644
index 84c9042..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayLoadTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-
-/**
- * @version $Revision$ $Date$
- */
-public class GatewayLoadTest extends TestCase
-{
-    private final ConcurrentMap<Long, AtomicLong> latencies = new ConcurrentHashMap<Long, AtomicLong>();
-    private final AtomicLong responses = new AtomicLong(0L);
-    private final AtomicLong failures = new AtomicLong(0L);
-    private final AtomicLong minLatency = new AtomicLong(Long.MAX_VALUE);
-    private final AtomicLong maxLatency = new AtomicLong(0L);
-    private final AtomicLong totLatency = new AtomicLong(0L);
-
-    public void testEcho() throws Exception
-    {
-        GatewayEchoServer server = new GatewayEchoServer();
-        server.start();
-
-        HttpClient httpClient = new HttpClient();
-        httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-        httpClient.start();
-
-        String uri = server.getURI() + "/";
-
-        char[] chars = new char[1024];
-        Arrays.fill(chars, 'x');
-        String requestBody = new String(chars);
-
-        int count = 1000;
-        CountDownLatch latch = new CountDownLatch(count);
-        for (int i = 0; i < count; ++i)
-        {
-            GatewayLoadTestExchange exchange = new GatewayLoadTestExchange(latch);
-            exchange.setMethod(HttpMethods.POST);
-            exchange.setAddress(server.getAddress());
-            exchange.setURI(uri + i);
-            exchange.setRequestContent(new ByteArrayBuffer(requestBody.getBytes("UTF-8")));
-            exchange.setStartNanos(System.nanoTime());
-            httpClient.send(exchange);
-            Thread.sleep(5);
-        }
-        latch.await();
-        printLatencies(count);
-        assertEquals(count, responses.get() + failures.get());
-    }
-
-    private void updateLatencies(long start, long end)
-    {
-        long latency = end - start;
-
-        // Update the latencies using a non-blocking algorithm
-        long oldMinLatency = minLatency.get();
-        while (latency < oldMinLatency)
-        {
-            if (minLatency.compareAndSet(oldMinLatency, latency)) break;
-            oldMinLatency = minLatency.get();
-        }
-        long oldMaxLatency = maxLatency.get();
-        while (latency > oldMaxLatency)
-        {
-            if (maxLatency.compareAndSet(oldMaxLatency, latency)) break;
-            oldMaxLatency = maxLatency.get();
-        }
-        totLatency.addAndGet(latency);
-
-        latencies.putIfAbsent(latency, new AtomicLong(0L));
-        latencies.get(latency).incrementAndGet();
-    }
-
-    public void printLatencies(long expectedCount)
-    {
-        if (latencies.size() > 1)
-        {
-            long maxLatencyBucketFrequency = 0L;
-            long[] latencyBucketFrequencies = new long[20];
-            long latencyRange = maxLatency.get() - minLatency.get();
-            for (Iterator<Map.Entry<Long, AtomicLong>> entries = latencies.entrySet().iterator(); entries.hasNext();)
-            {
-                Map.Entry<Long, AtomicLong> entry = entries.next();
-                long latency = entry.getKey();
-                Long bucketIndex = (latency - minLatency.get()) * latencyBucketFrequencies.length / latencyRange;
-                int index = bucketIndex.intValue() == latencyBucketFrequencies.length ? latencyBucketFrequencies.length - 1 : bucketIndex.intValue();
-                long value = entry.getValue().get();
-                latencyBucketFrequencies[index] += value;
-                if (latencyBucketFrequencies[index] > maxLatencyBucketFrequency) maxLatencyBucketFrequency = latencyBucketFrequencies[index];
-                entries.remove();
-            }
-
-            System.out.println("Messages - Latency Distribution Curve (X axis: Frequency, Y axis: Latency):");
-            for (int i = 0; i < latencyBucketFrequencies.length; i++)
-            {
-                long latencyBucketFrequency = latencyBucketFrequencies[i];
-                int value = Math.round(latencyBucketFrequency * (float) latencyBucketFrequencies.length / maxLatencyBucketFrequency);
-                if (value == latencyBucketFrequencies.length) value = value - 1;
-                for (int j = 0; j < value; ++j) System.out.print(" ");
-                System.out.print("@");
-                for (int j = value + 1; j < latencyBucketFrequencies.length; ++j) System.out.print(" ");
-                System.out.print("  _  ");
-                System.out.print(TimeUnit.NANOSECONDS.toMillis((latencyRange * (i + 1) / latencyBucketFrequencies.length) + minLatency.get()));
-                System.out.print(" (" + latencyBucketFrequency + ")");
-                System.out.println(" ms");
-            }
-        }
-
-        long responseCount = responses.get();
-        System.out.print("Messages success/failed/expected = ");
-        System.out.print(responseCount);
-        System.out.print("/");
-        System.out.print(failures.get());
-        System.out.print("/");
-        System.out.print(expectedCount);
-        System.out.print(" - Latency min/ave/max = ");
-        System.out.print(TimeUnit.NANOSECONDS.toMillis(minLatency.get()) + "/");
-        System.out.print(responseCount == 0 ? "-/" : TimeUnit.NANOSECONDS.toMillis(totLatency.get() / responseCount) + "/");
-        System.out.println(TimeUnit.NANOSECONDS.toMillis(maxLatency.get()) + " ms");
-    }
-
-    private class GatewayLoadTestExchange extends ContentExchange
-    {
-        private final CountDownLatch latch;
-        private volatile long start;
-
-        private GatewayLoadTestExchange(CountDownLatch latch)
-        {
-            super(true);
-            this.latch = latch;
-        }
-
-        @Override
-        protected void onResponseComplete() throws IOException
-        {
-            if (getResponseStatus() == HttpServletResponse.SC_OK)
-            {
-                long end = System.nanoTime();
-                responses.incrementAndGet();
-                updateLatencies(start, end);
-            }
-            else
-            {
-                failures.incrementAndGet();
-            }
-            latch.countDown();
-        }
-
-        @Override
-        protected void onException(Throwable throwable)
-        {
-            failures.incrementAndGet();
-            latch.countDown();
-        }
-
-        @Override
-        protected void onExpire()
-        {
-            failures.incrementAndGet();
-            latch.countDown();
-        }
-
-        public void setStartNanos(long value)
-        {
-            start = value;
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayTimeoutTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayTimeoutTest.java
deleted file mode 100644
index a075ccb..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/GatewayTimeoutTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.servlet.http.HttpServletResponse;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.http.HttpMethods;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.client.RHTTPListener;
-import org.eclipse.jetty.rhttp.client.RHTTPRequest;
-import org.eclipse.jetty.rhttp.client.RHTTPResponse;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardGateway;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class GatewayTimeoutTest extends TestCase
-{
-    /**
-     * Tests a forwarded request that lasts longer than the gateway timeout.
-     * The gateway client will perform 2 long polls before the forwarded request's response is returned.
-     *
-     * @throws Exception in case of test exceptions
-     */
-    public void testGatewayTimeout() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        final long gatewayTimeout = 5000L;
-        ((StandardGateway)server.getGateway()).setGatewayTimeout(gatewayTimeout);
-        final long externalTimeout = gatewayTimeout * 2;
-        ((StandardGateway)server.getGateway()).setExternalTimeout(externalTimeout);
-        server.start();
-        try
-        {
-            Address address = new Address("localhost", connector.getLocalPort());
-
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                String targetId = "1";
-                final RHTTPClient client = new JettyClient(httpClient, address, server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, targetId);
-                final AtomicReference<Exception> exceptionRef = new AtomicReference<Exception>();
-                client.addListener(new RHTTPListener()
-                {
-                    public void onRequest(RHTTPRequest request)
-                    {
-                        try
-                        {
-                            // Wait until gateway timeout expires
-                            Thread.sleep(gatewayTimeout + 1000L);
-                            RHTTPResponse response = new RHTTPResponse(request.getId(), 200, "OK", new HashMap<String, String>(), request.getBody());
-                            client.deliver(response);
-                        }
-                        catch (Exception x)
-                        {
-                            exceptionRef.set(x);
-                        }
-                    }
-                });
-                client.connect();
-                try
-                {
-                    // Make a request to the gateway and check response
-                    ContentExchange exchange = new ContentExchange(true);
-                    exchange.setMethod(HttpMethods.POST);
-                    exchange.setAddress(address);
-                    exchange.setURI(server.getContext().getContextPath()+GatewayServer.DFT_EXT_PATH + "/" + URLEncoder.encode(targetId, "UTF-8"));
-                    String requestContent = "body";
-                    exchange.setRequestContent(new ByteArrayBuffer(requestContent.getBytes("UTF-8")));
-                    httpClient.send(exchange);
-
-                    int status = exchange.waitForDone();
-                    assertEquals(HttpExchange.STATUS_COMPLETED, status);
-                    assertEquals(HttpServletResponse.SC_OK, exchange.getResponseStatus());
-                    assertNull(exceptionRef.get());
-                    String responseContent = exchange.getResponseContent();
-                    assertEquals(responseContent, requestContent);
-                }
-                finally
-                {
-                    client.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HandshakeClientTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HandshakeClientTest.java
deleted file mode 100644
index 463a2a3..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HandshakeClientTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import junit.framework.TestCase;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.rhttp.client.JettyClient;
-import org.eclipse.jetty.rhttp.client.RHTTPClient;
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardGateway;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-
-/**
- * @version $Revision$ $Date$
- */
-public class HandshakeClientTest extends TestCase
-{
-    public void testConnectReturnsImmediately() throws Exception
-    {
-        GatewayServer server = new GatewayServer();
-        SelectChannelConnector connector = new SelectChannelConnector();
-        server.addConnector(connector);
-        long gwt=5000L;
-        ((StandardGateway)server.getGateway()).setGatewayTimeout(gwt);
-        server.start();
-        try
-        {
-            HttpClient httpClient = new HttpClient();
-            httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
-            httpClient.start();
-            try
-            {
-                RHTTPClient client = new JettyClient(httpClient, new Address("localhost", connector.getLocalPort()), server.getContext().getContextPath()+GatewayServer.DFT_CONNECT_PATH, "test1");
-                long start = System.currentTimeMillis();
-                client.connect();
-                try
-                {
-                    long end = System.currentTimeMillis();
-                    assertTrue(end - start < gwt / 2);
-                }
-                finally
-                {
-                    client.disconnect();
-                }
-            }
-            finally
-            {
-                httpClient.stop();
-            }
-        }
-        finally
-        {
-            server.stop();
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetrieverTest.java b/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetrieverTest.java
deleted file mode 100644
index e5e7aa2..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/java/org/eclipse/jetty/rhttp/gateway/HostTargetIdRetrieverTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.gateway;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.eclipse.jetty.rhttp.gateway.HostTargetIdRetriever;
-
-import junit.framework.TestCase;
-
-/**
- * @version $Revision$ $Date$
- */
-public class HostTargetIdRetrieverTest extends TestCase
-{
-    public void testHostTargetIdRetrieverNoSuffix()
-    {
-        String host = "test";
-        Class<HttpServletRequest> klass = HttpServletRequest.class;
-        HttpServletRequest request = (HttpServletRequest)Proxy.newProxyInstance(klass.getClassLoader(), new Class<?>[]{klass}, new Request(host));
-
-        HostTargetIdRetriever retriever = new HostTargetIdRetriever(null);
-        String result = retriever.retrieveTargetId(request);
-
-        assertEquals(host, result);
-    }
-
-    public void testHostTargetIdRetrieverWithSuffix()
-    {
-        String suffix = ".rhttp.example.com";
-        String host = "test";
-        Class<HttpServletRequest> klass = HttpServletRequest.class;
-        HttpServletRequest request = (HttpServletRequest)Proxy.newProxyInstance(klass.getClassLoader(), new Class<?>[]{klass}, new Request(host + suffix));
-
-        HostTargetIdRetriever retriever = new HostTargetIdRetriever(suffix);
-        String result = retriever.retrieveTargetId(request);
-
-        assertEquals(host, result);
-    }
-
-    public void testHostTargetIdRetrieverWithSuffixAndPort()
-    {
-        String suffix = ".rhttp.example.com";
-        String host = "test";
-        Class<HttpServletRequest> klass = HttpServletRequest.class;
-        HttpServletRequest request = (HttpServletRequest)Proxy.newProxyInstance(klass.getClassLoader(), new Class<?>[]{klass}, new Request(host + suffix + ":8080"));
-
-        HostTargetIdRetriever retriever = new HostTargetIdRetriever(suffix);
-        String result = retriever.retrieveTargetId(request);
-
-        assertEquals(host, result);
-    }
-
-    public void testHostTargetIdRetrieverNullHost()
-    {
-        Class<HttpServletRequest> klass = HttpServletRequest.class;
-        HttpServletRequest request = (HttpServletRequest)Proxy.newProxyInstance(klass.getClassLoader(), new Class<?>[]{klass}, new Request(null));
-
-        HostTargetIdRetriever retriever = new HostTargetIdRetriever(".rhttp.example.com");
-        String result = retriever.retrieveTargetId(request);
-
-        assertNull(result);
-    }
-
-    private static class Request implements InvocationHandler
-    {
-        private final String host;
-
-        private Request(String host)
-        {
-            this.host = host;
-        }
-
-        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
-        {
-            if ("getHeader".equals(method.getName()))
-            {
-                if (args.length == 1 && "Host".equals(args[0]))
-                {
-                    return host;
-                }
-            }
-            return null;
-        }
-    }
-
-}
diff --git a/jetty-rhttp/jetty-rhttp-gateway/src/test/resources/log4j.properties b/jetty-rhttp/jetty-rhttp-gateway/src/test/resources/log4j.properties
deleted file mode 100644
index 8e6eddb..0000000
--- a/jetty-rhttp/jetty-rhttp-gateway/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# LOG4J levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL
-#
-log4j.rootLogger=ALL,CONSOLE
-
-log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
-#log4j.appender.CONSOLE.threshold=INFO
-log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
-#log4j.appender.CONSOLE.layout.ConversionPattern=%d %t [%5p][%c{1}] %m%n
-log4j.appender.CONSOLE.layout.ConversionPattern=%d [%5p][%c] %m%n
-
-# Level tuning
-log4j.logger.org.eclipse.jetty=INFO
-log4j.logger.org.mortbay.jetty.rhttp=INFO
diff --git a/jetty-rhttp/jetty-rhttp-loadtest/pom.xml b/jetty-rhttp/jetty-rhttp-loadtest/pom.xml
deleted file mode 100644
index bd36d4e..0000000
--- a/jetty-rhttp/jetty-rhttp-loadtest/pom.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.rhttp</groupId>
-        <artifactId>jetty-rhttp-project</artifactId>
-        <version>9.0.0-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>reverse-http-loadtest</artifactId>
-    <packaging>jar</packaging>
-    <name>Jetty :: Reverse HTTP :: Load Test</name>
-
-    <profiles>
-        <profile>
-            <id>loader</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <configuration>
-                            <mainClass>org.eclipse.jetty.rhttp.loadtest.Loader</mainClass>
-                            <classpathScope>runtime</classpathScope>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-        <profile>
-            <id>server</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <configuration>
-                            <mainClass>org.eclipse.jetty.rhttp.loadtest.Server</mainClass>
-                            <classpathScope>runtime</classpathScope>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>reverse-http-gateway</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Loader.java b/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Loader.java
deleted file mode 100644
index c65fbc7..0000000
--- a/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Loader.java
+++ /dev/null
@@ -1,429 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.loadtest;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.eclipse.jetty.client.Address;
-import org.eclipse.jetty.client.ContentExchange;
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.io.ByteArrayBuffer;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.mortbay.jetty.rhttp.client.RHTTPClient;
-import org.mortbay.jetty.rhttp.client.JettyClient;
-import org.mortbay.jetty.rhttp.client.RHTTPListener;
-import org.mortbay.jetty.rhttp.client.RHTTPRequest;
-import org.mortbay.jetty.rhttp.client.RHTTPResponse;
-
-/**
- * @version $Revision$ $Date$
- */
-public class Loader
-{
-    private final List<RHTTPClient> clients = new ArrayList<RHTTPClient>();
-    private final AtomicLong start = new AtomicLong();
-    private final AtomicLong end = new AtomicLong();
-    private final AtomicLong responses = new AtomicLong();
-    private final AtomicLong failures = new AtomicLong();
-    private final AtomicLong minLatency = new AtomicLong();
-    private final AtomicLong maxLatency = new AtomicLong();
-    private final AtomicLong totLatency = new AtomicLong();
-    private final ConcurrentMap<Long, AtomicLong> latencies = new ConcurrentHashMap<Long, AtomicLong>();
-    private final String nodeName;
-
-    public static void main(String[] args) throws Exception
-    {
-        String nodeName = "";
-        if (args.length > 0)
-            nodeName = args[0];
-
-        Loader loader = new Loader(nodeName);
-        loader.run();
-    }
-
-    public Loader(String nodeName)
-    {
-        this.nodeName = nodeName;
-    }
-
-    private void run() throws Exception
-    {
-        HttpClient httpClient = new HttpClient();
-        httpClient.setMaxConnectionsPerAddress(40000);
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setMaxThreads(500);
-        threadPool.setDaemon(true);
-        httpClient.setThreadPool(threadPool);
-        httpClient.setIdleTimeout(5000);
-        httpClient.start();
-
-        Random random = new Random();
-
-        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
-
-        System.err.print("server [localhost]: ");
-        String value = console.readLine().trim();
-        if (value.length() == 0)
-            value = "localhost";
-        String host = value;
-
-        System.err.print("port [8080]: ");
-        value = console.readLine().trim();
-        if (value.length() == 0)
-            value = "8080";
-        int port = Integer.parseInt(value);
-
-        System.err.print("context []: ");
-        value = console.readLine().trim();
-        if (value.length() == 0)
-            value = "";
-        String context = value;
-
-        System.err.print("external path [/]: ");
-        value = console.readLine().trim();
-        if (value.length() == 0)
-            value = "/";
-        String externalPath = value;
-
-        System.err.print("gateway path [/__gateway]: ");
-        value = console.readLine().trim();
-        if (value.length() == 0)
-            value = "/__gateway";
-        String gatewayPath = value;
-
-        int clients = 100;
-        int batchCount = 1000;
-        int batchSize = 5;
-        long batchPause = 5;
-        int requestSize = 50;
-
-        while (true)
-        {
-            System.err.println("-----");
-
-            System.err.print("clients [" + clients + "]: ");
-            value = console.readLine();
-            if (value == null)
-                break;
-            value = value.trim();
-            if (value.length() == 0)
-                value = "" + clients;
-            clients = Integer.parseInt(value);
-
-            System.err.println("Waiting for clients to be ready...");
-
-            Address gatewayAddress = new Address(host, port);
-            String gatewayURI = context + gatewayPath;
-
-            // Create or remove the necessary clients
-            int currentClients = this.clients.size();
-            if (currentClients < clients)
-            {
-                for (int i = 0; i < clients - currentClients; ++i)
-                {
-                    final RHTTPClient client = new JettyClient(httpClient, gatewayAddress, gatewayURI, nodeName + (currentClients + i));
-                    client.addListener(new EchoListener(client));
-                    client.connect();
-                    this.clients.add(client);
-
-                    // Give some time to the server to accept connections and
-                    // reply to handshakes and connects
-                    if (i % 10 == 0)
-                    {
-                        Thread.sleep(100);
-                    }
-                }
-            }
-            else if (currentClients > clients)
-            {
-                for (int i = 0; i < currentClients - clients; ++i)
-                {
-                    RHTTPClient client = this.clients.remove(currentClients - i - 1);
-                    client.disconnect();
-                }
-            }
-
-            System.err.println("Clients ready");
-
-            currentClients = this.clients.size();
-            if (currentClients > 0)
-            {
-                System.err.print("batch count [" + batchCount + "]: ");
-                value = console.readLine().trim();
-                if (value.length() == 0)
-                    value = "" + batchCount;
-                batchCount = Integer.parseInt(value);
-
-                System.err.print("batch size [" + batchSize + "]: ");
-                value = console.readLine().trim();
-                if (value.length() == 0)
-                    value = "" + batchSize;
-                batchSize = Integer.parseInt(value);
-
-                System.err.print("batch pause [" + batchPause + "]: ");
-                value = console.readLine().trim();
-                if (value.length() == 0)
-                    value = "" + batchPause;
-                batchPause = Long.parseLong(value);
-
-                System.err.print("request size [" + requestSize + "]: ");
-                value = console.readLine().trim();
-                if (value.length() == 0)
-                    value = "" + requestSize;
-                requestSize = Integer.parseInt(value);
-                String requestBody = "";
-                for (int i = 0; i < requestSize; i++)
-                    requestBody += "x";
-
-                String externalURL = "http://" + host + ":" + port + context + externalPath;
-                if (!externalURL.endsWith("/"))
-                    externalURL += "/";
-
-                reset();
-
-                long start = System.nanoTime();
-                long expected = 0;
-                for (int i = 0; i < batchCount; ++i)
-                {
-                    for (int j = 0; j < batchSize; ++j)
-                    {
-                        int clientIndex = random.nextInt(this.clients.size());
-                        RHTTPClient client = this.clients.get(clientIndex);
-                        String targetId = client.getTargetId();
-                        String url = externalURL + targetId;
-
-                        ExternalExchange exchange = new ExternalExchange();
-                        exchange.setMethod("GET");
-                        exchange.setURL(url);
-                        exchange.setRequestContent(new ByteArrayBuffer(requestBody, "UTF-8"));
-                        exchange.send(httpClient);
-                        ++expected;
-                    }
-
-                    if (batchPause > 0)
-                        Thread.sleep(batchPause);
-                }
-                long end = System.nanoTime();
-                long elapsedNanos = end - start;
-                if (elapsedNanos > 0)
-                {
-                    System.err.print("Messages - Elapsed | Rate = ");
-                    System.err.print(TimeUnit.NANOSECONDS.toMillis(elapsedNanos));
-                    System.err.print(" ms | ");
-                    System.err.print(expected * 1000 * 1000 * 1000 / elapsedNanos);
-                    System.err.println(" requests/s ");
-                }
-
-                waitForResponses(expected);
-                printReport(expected);
-            }
-        }
-    }
-
-    private void reset()
-    {
-        start.set(0L);
-        end.set(0L);
-        responses.set(0L);
-        failures.set(0L);
-        minLatency.set(Long.MAX_VALUE);
-        maxLatency.set(0L);
-        totLatency.set(0L);
-    }
-
-    private void updateLatencies(long start, long end)
-    {
-        long latency = end - start;
-
-        // Update the latencies using a non-blocking algorithm
-        long oldMinLatency = minLatency.get();
-        while (latency < oldMinLatency)
-        {
-            if (minLatency.compareAndSet(oldMinLatency, latency)) break;
-            oldMinLatency = minLatency.get();
-        }
-        long oldMaxLatency = maxLatency.get();
-        while (latency > oldMaxLatency)
-        {
-            if (maxLatency.compareAndSet(oldMaxLatency, latency)) break;
-            oldMaxLatency = maxLatency.get();
-        }
-        totLatency.addAndGet(latency);
-
-        latencies.putIfAbsent(latency, new AtomicLong(0L));
-        latencies.get(latency).incrementAndGet();
-    }
-
-    private boolean waitForResponses(long expected) throws InterruptedException
-    {
-        long arrived = responses.get() + failures.get();
-        long lastArrived = 0;
-        int maxRetries = 20;
-        int retries = maxRetries;
-        while (arrived < expected)
-        {
-            System.err.println("Waiting for responses to arrive " + arrived + "/" + expected);
-            Thread.sleep(500);
-            if (lastArrived == arrived)
-            {
-                --retries;
-                if (retries == 0) break;
-            }
-            else
-            {
-                lastArrived = arrived;
-                retries = maxRetries;
-            }
-            arrived = responses.get() + failures.get();
-        }
-        if (arrived < expected)
-        {
-            System.err.println("Interrupting wait for responses " + arrived + "/" + expected);
-            return false;
-        }
-        else
-        {
-            System.err.println("All responses arrived " + arrived + "/" + expected);
-            return true;
-        }
-    }
-
-    public void printReport(long expectedCount)
-    {
-        long responseCount = responses.get() + failures.get();
-        System.err.print("Messages - Success/Failures/Expected = ");
-        System.err.print(responses.get());
-        System.err.print("/");
-        System.err.print(failures.get());
-        System.err.print("/");
-        System.err.println(expectedCount);
-
-        long elapsedNanos = end.get() - start.get();
-        if (elapsedNanos > 0)
-        {
-            System.err.print("Messages - Elapsed | Rate = ");
-            System.err.print(TimeUnit.NANOSECONDS.toMillis(elapsedNanos));
-            System.err.print(" ms | ");
-            System.err.print(responseCount * 1000 * 1000 * 1000 / elapsedNanos);
-            System.err.println(" responses/s ");
-        }
-
-        if (latencies.size() > 1)
-        {
-            long maxLatencyBucketFrequency = 0L;
-            long[] latencyBucketFrequencies = new long[20];
-            long latencyRange = maxLatency.get() - minLatency.get();
-            for (Iterator<Map.Entry<Long, AtomicLong>> entries = latencies.entrySet().iterator(); entries.hasNext();)
-            {
-                Map.Entry<Long, AtomicLong> entry = entries.next();
-                long latency = entry.getKey();
-                Long bucketIndex = (latency - minLatency.get()) * latencyBucketFrequencies.length / latencyRange;
-                int index = bucketIndex.intValue() == latencyBucketFrequencies.length ? latencyBucketFrequencies.length - 1 : bucketIndex.intValue();
-                long value = entry.getValue().get();
-                latencyBucketFrequencies[index] += value;
-                if (latencyBucketFrequencies[index] > maxLatencyBucketFrequency) maxLatencyBucketFrequency = latencyBucketFrequencies[index];
-                entries.remove();
-            }
-
-            System.err.println("Messages - Latency Distribution Curve (X axis: Frequency, Y axis: Latency):");
-            for (int i = 0; i < latencyBucketFrequencies.length; i++)
-            {
-                long latencyBucketFrequency = latencyBucketFrequencies[i];
-                int value = Math.round(latencyBucketFrequency * (float) latencyBucketFrequencies.length / maxLatencyBucketFrequency);
-                if (value == latencyBucketFrequencies.length) value = value - 1;
-                for (int j = 0; j < value; ++j) System.err.print(" ");
-                System.err.print("@");
-                for (int j = value + 1; j < latencyBucketFrequencies.length; ++j) System.err.print(" ");
-                System.err.print("  _  ");
-                System.err.print(TimeUnit.NANOSECONDS.toMillis((latencyRange * (i + 1) / latencyBucketFrequencies.length) + minLatency.get()));
-                System.err.println(" ms (" + latencyBucketFrequency + ")");
-            }
-        }
-
-        System.err.print("Messages - Latency Min/Ave/Max = ");
-        System.err.print(TimeUnit.NANOSECONDS.toMillis(minLatency.get()) + "/");
-        System.err.print(responseCount == 0 ? "-/" : TimeUnit.NANOSECONDS.toMillis(totLatency.get() / responseCount) + "/");
-        System.err.println(TimeUnit.NANOSECONDS.toMillis(maxLatency.get()) + " ms");
-    }
-
-    private class ExternalExchange extends ContentExchange
-    {
-        private volatile long sendTime;
-
-        private ExternalExchange()
-        {
-            super(true);
-        }
-
-        private void send(HttpClient httpClient) throws IOException
-        {
-            this.sendTime = System.nanoTime();
-            httpClient.send(this);
-        }
-
-        @Override
-        protected void onResponseComplete() throws IOException
-        {
-            if (getResponseStatus() == 200)
-                responses.incrementAndGet();
-            else
-                failures.incrementAndGet();
-
-            long arrivalTime = System.nanoTime();
-            if (start.get() == 0L)
-                start.set(arrivalTime);
-            end.set(arrivalTime);
-            updateLatencies(sendTime, arrivalTime);
-        }
-
-        @Override
-        protected void onException(Throwable x)
-        {
-            failures.incrementAndGet();
-        }
-    }
-
-    private static class EchoListener implements RHTTPListener
-    {
-        private final RHTTPClient client;
-
-        public EchoListener(RHTTPClient client)
-        {
-            this.client = client;
-        }
-
-        public void onRequest(RHTTPRequest request) throws Exception
-        {
-            RHTTPResponse response = new RHTTPResponse(request.getId(), 200, "OK", new HashMap<String, String>(), request.getBody());
-            client.deliver(response);
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Server.java b/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Server.java
deleted file mode 100644
index 181beb5..0000000
--- a/jetty-rhttp/jetty-rhttp-loadtest/src/main/java/org/eclipse/jetty/rhttp/loadtest/Server.java
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.rhttp.loadtest;
-
-import org.eclipse.jetty.rhttp.gateway.GatewayServer;
-import org.eclipse.jetty.rhttp.gateway.StandardTargetIdRetriever;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.nio.SelectChannelConnector;
-
-/**
- * @version $Revision$ $Date$
- */
-public class Server
-{
-    public static void main(String[] args) throws Exception
-    {
-        int port = 8080;
-        if (args.length > 0)
-            port = Integer.parseInt(args[0]);
-
-        GatewayServer server = new GatewayServer();
-        Connector connector = new SelectChannelConnector();
-        connector.setLowResourceMaxIdleTime(connector.getMaxIdleTime());
-        connector.setPort(port);
-        server.addConnector(connector);
-        server.setTargetIdRetriever(new StandardTargetIdRetriever());
-        server.start();
-        server.getServer().dumpStdErr();
-        Runtime.getRuntime().addShutdownHook(new Shutdown(server));
-    }
-
-    private static class Shutdown extends Thread
-    {
-        private final GatewayServer server;
-
-        public Shutdown(GatewayServer server)
-        {
-            this.server = server;
-        }
-
-        @Override
-        public void run()
-        {
-            try
-            {
-                server.stop();
-            }
-            catch (Exception ignored)
-            {
-            }
-        }
-    }
-}
diff --git a/jetty-rhttp/jetty-rhttp-loadtest/src/main/resources/log4j.properties b/jetty-rhttp/jetty-rhttp-loadtest/src/main/resources/log4j.properties
deleted file mode 100644
index 8e6eddb..0000000
--- a/jetty-rhttp/jetty-rhttp-loadtest/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# LOG4J levels: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL
-#
-log4j.rootLogger=ALL,CONSOLE
-
-log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
-#log4j.appender.CONSOLE.threshold=INFO
-log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
-#log4j.appender.CONSOLE.layout.ConversionPattern=%d %t [%5p][%c{1}] %m%n
-log4j.appender.CONSOLE.layout.ConversionPattern=%d [%5p][%c] %m%n
-
-# Level tuning
-log4j.logger.org.eclipse.jetty=INFO
-log4j.logger.org.mortbay.jetty.rhttp=INFO
diff --git a/jetty-rhttp/pom.xml b/jetty-rhttp/pom.xml
deleted file mode 100644
index 0284a0f..0000000
--- a/jetty-rhttp/pom.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-project</artifactId>
-        <version>9.0.0-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.eclipse.jetty.rhttp</groupId>
-    <artifactId>jetty-rhttp-project</artifactId>
-    <packaging>pom</packaging>
-    <name>Jetty :: Reverse HTTP</name>
-
-    <properties>
-    </properties>
-
-    <modules>
-        <module>reverse-http-client</module>
-        <module>reverse-http-connector</module>
-        <module>reverse-http-gateway</module>
-        <module>reverse-http-loadtest</module>
-    </modules>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.sonatype.maven.plugin</groupId>
-                <artifactId>emma-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>process-classes</phase>
-                        <goals>
-                            <goal>instrument</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <classesDirectory>${project.build.directory}/generated-classes/emma/classes</classesDirectory>
-                    <systemProperties>
-                        <property>
-                            <name>emma.coverage.out.file</name>
-                            <value>${project.build.directory}/coverage.ec</value>
-                        </property>
-                    </systemProperties>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.sonatype.maven.plugin</groupId>
-                <artifactId>emma4it-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>report</id>
-                        <phase>post-integration-test</phase>
-                        <goals>
-                            <goal>report</goal>
-                        </goals>
-                        <configuration>
-                            <sourceSets>
-                                <sourceSet>
-                                    <directory>${project.build.sourceDirectory}</directory>
-                                </sourceSet>
-                            </sourceSets>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>javax.servlet</groupId>
-                <artifactId>servlet-api</artifactId>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.jetty</groupId>
-                <artifactId>jetty-server</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.jetty</groupId>
-                <artifactId>jetty-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.jetty</groupId>
-                <artifactId>jetty-io</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.jetty</groupId>
-                <artifactId>jetty-util</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.eclipse.jetty.toolchain</groupId>
-                <artifactId>jetty-test-helper</artifactId>
-                <scope>test</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-</project>
diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml
index ef23d56..7b449d9 100644
--- a/jetty-runner/pom.xml
+++ b/jetty-runner/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-runner</artifactId>
@@ -10,17 +10,19 @@
 
  <properties>
     <assembly-directory>target/distribution</assembly-directory>
+    <bundle-symbolic-name>${project.groupId}.runner</bundle-symbolic-name>
   </properties>
   <url>http://www.eclipse.org/jetty</url>
   <build>
     <plugins>
+
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <executions>
           <execution>
             <id>unpack-dependencies</id>
-            <phase>package</phase>
+            <phase>prepare-package</phase>
             <goals>
               <goal>unpack-dependencies</goal>
             </goals>
@@ -35,33 +37,32 @@
         </executions>
       </plugin>
       <plugin>
-        <groupId>org.apache.maven.plugins
-        </groupId>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>maven-bundle-plugin</artifactId>
+          <extensions>true</extensions>
+          <executions>
+              <execution>
+                  <goals>
+                      <goal>manifest</goal>
+                  </goals>
+              </execution>
+          </executions>
+          <configuration>
+            <instructions>
+              <Main-Class>org.eclipse.jetty.runner.Runner</Main-Class>
+              <Import-Package>!*</Import-Package>
+              <Export-Package></Export-Package>
+            </instructions>
+          </configuration>
+        </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>package</id>
-            <phase>package</phase>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-            <configuration>
-              <archive>
-                <manifest>
-                  <mainClass>org.eclipse.jetty.runner.Runner</mainClass>
-                </manifest>
-                <manifestEntries>
-                  <mode>development</mode>
-                  <url>http://eclipse.org/jetty</url>
-                  <Built-By>${user.name}</Built-By>
-                  <package>org.eclipse.jetty.runner</package>
-                  <Bundle-Name>Jetty Runner</Bundle-Name>
-                  <Bundle-Vendor>Mort Bay Consulting</Bundle-Vendor>
-                </manifestEntries>
-              </archive>
-            </configuration>
-          </execution>
-        </executions>
+        <configuration>
+         <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+         </archive>
+        </configuration>
       </plugin>
     </plugins>
   </build>
@@ -94,7 +95,12 @@
     </dependency>
       <dependency>
         <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-jsp</artifactId>
+        <artifactId>apache-jsp</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.eclipse.jetty</groupId>
+        <artifactId>apache-jstl</artifactId>
         <version>${project.version}</version>
       </dependency>
   </dependencies>
diff --git a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
index ca041fa..aa8870c 100644
--- a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
+++ b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
@@ -18,12 +18,32 @@
 
 package org.eclipse.jetty.runner;
 
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.HashLoginService;
 import org.eclipse.jetty.security.authentication.BasicAuthenticator;
-import org.eclipse.jetty.server.*;
-import org.eclipse.jetty.server.handler.*;
+import org.eclipse.jetty.server.AbstractConnector;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.ConnectorStatistics;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.NCSARequestLog;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.ShutdownMonitor;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.DefaultHandler;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
 import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
@@ -36,21 +56,10 @@
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.eclipse.jetty.xml.XmlConfiguration;
 
-import java.io.IOException;
-import java.io.PrintStream;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-
 /**
  * Runner
- *
+ * <p>
  * Combine jetty classes into a single executable jar and run webapps based on the args to it.
- *
  */
 public class Runner
 {
@@ -84,8 +93,6 @@
 
     /**
      * Classpath
-     *
-     *
      */
     public class Classpath
     {
@@ -137,22 +144,15 @@
         }
     }
 
-
-
-
-    /**
-     *
-     */
     public Runner()
     {
-
     }
 
 
     /**
      * Generate helpful usage message and exit
      *
-     * @param error
+     * @param error the error header
      */
     public void usage(String error)
     {
@@ -192,8 +192,8 @@
     /**
      * Configure a jetty instance and deploy the webapps presented as args
      *
-     * @param args
-     * @throws Exception
+     * @param args the command line arguments
+     * @throws Exception if unable to configure
      */
     public void configure(String[] args) throws Exception
     {
@@ -482,10 +482,6 @@
     }
 
 
-    /**
-     * @param handler
-     * @param handlers
-     */
     protected void prependHandler (Handler handler, HandlerCollection handlers)
     {
         if (handler == null || handlers == null)
@@ -501,9 +497,6 @@
 
 
 
-    /**
-     * @throws Exception
-     */
     public void run() throws Exception
     {
         _server.start();
@@ -534,9 +527,6 @@
 
 
 
-    /**
-     * @param args
-     */
     public static void main(String[] args)
     {
         Runner runner = new Runner();
diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml
index a14f984..fa0ea8c 100644
--- a/jetty-security/pom.xml
+++ b/jetty-security/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-security</artifactId>
@@ -25,7 +25,7 @@
             </goals>
             <configuration>
               <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.security.cert,*</Import-Package>
+                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",javax.security.cert,org.eclipse.jetty*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",*</Import-Package>
               </instructions>
             </configuration>
 
@@ -33,35 +33,6 @@
         </executions>
       </plugin>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-security/src/main/config/etc/krb5.ini b/jetty-security/src/main/config/etc/krb5.ini
index 9cea63c..283880c 100644
--- a/jetty-security/src/main/config/etc/krb5.ini
+++ b/jetty-security/src/main/config/etc/krb5.ini
@@ -9,9 +9,9 @@
 
 [realms]
 MORTBAY.ORG = {
- 		kdc = 192.168.2.30
- 		admin_server = 192.168.2.30
- 		default_domain = MORTBAY.ORG
+    kdc = 192.168.2.30
+    admin_server = 192.168.2.30
+    default_domain = MORTBAY.ORG
 }
 
 [domain_realm]
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java
index 83a965d..e444797 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/Authenticator.java
@@ -43,7 +43,8 @@
     /* ------------------------------------------------------------ */
     /**
      * Configure the Authenticator
-     * @param configuration
+     * 
+     * @param configuration the configuration
      */
     void setConfiguration(AuthConfiguration configuration);
 
@@ -64,13 +65,16 @@
      * where the http method of the original request causing authentication
      * is not the same as the http method resulting from the redirect
      * after authentication.
-     * @param request
+     * 
+     * @param request the request to manipulate
      */
     void prepareRequest(ServletRequest request);
     
 
     /* ------------------------------------------------------------ */
-    /** Validate a request
+    /** 
+     * Validate a request
+     * 
      * @param request The request
      * @param response The response
      * @param mandatory True if authentication is mandatory.
@@ -79,18 +83,20 @@
      * implement {@link org.eclipse.jetty.server.Authentication.ResponseSent}.  If Authentication is not manditory, then a
      * {@link org.eclipse.jetty.server.Authentication.Deferred} may be returned.
      *
-     * @throws ServerAuthException
+     * @throws ServerAuthException if unable to validate request
      */
     Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException;
 
     /* ------------------------------------------------------------ */
     /**
-     * @param request
-     * @param response
-     * @param mandatory
-     * @param validatedUser
+     * is response secure
+     * 
+     * @param request the request 
+     * @param response the response
+     * @param mandatory if security is mandator
+     * @param validatedUser the user that was validated
      * @return true if response is secure
-     * @throws ServerAuthException
+     * @throws ServerAuthException if unable to test response
      */
     boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, User validatedUser) throws ServerAuthException;
 
@@ -106,7 +112,8 @@
         String getAuthMethod();
         String getRealmName();
 
-        /** Get a SecurityHandler init parameter
+        /** 
+         * Get a SecurityHandler init parameter
          * @see SecurityHandler#getInitParameter(String)
          * @param param parameter name
          * @return Parameter value or null
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java
index bf0e027..827e6fb 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintAware.java
@@ -21,9 +21,6 @@
 import java.util.List;
 import java.util.Set;
 
-/**
- * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
- */
 public interface ConstraintAware
 {
     List<ConstraintMapping> getConstraintMappings();
@@ -32,15 +29,15 @@
     /* ------------------------------------------------------------ */
     /** Set Constraint Mappings and roles.
      * Can only be called during initialization.
-     * @param constraintMappings
-     * @param roles
+     * @param constraintMappings the mappings
+     * @param roles the roles
      */
     void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles);
     
     /* ------------------------------------------------------------ */
     /** Add a Constraint Mapping.
      * May be called for running webapplication as an annotated servlet is instantiated.
-     * @param mapping
+     * @param mapping the mapping
      */
     void addConstraintMapping(ConstraintMapping mapping);
     
@@ -48,7 +45,7 @@
     /* ------------------------------------------------------------ */
     /** Add a Role definition.
      * May be called on running webapplication as an annotated servlet is instantiated.
-     * @param role
+     * @param role the role
      */
     void addRole(String role);
     
@@ -56,7 +53,7 @@
      * See Servlet Spec 31, sec 13.8.4, pg 145
      * When true, requests with http methods not explicitly covered either by inclusion or omissions
      * in constraints, will have access denied.
-     * @param deny
+     * @param deny true for denied method access
      */
     void setDenyUncoveredHttpMethods(boolean deny);
     
@@ -65,6 +62,7 @@
     /**
      * See Servlet Spec 31, sec 13.8.4, pg 145
      * Container must check if there are urls with uncovered http methods
+     * @return true if urls with uncovered http methods
      */
     boolean checkPathsWithUncoveredHttpMethods();
 }
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
index 47efd25..8708775 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java
@@ -40,7 +40,6 @@
 
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
@@ -51,14 +50,12 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.security.Constraint;
 
-/* ------------------------------------------------------------ */
 /**
  * ConstraintSecurityHandler
- * 
+ * <p> 
  * Handler to enforce SecurityConstraints. This implementation is servlet spec
  * 3.1 compliant and pre-computes the constraint combinations for runtime
  * efficiency.
- *
  */
 public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
 {
@@ -79,9 +76,6 @@
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param constraint
-     */
     public static Constraint createConstraint(Constraint constraint)
     {
         try
@@ -98,10 +92,11 @@
     /**
      * Create a security constraint
      * 
-     * @param name
-     * @param authenticate
-     * @param roles
-     * @param dataConstraint
+     * @param name the name of the constraint
+     * @param authenticate true to authenticate
+     * @param roles list of roles
+     * @param dataConstraint the data constraint
+     * @return the constraint
      */
     public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
     {
@@ -117,8 +112,11 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param name
-     * @param element
+     * Create a Constraint
+     * 
+     * @param name the name
+     * @param element the http constraint element
+     * @return the created constraint
      */
     public static Constraint createConstraint (String name, HttpConstraintElement element)
     {
@@ -128,10 +126,13 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param name
-     * @param rolesAllowed
-     * @param permitOrDeny
-     * @param transport
+     * Create Constraint
+     * 
+     * @param name the name
+     * @param rolesAllowed the list of allowed roles
+     * @param permitOrDeny the permission semantic
+     * @param transport the transport guarantee
+     * @return the created constraint
      */
     public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
     {
@@ -168,10 +169,6 @@
     
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param pathSpec
-     * @param constraintMappings
-     */
     public static List<ConstraintMapping> getConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
     {
         if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
@@ -193,8 +190,9 @@
     /** Take out of the constraint mappings those that match the 
      * given path.
      * 
-     * @param pathSpec
+     * @param pathSpec the path spec
      * @param constraintMappings a new list minus the matching constraints
+     * @return the list of constraint mappings
      */
     public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
     {
@@ -216,12 +214,13 @@
     
     
     /* ------------------------------------------------------------ */
-    /** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
+    /** 
+     * Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
      * 
-     * @param name
-     * @param pathSpec
-     * @param securityElement
-     * @return
+     * @param name the name
+     * @param pathSpec the path spec
+     * @param securityElement the servlet security element
+     * @return the list of constraint mappings
      */
     public static List<ConstraintMapping> createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
     {
@@ -464,7 +463,7 @@
      * Create and combine the constraint with the existing processed
      * constraints.
      * 
-     * @param mapping
+     * @param mapping the constraint mapping
      */
     protected void processConstraintMapping(ConstraintMapping mapping)
     {
@@ -522,8 +521,8 @@
      * the mappings: an entry that names the method of the Request specifically, an
      * entry that names constraints that apply to all methods, entries of the form
      * &lt;method&gt;.omission, where the method of the Request is not named in the omission.
-     * @param mapping
-     * @param mappings
+     * @param mapping the constraint mapping
+     * @param mappings the mappings of roles
      */
     protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
     {
@@ -545,8 +544,8 @@
     /* ------------------------------------------------------------ */
     /**
      * Initialize or update the RoleInfo from the constraint
-     * @param ri
-     * @param mapping
+     * @param ri the role info
+     * @param mapping the constraint mapping
      */
     protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
     { 
@@ -675,7 +674,7 @@
         if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
             return true;
 
-        HttpConfiguration httpConfig = HttpChannel.getCurrentHttpChannel().getHttpConfiguration();
+        HttpConfiguration httpConfig = Request.getBaseRequest(request).getHttpChannel().getHttpConfiguration();
 
         if (dataConstraint == UserDataConstraint.Confidential || dataConstraint == UserDataConstraint.Integral)
         {
@@ -871,9 +870,9 @@
      * Check if any http method omissions exist in the list of method
      * to auth info mappings.
      * 
-     * @param path
-     * @param methodMappings
-     * @return
+     * @param path the path
+     * @param methodMappings the method mappings
+     * @return true if ommision exist
      */
     protected boolean omissionsExist (String path, Map<String, RoleInfo> methodMappings)
     {
@@ -891,11 +890,11 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * Given a string of the form &lt;method&gt;.&lt;method&gt;.omission
+     * Given a string of the form <code>&lt;method&gt;.&lt;method&gt;.omission</code>
      * split out the individual method names.
      * 
-     * @param omission
-     * @return
+     * @param omission the method
+     * @return the list of strings
      */
     protected Set<String> getOmittedMethods (String omission)
     {
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
deleted file mode 100644
index 9e82add..0000000
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.security;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
- * @deprecated
- */
-public interface CrossContextPsuedoSession<T>
-{
-
-    T fetch(HttpServletRequest request);
-
-    void store(T data, HttpServletResponse response);
-
-    void clear(HttpServletRequest request);
-
-}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
deleted file mode 100644
index e205d77..0000000
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.security;
-
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
- * @deprecated
- */
-public class HashCrossContextPsuedoSession<T> implements CrossContextPsuedoSession<T>
-{
-    private final String _cookieName;
-
-    private final String _cookiePath;
-
-    private final Random _random = new SecureRandom();
-
-    private final Map<String, T> _data = new HashMap<String, T>();
-
-    public HashCrossContextPsuedoSession(String cookieName, String cookiePath)
-    {
-        this._cookieName = cookieName;
-        this._cookiePath = cookiePath == null ? "/" : cookiePath;
-    }
-
-    public T fetch(HttpServletRequest request)
-    {
-        Cookie[] cookies = request.getCookies();
-        if (cookies == null)
-            return null;
-        
-        for (Cookie cookie : cookies)
-        {
-            if (_cookieName.equals(cookie.getName()))
-            {
-                String key = cookie.getValue();
-                return _data.get(key);
-            }
-        }
-        return null;
-    }
-
-    public void store(T datum, HttpServletResponse response)
-    {
-        String key;
-
-        synchronized (_data)
-        {
-            // Create new ID
-            while (true)
-            {
-                key = Long.toString(Math.abs(_random.nextLong()), 30 + (int) (System.currentTimeMillis() % 7));
-                if (!_data.containsKey(key)) break;
-            }
-
-            _data.put(key, datum);
-        }
-
-        Cookie cookie = new Cookie(_cookieName, key);
-        cookie.setPath(_cookiePath);
-        response.addCookie(cookie);
-    }
-
-    public void clear(HttpServletRequest request)
-    {
-        for (Cookie cookie : request.getCookies())
-        {
-            if (_cookieName.equals(cookie.getName()))
-            {
-                String key = cookie.getValue();
-                _data.remove(key);
-                break;
-            }
-        }
-    }
-}
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java
index beb051b..d49f158 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashLoginService.java
@@ -19,7 +19,11 @@
 package org.eclipse.jetty.security;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
 
+import org.eclipse.jetty.security.MappedLoginService.KnownUser;
 import org.eclipse.jetty.security.PropertyUserStore.UserListener;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.Scanner;
@@ -31,18 +35,18 @@
 /* ------------------------------------------------------------ */
 /**
  * Properties User Realm.
- * 
+ * <p>
  * An implementation of UserRealm that stores users and roles in-memory in HashMaps.
- * <P>
+ * <p>
  * Typically these maps are populated by calling the load() method or passing a properties resource to the constructor. The format of the properties file is:
  * 
- * <PRE>
+ * <pre>
  *  username: password [,rolename ...]
- * </PRE>
+ * </pre>
  * 
  * Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
  * checksums.
- * 
+ * <p>
  * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
  */
 public class HashLoginService extends MappedLoginService implements UserListener
@@ -52,7 +56,29 @@
     private PropertyUserStore _propertyUserStore;
     private String _config;
     private Resource _configResource;
-    private int _refreshInterval = 0;// default is not to reload
+    private boolean hotReload = false; // default is not to reload
+    
+    
+    
+    public class HashKnownUser extends KnownUser
+    {
+        String[] _roles;
+        
+        public HashKnownUser(String name, Credential credential)
+        {
+            super(name, credential);
+        }
+        
+        public void setRoles (String[] roles)
+        {
+            _roles = roles;
+        }
+        
+        public String[] getRoles()
+        {
+            return _roles;
+        }
+    }
 
     /* ------------------------------------------------------------ */
     public HashLoginService()
@@ -101,17 +127,51 @@
     {
         _config = config;
     }
-
-    /* ------------------------------------------------------------ */
-    public void setRefreshInterval(int msec)
+    
+    /**
+     * Is hot reload enabled on this user store
+     * 
+     * @return true if hot reload was enabled before startup
+     */
+    public boolean isHotReload()
     {
-        _refreshInterval = msec;
+        return hotReload;
+    }
+
+    /**
+     * Enable Hot Reload of the Property File
+     * 
+     * @param enable true to enable, false to disable
+     */
+    public void setHotReload(boolean enable)
+    {
+        if (isRunning())
+        {
+            throw new IllegalStateException("Cannot set hot reload while user store is running");
+        }
+        this.hotReload = enable;
     }
 
     /* ------------------------------------------------------------ */
+    /**
+     * sets the refresh interval (in seconds)
+     * @param sec the refresh interval
+     * @deprecated use {@link #setHotReload(boolean)} instead
+     */
+    @Deprecated
+    public void setRefreshInterval(int sec)
+    {
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return refresh interval in seconds for how often the properties file should be checked for changes
+     * @deprecated use {@link #isHotReload()} instead
+     */
+    @Deprecated
     public int getRefreshInterval()
     {
-        return _refreshInterval;
+        return (hotReload)?1:0;
     }
 
     /* ------------------------------------------------------------ */
@@ -128,6 +188,41 @@
         // TODO: Consider refactoring MappedLoginService to not have to override with unused methods
     }
 
+
+
+    @Override
+    protected String[] loadRoleInfo(KnownUser user)
+    {
+        UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
+        if (id == null)
+            return null;
+
+
+        Set<RolePrincipal> roles = id.getSubject().getPrincipals(RolePrincipal.class);
+        if (roles == null)
+            return null;
+
+        List<String> list = new ArrayList<>();
+        for (RolePrincipal r:roles)
+            list.add(r.getName());
+
+        return list.toArray(new String[roles.size()]);
+    }
+
+    @Override
+    protected KnownUser loadUserInfo(String userName)
+    {
+        UserIdentity id = _propertyUserStore.getUserIdentity(userName);
+        if (id != null)
+        {
+            return (KnownUser)id.getUserPrincipal();
+        }
+        
+        return null;
+    }
+    
+    
+
     /* ------------------------------------------------------------ */
     /**
      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
@@ -140,11 +235,11 @@
         if (_propertyUserStore == null)
         {
             if(LOG.isDebugEnabled())
-                LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " refreshInterval: " + _refreshInterval);
+                LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _config + " hotReload: " + hotReload);
             
             _propertyUserStore = new PropertyUserStore();
-            _propertyUserStore.setRefreshInterval(_refreshInterval);
-            _propertyUserStore.setConfig(_config);
+            _propertyUserStore.setHotReload(hotReload);
+            _propertyUserStore.setConfigPath(_config);
             _propertyUserStore.registerUserListener(this);
             _propertyUserStore.start();
         }
@@ -169,9 +264,11 @@
     {
         if (LOG.isDebugEnabled())
             LOG.debug("update: " + userName + " Roles: " + roleArray.length);
-        putUser(userName,credential,roleArray);
+       //TODO need to remove and replace the authenticated user?
     }
 
+    
+    
     /* ------------------------------------------------------------ */
     @Override
     public void remove(String userName)
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
index b37cc5c..c04bee8 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/IdentityService.java
@@ -24,10 +24,8 @@
 
 import org.eclipse.jetty.server.UserIdentity;
 
-/* ------------------------------------------------------------ */
 /**
  * Associates UserIdentities from with threads and UserIdentity.Contexts.
- *
  */
 public interface IdentityService
 {
@@ -37,7 +35,7 @@
     /**
      * Associate a user identity with the current thread.
      * This is called with as a thread enters the
-     * {@link SecurityHandler#handle(String, Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
+     * {@link SecurityHandler#handle(String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}
      * method and then again with a null argument as that call exits.
      * @param user The current user or null for no user to associated.
      * @return an object representing the previous associated state
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java
index 98f7664..dddac27 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/JDBCLoginService.java
@@ -29,6 +29,8 @@
 import java.util.List;
 import java.util.Properties;
 
+import javax.servlet.ServletRequest;
+
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.log.Log;
@@ -39,24 +41,17 @@
 /* ------------------------------------------------------------ */
 /**
  * HashMapped User Realm with JDBC as data source. 
- * The login() method checks the inherited Map for the user. If the user is not
+ * The {@link #login(String, Object, ServletRequest)} method checks the inherited Map for the user. If the user is not
  * found, it will fetch details from the database and populate the inherited
- * Map. It then calls the superclass login() method to perform the actual
+ * Map. It then calls the superclass {@link #login(String, Object, ServletRequest)} method to perform the actual
  * authentication. Periodically (controlled by configuration parameter),
  * internal hashes are cleared. Caching can be disabled by setting cache refresh
  * interval to zero. Uses one database connection that is initialized at
- * startup. Reconnect on failures. authenticate() is 'synchronized'.
- * 
+ * startup. Reconnect on failures.
+ * <p> 
  * An example properties file for configuration is in
- * $JETTY_HOME/etc/jdbcRealm.properties
- * 
- * @version $Id: JDBCLoginService.java 4792 2009-03-18 21:55:52Z gregw $
- * 
- * 
- * 
- * 
+ * <code>${jetty.home}/etc/jdbcRealm.properties</code>
  */
-
 public class JDBCLoginService extends MappedLoginService
 {
     private static final Logger LOG = Log.getLogger(JDBCLoginService.class);
@@ -75,6 +70,26 @@
     protected String _userSql;
     protected String _roleSql;
 
+    
+    /**
+     * JDBCKnownUser
+     */
+    public class JDBCKnownUser extends KnownUser
+    {
+        int _userKey;
+        
+        public JDBCKnownUser(String name, Credential credential, int key)
+        {
+            super(name, credential);
+            _userKey = key;
+        }
+        
+        
+        public int getUserKey ()
+        {
+            return _userKey;
+        }
+    }
 
     /* ------------------------------------------------------------ */
     public JDBCLoginService()
@@ -209,7 +224,7 @@
 
     /* ------------------------------------------------------------ */
     @Override
-    public UserIdentity login(String username, Object credentials)
+    public UserIdentity login(String username, Object credentials, ServletRequest request)
     {
         long now = System.currentTimeMillis();
         if (now - _lastHashPurge > _cacheTime || _cacheTime == 0)
@@ -219,7 +234,7 @@
             closeConnection();
         }
         
-        return super.login(username,credentials);
+        return super.login(username,credentials, request);
     }
 
     /* ------------------------------------------------------------ */
@@ -229,7 +244,7 @@
     }
     
     /* ------------------------------------------------------------ */
-    @Override
+    @Deprecated
     protected UserIdentity loadUser(String username)
     {
         try
@@ -249,6 +264,8 @@
                     {
                         int key = rs1.getInt(_userTableKey);
                         String credentials = rs1.getString(_userTablePasswordField);
+
+
                         List<String> roles = new ArrayList<String>();
 
                         try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
@@ -260,7 +277,7 @@
                                     roles.add(rs2.getString(_roleTableRoleField));
                             }
                         }
-                        return putUser(username, credentials, roles.toArray(new String[roles.size()]));
+                        return putUser(username, Credential.getCredential(credentials), roles.toArray(new String[roles.size()]));
                     }
                 }
             }
@@ -272,11 +289,83 @@
         }
         return null;
     }
-    
-    /* ------------------------------------------------------------ */
-    protected UserIdentity putUser (String username, String credentials, String[] roles)
+
+
+    /** 
+     * @see org.eclipse.jetty.security.MappedLoginService#loadUserInfo(java.lang.String)
+     */
+    public KnownUser loadUserInfo (String username)
     {
-        return putUser(username, Credential.getCredential(credentials),roles);
+        try
+        {
+            if (null == _con) 
+                connectDatabase();
+
+            if (null == _con) 
+                throw new SQLException("Can't connect to database");
+
+            try (PreparedStatement stat1 = _con.prepareStatement(_userSql))
+            {
+                stat1.setObject(1, username);
+                try (ResultSet rs1 = stat1.executeQuery())
+                {
+                    if (rs1.next())
+                    {
+                        int key = rs1.getInt(_userTableKey);
+                        String credentials = rs1.getString(_userTablePasswordField);
+
+                        return new JDBCKnownUser (username, Credential.getCredential(credentials), key);
+                    }
+                }
+            }
+        }
+        catch (SQLException e)
+        {
+            LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
+            closeConnection();
+        }
+        
+        return null;
+    }
+
+    
+    
+    /** 
+     * @see org.eclipse.jetty.security.MappedLoginService#loadRoleInfo(org.eclipse.jetty.security.MappedLoginService.KnownUser)
+     */
+    public String[] loadRoleInfo (KnownUser user)
+    {
+        JDBCKnownUser jdbcUser = (JDBCKnownUser)user;
+        
+        try
+        {
+            if (null == _con) 
+                connectDatabase();
+
+            if (null == _con) 
+                throw new SQLException("Can't connect to database");
+            
+            
+            List<String> roles = new ArrayList<String>();
+
+            try (PreparedStatement stat2 = _con.prepareStatement(_roleSql))
+            {
+                stat2.setInt(1, jdbcUser.getUserKey());
+                try (ResultSet rs2 = stat2.executeQuery())
+                {
+                    while (rs2.next())
+                        roles.add(rs2.getString(_roleTableRoleField));
+                    return roles.toArray(new String[roles.size()]);
+                }
+            }
+        }
+        catch (SQLException e)
+        {
+            LOG.warn("UserRealm " + getName() + " could not load user information from database", e);
+            closeConnection();
+        }
+        
+        return null;
     }
     
 
@@ -292,5 +381,4 @@
         }
         _con = null;
     }
-
 }
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java
index b1d9aa4..8917c6e 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/LoginService.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.security;
 
+import javax.servlet.ServletRequest;
+
 import org.eclipse.jetty.server.UserIdentity;
 
 
@@ -42,14 +44,15 @@
     /** Login a user.
      * @param username The user name
      * @param credentials The users credentials
+     * @param request TODO
      * @return A UserIdentity if the credentials matched, otherwise null
      */
-    UserIdentity login(String username,Object credentials);
+    UserIdentity login(String username,Object credentials, ServletRequest request);
     
     /* ------------------------------------------------------------ */
     /** Validate a user identity.
      * Validate that a UserIdentity previously created by a call 
-     * to {@link #login(String, Object)} is still valid.
+     * to {@link #login(String, Object, ServletRequest)} is still valid.
      * @param user The user to validate
      * @return true if authentication has not been revoked for the user.
      */
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java
index 4cec9b3..629b7f5 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/MappedLoginService.java
@@ -27,6 +27,7 @@
 import java.util.concurrent.ConcurrentMap;
 
 import javax.security.auth.Subject;
+import javax.servlet.ServletRequest;
 
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -138,6 +139,8 @@
     public void logout(UserIdentity identity)
     {
         LOG.debug("logout {}",identity);
+        
+        //TODO should remove the user?????
     }
 
     /* ------------------------------------------------------------ */
@@ -199,6 +202,24 @@
         _users.put(userName,identity);
         return identity;
     }
+    
+    
+
+    
+    public synchronized UserIdentity putUser (KnownUser userPrincipal, String[] roles)
+    {
+        Subject subject = new Subject();
+        subject.getPrincipals().add(userPrincipal);
+        subject.getPrivateCredentials().add(userPrincipal._credential);
+        if (roles!=null)
+            for (String role : roles)
+                subject.getPrincipals().add(new RolePrincipal(role));
+        subject.setReadOnly();
+        UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
+        _users.put(userPrincipal._name,identity);
+        return identity;
+    }
+    
 
     /* ------------------------------------------------------------ */
     public void removeUser(String username)
@@ -208,9 +229,9 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object)
+     * @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object, ServletRequest)
      */
-    public UserIdentity login(String username, Object credentials)
+    public UserIdentity login(String username, Object credentials, ServletRequest request)
     {
         if (username == null)
             return null;
@@ -218,9 +239,17 @@
         UserIdentity user = _users.get(username);
 
         if (user==null)
-            user = loadUser(username);
-
-        if (user!=null)
+        {
+            KnownUser userPrincipal = loadUserInfo(username);
+            if (userPrincipal.authenticate(credentials))
+            {
+                //safe to load the roles
+                String[] roles = loadRoleInfo(userPrincipal);
+                user = putUser(userPrincipal, roles);
+                return user;
+            }
+        }
+        else
         {
             UserPrincipal principal = (UserPrincipal)user.getUserPrincipal();
             if (principal.authenticate(credentials))
@@ -240,7 +269,10 @@
 
         return false;
     }
-
+    /* ------------------------------------------------------------ */
+    protected abstract String[] loadRoleInfo (KnownUser user);
+    /* ------------------------------------------------------------ */
+    protected abstract KnownUser loadUserInfo (String username);
     /* ------------------------------------------------------------ */
     protected abstract UserIdentity loadUser(String username);
 
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java b/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java
index cbd3bfd..51dd0f1 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/PropertyUserStore.java
@@ -19,8 +19,8 @@
 package org.eclipse.jetty.security;
 
 import java.io.File;
-import java.io.FilenameFilter;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -36,37 +36,39 @@
 import org.eclipse.jetty.security.MappedLoginService.KnownUser;
 import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
 import org.eclipse.jetty.server.UserIdentity;
-import org.eclipse.jetty.util.Scanner;
-import org.eclipse.jetty.util.Scanner.BulkListener;
+import org.eclipse.jetty.util.PathWatcher;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.PathResource;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.security.Credential;
 
 /**
  * PropertyUserStore
- *
+ * <p>
  * This class monitors a property file of the format mentioned below and notifies registered listeners of the changes to the the given file.
  *
- * <PRE>
+ * <pre>
  *  username: password [,rolename ...]
- * </PRE>
+ * </pre>
  *
  * Passwords may be clear text, obfuscated or checksummed. The class com.eclipse.Util.Password should be used to generate obfuscated passwords or password
  * checksums.
  *
  * If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
  */
-public class PropertyUserStore extends AbstractLifeCycle
+public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.Listener
 {
     private static final Logger LOG = Log.getLogger(PropertyUserStore.class);
 
-    private String _config;
+    private Path _configPath;
     private Resource _configResource;
-    private Scanner _scanner;
-    private int _refreshInterval = 0;// default is not to reload
+    
+    private PathWatcher pathWatcher;
+    private boolean hotReload = false; // default is not to reload
 
     private IdentityService _identityService = new DefaultIdentityService();
     private boolean _firstLoad = true; // true if first load, false from that point on
@@ -74,67 +76,165 @@
     private final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
     private List<UserListener> _listeners;
 
-    /* ------------------------------------------------------------ */
+    /**
+     * Get the config (as a string)
+     * @return the config path as a string
+     * @deprecated use {@link #getConfigPath()} instead
+     */
+    @Deprecated
     public String getConfig()
     {
-        return _config;
+        return _configPath.toString();
     }
 
-    /* ------------------------------------------------------------ */
-    public void setConfig(String config)
+    /**
+     * Set the Config Path from a String reference to a file
+     * @param configFile the config file
+     * @deprecated use {@link #setConfigPath(String)} instead
+     */
+    @Deprecated
+    public void setConfig(String configFile)
     {
-        _config = config;
+        setConfigPath(configFile);
+    }
+    
+    /**
+     * Get the Config {@link Path} reference.
+     * @return the config path
+     */
+    public Path getConfigPath()
+    {
+        return _configPath;
     }
 
-    /* ------------------------------------------------------------ */
-        public UserIdentity getUserIdentity(String userName)
+    /**
+     * Set the Config Path from a String reference to a file
+     * @param configFile the config file
+     */
+    public void setConfigPath(String configFile)
+    {
+        if (configFile == null)
         {
-            return _knownUserIdentities.get(userName);
+            _configPath = null;
         }
+        else
+        {
+            _configPath = new File(configFile).toPath();
+        }
+    }
+
+    /**
+     * Set the Config Path from a {@link File} reference
+     * @param configFile the config file
+     */
+    public void setConfigPath(File configFile)
+    {
+        _configPath = configFile.toPath();
+    }
+
+    /**
+     * Set the Config Path
+     * @param configPath the config path
+     */
+    public void setConfigPath(Path configPath)
+    {
+        _configPath = configPath;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public UserIdentity getUserIdentity(String userName)
+    {
+        return _knownUserIdentities.get(userName);
+    }
 
     /* ------------------------------------------------------------ */
     /**
-     * returns the resource associated with the configured properties file, creating it if necessary
+     * @return the resource associated with the configured properties file, creating it if necessary
+     * @throws IOException if unable to get the resource
      */
     public Resource getConfigResource() throws IOException
     {
         if (_configResource == null)
         {
-            _configResource = Resource.newResource(_config);
+            _configResource = new PathResource(_configPath);
         }
 
         return _configResource;
     }
+    
+    /**
+     * Is hot reload enabled on this user store
+     * 
+     * @return true if hot reload was enabled before startup
+     */
+    public boolean isHotReload()
+    {
+        return hotReload;
+    }
+
+    /**
+     * Enable Hot Reload of the Property File
+     * 
+     * @param enable true to enable, false to disable
+     */
+    public void setHotReload(boolean enable)
+    {
+        if (isRunning())
+        {
+            throw new IllegalStateException("Cannot set hot reload while user store is running");
+        }
+        this.hotReload = enable;
+    }
 
     /* ------------------------------------------------------------ */
     /**
      * sets the refresh interval (in seconds)
+     * @param sec the refresh interval
+     * @deprecated use {@link #setHotReload(boolean)} instead
      */
-    public void setRefreshInterval(int msec)
+    @Deprecated
+    public void setRefreshInterval(int sec)
     {
-        _refreshInterval = msec;
     }
 
     /* ------------------------------------------------------------ */
     /**
-     * refresh interval in seconds for how often the properties file should be checked for changes
+     * @return refresh interval in seconds for how often the properties file should be checked for changes
+     * @deprecated use {@link #isHotReload()} instead
      */
+    @Deprecated
     public int getRefreshInterval()
     {
-        return _refreshInterval;
+        return (hotReload)?1:0;
+    }
+    
+    @Override
+    public String toString()
+    {
+        StringBuilder s = new StringBuilder();
+        s.append(this.getClass().getName());
+        s.append("[");
+        s.append("users.count=").append(this._knownUsers.size());
+        s.append("identityService=").append(this._identityService);
+        s.append("]");
+        return s.toString();
     }
 
     /* ------------------------------------------------------------ */
     private void loadUsers() throws IOException
     {
-        if (_config == null)
+        if (_configPath == null)
             return;
 
         if (LOG.isDebugEnabled())
-            LOG.debug("Load " + this + " from " + _config);
+        {
+            LOG.debug("Loading " + this + " from " + _configPath);
+        }
+        
         Properties properties = new Properties();
         if (getConfigResource().exists())
             properties.load(getConfigResource().getInputStream());
+        
         Set<String> known = new HashSet<String>();
 
         for (Map.Entry<Object, Object> entry : properties.entrySet())
@@ -211,8 +311,13 @@
          * set initial load to false as there should be no more initial loads
          */
         _firstLoad = false;
+        
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Loaded " + this + " from " + _configPath);
+        }
     }
-
+    
     /* ------------------------------------------------------------ */
     /**
      * Depending on the value of the refresh interval, this method will either start up a scanner thread that will monitor the properties file for changes after
@@ -225,66 +330,29 @@
     {
         super.doStart();
 
-        if (getRefreshInterval() > 0)
+        loadUsers();
+        if ( isHotReload() && (_configPath != null) )
         {
-            _scanner = new Scanner();
-            _scanner.setScanInterval(getRefreshInterval());
-            List<File> dirList = new ArrayList<File>(1);
-            dirList.add(getConfigResource().getFile().getParentFile());
-            _scanner.setScanDirs(dirList);
-            _scanner.setFilenameFilter(new FilenameFilter()
-            {
-                public boolean accept(File dir, String name)
-                {
-                    File f = new File(dir,name);
-                    try
-                    {
-                        if (f.compareTo(getConfigResource().getFile()) == 0)
-                        {
-                            return true;
-                        }
-                    }
-                    catch (IOException e)
-                    {
-                        return false;
-                    }
-
-                    return false;
-                }
-
-            });
-
-            _scanner.addListener(new BulkListener()
-            {
-                public void filesChanged(List<String> filenames) throws Exception
-                {
-                    if (filenames == null)
-                        return;
-                    if (filenames.isEmpty())
-                        return;
-                    if (filenames.size() == 1)
-                    {
-                        Resource r = Resource.newResource(filenames.get(0));
-                        if (r.getFile().equals(_configResource.getFile()))
-                            loadUsers();
-                    }
-                }
-
-                public String toString()
-                {
-                    return "PropertyUserStore$Scanner";
-                }
-
-            });
-
-            _scanner.setReportExistingFilesOnStartup(true);
-            _scanner.setRecursive(false);
-            _scanner.start();
+            this.pathWatcher = new PathWatcher();
+            this.pathWatcher.watch(_configPath);
+            this.pathWatcher.addListener(this);
+            this.pathWatcher.setNotifyExistingOnStart(false);
+            this.pathWatcher.start();
         }
-        else
+       
+    }
+    
+    @Override
+    public void onPathWatchEvent(PathWatchEvent event)
+    {
+        try
         {
             loadUsers();
         }
+        catch (IOException e)
+        {
+            LOG.warn(e);
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -294,9 +362,9 @@
     protected void doStop() throws Exception
     {
         super.doStop();
-        if (_scanner != null)
-            _scanner.stop();
-        _scanner = null;
+        if (this.pathWatcher != null)
+            this.pathWatcher.stop();
+        this.pathWatcher = null;
     }
 
     /**
@@ -335,6 +403,7 @@
 
     /**
      * registers a listener to be notified of the contents of the property file
+     * @param listener the user listener
      */
     public void registerUserListener(UserListener listener)
     {
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
index bfcb8fa..88df101 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
@@ -29,25 +29,22 @@
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionListener;
 
 import org.eclipse.jetty.security.authentication.DeferredAuthentication;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ContextHandler.Context;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.eclipse.jetty.server.session.AbstractSession;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
 /**
  * Abstract SecurityHandler.
+ * <p>
  * Select and apply an {@link Authenticator} to a request.
  * <p>
  * The Authenticator may either be directly set on the handler
@@ -58,7 +55,6 @@
  * Authentication.Configuration. At startup, any context init parameters
  * that start with "org.eclipse.jetty.security." that do not have
  * values in the SecurityHandler init parameters, are copied.
- *
  */
 public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.AuthConfiguration
 {
@@ -133,8 +129,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Set the authenticator.
-     * @param authenticator
+    /** 
+     * Set the authenticator.
+     * @param authenticator the authenticator
      * @throws IllegalStateException if the SecurityHandler is running
      */
     public void setAuthenticator(Authenticator authenticator)
@@ -251,8 +248,8 @@
 
     /* ------------------------------------------------------------ */
     /** Set an initialization parameter.
-     * @param key
-     * @param value
+     * @param key the init key
+     * @param value the init value
      * @return previous value
      * @throws IllegalStateException if the SecurityHandler is running
      */
@@ -309,33 +306,6 @@
                         getInitParameter(name)==null)
                     setInitParameter(name,context.getInitParameter(name));
             }
-            
-            //register a session listener to handle securing sessions when authentication is performed
-            context.getContextHandler().addEventListener(new HttpSessionListener()
-            {
-                @Override
-                public void sessionDestroyed(HttpSessionEvent se)
-                {
-                }
-
-                @Override
-                public void sessionCreated(HttpSessionEvent se)
-                {                    
-                    //if current request is authenticated, then as we have just created the session, mark it as secure, as it has not yet been returned to a user
-                    HttpChannel<?> channel = HttpChannel.getCurrentHttpChannel();              
-                    
-                    if (channel == null)
-                        return;
-                    Request request = channel.getRequest();
-                    if (request == null)
-                        return;
-                    
-                    if (request.isSecure())
-                    {
-                        se.getSession().setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
-                    }
-                }
-            });
         }
 
         // complicated resolution of login and identity service to handle
@@ -445,6 +415,7 @@
     /** Set renew the session on Authentication.
      * <p>
      * If set to true, then on authentication, the session associated with a reqeuest is invalidated and replaced with a new session.
+     * @param renew true to renew the authentication on session
      * @see org.eclipse.jetty.security.Authenticator.AuthConfiguration#isSessionRenewedOnAuthentication()
      */
     public void setSessionRenewedOnAuthentication(boolean renew)
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java
index 3155b43..fa61070 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SpnegoLoginService.java
@@ -21,6 +21,7 @@
 import java.util.Properties;
 
 import javax.security.auth.Subject;
+import javax.servlet.ServletRequest;
 
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.B64Code;
@@ -112,7 +113,7 @@
      * username will be null since the credentials will contain all the relevant info
      */
     @Override
-    public UserIdentity login(String username, Object credentials)
+    public UserIdentity login(String username, Object credentials, ServletRequest request)
     {
         String encodedAuthToken = (String)credentials;
 
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
index bfdeb73..1498f73 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
@@ -36,14 +36,12 @@
 import org.eclipse.jetty.server.Authentication.User;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.B64Code;
+import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.security.CertificateUtils;
 import org.eclipse.jetty.util.security.CertificateValidator;
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.security.Password;
 
-/**
- * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
- */
 public class ClientCertAuthenticator extends LoginAuthenticator
 {
     /** String name of keystore password property. */
@@ -82,12 +80,6 @@
         return Constraint.__CERT_AUTH;
     }
 
-    
-
-    /**
-     * @return Authentication for request
-     * @throws ServerAuthException
-     */
     @Override
     public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
     {
@@ -106,7 +98,7 @@
 
                 if (_validateCerts)
                 {
-                    KeyStore trustStore = getKeyStore(null,
+                    KeyStore trustStore = getKeyStore(
                             _trustStorePath, _trustStoreType, _trustStoreProvider,
                             _trustStorePassword == null ? null :_trustStorePassword.toString());
                     Collection<? extends CRL> crls = loadCRL(_crlPath);
@@ -147,6 +139,11 @@
         }
     }
 
+    @Deprecated
+    protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
+    {
+        return getKeyStore(storePath, storeType, storeProvider, storePassword);
+    }
     /* ------------------------------------------------------------ */
     /**
      * Loads keystore using an input stream or a file path in the same
@@ -155,17 +152,16 @@
      * Required for integrations to be able to override the mechanism
      * used to load a keystore in order to provide their own implementation.
      *
-     * @param storeStream keystore input stream
      * @param storePath path of keystore file
      * @param storeType keystore type
      * @param storeProvider keystore provider
      * @param storePassword keystore password
      * @return created keystore
-     * @throws Exception
+     * @throws Exception if unable to get keystore
      */
-    protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
+    protected KeyStore getKeyStore(String storePath, String storeType, String storeProvider, String storePassword) throws Exception
     {
-        return CertificateUtils.getKeyStore(storeStream, storePath, storeType, storeProvider, storePassword);
+        return CertificateUtils.getKeyStore(Resource.newResource(storePath), storeType, storeProvider, storePassword);
     }
 
     /* ------------------------------------------------------------ */
@@ -178,7 +174,7 @@
      * @param crlPath path of certificate revocation list file
      * @return a (possibly empty) collection view of java.security.cert.CRL objects initialized with the data from the
      *         input stream.
-     * @throws Exception
+     * @throws Exception if unable to load CRL
      */
     protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
     {
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
index 32f0461..4b6cae2 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
@@ -140,7 +140,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param response
+     * @param response the response
      * @return true if this response is from a deferred call to {@link #authenticate(ServletRequest)}
      */
     public static boolean isDeferred(HttpServletResponse response)
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
index 99a46a3..9359da1 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
@@ -34,6 +34,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.security.ServerAuthException;
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.server.Authentication;
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java
index 6a5b2a6..85babb7 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/FormAuthenticator.java
@@ -22,6 +22,7 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Locale;
+
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
@@ -41,7 +42,6 @@
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.Authentication.User;
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.server.UserIdentity;
@@ -64,8 +64,6 @@
  * to the /j_security_check URI within the context.  FormAuthentication uses
  * {@link SessionAuthentication} to wrap Authentication results so that they
  * are  associated with the session.</p>
- *
- *
  */
 public class FormAuthenticator extends LoginAuthenticator
 {
@@ -109,7 +107,7 @@
      * be remembered. If false, only the first uri that leads to a login
      * page redirect is remembered.
      * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=379909
-     * @param alwaysSave
+     * @param alwaysSave true to always save the uri
      */
     public void setAlwaysSaveUri (boolean alwaysSave)
     {
@@ -235,9 +233,8 @@
         
         //restore the original request's method on this request
         if (LOG.isDebugEnabled()) LOG.debug("Restoring original method {} for {} with method {}", method, juri,httpRequest.getMethod());
-        Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
-        HttpMethod m = HttpMethod.fromString(method);
-        base_request.setMethod(m,m.asString());
+        Request base_request = Request.getBaseRequest(request);
+        base_request.setMethod(method);
     }
 
     /* ------------------------------------------------------------ */
@@ -246,6 +243,9 @@
     {
         HttpServletRequest request = (HttpServletRequest)req;
         HttpServletResponse response = (HttpServletResponse)res;
+        Request base_request = Request.getBaseRequest(request);
+        Response base_response = base_request.getResponse();
+        
         String uri = request.getRequestURI();
         if (uri==null)
             uri=URIUtil.SLASH;
@@ -290,8 +290,6 @@
                     LOG.debug("authenticated {}->{}",form_auth,nuri);
 
                     response.setContentLength(0);
-                    Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
-                    Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
                     int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
                     base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri));
                     return form_auth;
@@ -317,8 +315,6 @@
                 else
                 {
                     LOG.debug("auth failed {}->{}",username,_formErrorPage);
-                    Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
-                    Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
                     int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
                     base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formErrorPage)));
                 }
@@ -358,7 +354,6 @@
                                 if (j_post!=null)
                                 {
                                     LOG.debug("auth rePOST {}->{}",authentication,j_uri);
-                                    Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
                                     base_request.setContentParameters(j_post);
                                 }
                                 session.removeAttribute(__J_URI);
@@ -393,7 +388,6 @@
 
                     if (MimeTypes.Type.FORM_ENCODED.is(req.getContentType()) && HttpMethod.POST.is(request.getMethod()))
                     {
-                        Request base_request = (req instanceof Request)?(Request)req:HttpChannel.getCurrentHttpChannel().getRequest();
                         MultiMap<String> formParameters = new MultiMap<>();
                         base_request.extractFormParameters(formParameters);
                         session.setAttribute(__J_POST, formParameters);
@@ -413,8 +407,6 @@
             else
             {
                 LOG.debug("challenge {}->{}",session.getId(),_formLoginPage);
-                Response base_response = HttpChannel.getCurrentHttpChannel().getResponse();
-                Request base_request = HttpChannel.getCurrentHttpChannel().getRequest();
                 int redirectCode = (base_request.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER);
                 base_response.sendRedirect(redirectCode, response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),_formLoginPage)));
             }
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
index 4f5a9ec..8518695 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
@@ -58,7 +58,7 @@
     /* ------------------------------------------------------------ */
     public UserIdentity login(String username, Object password, ServletRequest request)
     {
-        UserIdentity user = _loginService.login(username,password);
+        UserIdentity user = _loginService.login(username,password, request);
         if (user!=null)
         {
             renewSession((HttpServletRequest)request, (request instanceof Request? ((Request)request).getResponse() : null));
@@ -92,11 +92,11 @@
     /** Change the session id.
      * The session is changed to a new instance with a new ID if and only if:<ul>
      * <li>A session exists.
-     * <li>The {@link AuthConfiguration#isSessionRenewedOnAuthentication()} returns true.
+     * <li>The {@link org.eclipse.jetty.security.Authenticator.AuthConfiguration#isSessionRenewedOnAuthentication()} returns true.
      * <li>The session ID has been given to unauthenticated responses
      * </ul>
-     * @param request
-     * @param response
+     * @param request the request
+     * @param response the response
      * @return The new session.
      */
     protected HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
@@ -109,14 +109,14 @@
             {
                 //if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
                 //(indicated by SESSION_SECURED not being set on the session) then we should change id
-                if (httpSession.getAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED)!=Boolean.TRUE)
+                if (httpSession.getAttribute(AbstractSession.SESSION_CREATED_SECURE)!=Boolean.TRUE)
                 {
                     if (httpSession instanceof AbstractSession)
                     {
                         AbstractSession abstractSession = (AbstractSession)httpSession;
                         String oldId = abstractSession.getId();
                         abstractSession.renewId(request);
-                        abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
+                        abstractSession.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
                         if (abstractSession.isIdChanged() && response != null && (response instanceof Response))
                             ((Response)response).addCookie(abstractSession.getSessionManager().getSessionCookie(abstractSession, request.getContextPath(), request.isSecure()));
                         LOG.debug("renew {}->{}",oldId,abstractSession.getId());
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
index 6f58947..9155bf3 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java
@@ -71,7 +71,7 @@
         if (login_service==null)
             throw new IllegalStateException("!LoginService");
 
-        _userIdentity=login_service.login(_name,_credentials);
+        _userIdentity=login_service.login(_name,_credentials, null);
         LOG.debug("Deserialized and relogged in {}",this);
     }
 
@@ -89,7 +89,7 @@
         if (security!=null)
             security.logout(this);
         if (_session!=null)
-            _session.removeAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED);
+            _session.removeAttribute(AbstractSession.SESSION_CREATED_SECURE);
     }
 
     @Override
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
index 182635a..f201606 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
@@ -46,7 +46,7 @@
 
     /**
      * Allow for a custom authMethod value to be set for instances where SPENGO may not be appropriate
-     * @param authMethod
+     * @param authMethod the auth method
      */
     public SpnegoAuthenticator( String authMethod )
     {
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
index 12b13ef..7ea18e2 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/AliasedConstraintTest.java
@@ -18,8 +18,10 @@
 

 package org.eclipse.jetty.security;

 

-import static org.hamcrest.Matchers.*;

-import static org.junit.Assert.*;

+import static org.hamcrest.Matchers.containsString;

+import static org.hamcrest.Matchers.startsWith;

+import static org.junit.Assert.assertThat;

+import static org.junit.Assert.fail;

 

 import java.util.ArrayList;

 import java.util.Collection;

@@ -29,9 +31,12 @@
 

 import org.eclipse.jetty.http.HttpStatus;

 import org.eclipse.jetty.server.Connector;

+import org.eclipse.jetty.server.Handler;

 import org.eclipse.jetty.server.LocalConnector;

 import org.eclipse.jetty.server.Server;

 import org.eclipse.jetty.server.handler.ContextHandler;

+import org.eclipse.jetty.server.handler.DefaultHandler;

+import org.eclipse.jetty.server.handler.HandlerList;

 import org.eclipse.jetty.server.handler.ResourceHandler;

 import org.eclipse.jetty.server.session.SessionHandler;

 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;

@@ -77,7 +82,10 @@
 

         context.setContextPath("/ctx");

         context.setResourceBase(MavenTestingUtils.getTestResourceDir("docroot").getAbsolutePath());

-        server.setHandler(context);

+        

+        HandlerList handlers = new HandlerList();

+        handlers.setHandlers(new Handler[]{context,new DefaultHandler()});

+        server.setHandler(handlers);

         context.setHandler(session);

         // context.addAliasCheck(new AllowSymLinkAliasChecker());

 

diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
index 8e9e977..002f7e6 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java
@@ -32,6 +32,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import javax.servlet.HttpConstraintElement;
 import javax.servlet.HttpMethodConstraintElement;
 import javax.servlet.ServletException;
@@ -219,8 +220,8 @@
 
     /**
      * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-1
-     * @ServletSecurity
-     * @throws Exception
+     * &#064;ServletSecurity
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_1() throws Exception
@@ -233,9 +234,9 @@
    
     /**
      * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-2
-     * @ServletSecurity(@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL))
+     * &#064;ServletSecurity(@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL))
      * 
-     * @throws Exception
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_2() throws Exception
@@ -252,7 +253,7 @@
     /**
      * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-3
      * @ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY))
-     * @throws Exception
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_3() throws Exception
@@ -269,7 +270,7 @@
     /**
      * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-4
      * @ServletSecurity(@HttpConstraint(rolesAllowed = "R1"))
-     * @throws Exception
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_4() throws Exception
@@ -293,7 +294,7 @@
      * @HttpMethodConstraint(value = "GET", rolesAllowed = "R1"),
      * @HttpMethodConstraint(value = "POST", rolesAllowed = "R1",
      *         transportGuarantee = TransportGuarantee.CONFIDENTIAL)})
-     * @throws Exception
+     * @throws Exception if test fails
      */ 
     @Test
     public void testSecurityElementExample13_5() throws Exception
@@ -318,7 +319,7 @@
     /**
      * Equivalent of Servlet Spec 3.1 pg 132, sec 13.4.1.1, Example 13-6
      * @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"), httpMethodConstraints = @HttpMethodConstraint("GET"))
-     * @throws Exception
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_6 () throws Exception
@@ -344,7 +345,7 @@
      * @ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"), 
      *                  httpMethodConstraints = @HttpMethodConstraint(value="TRACE",
      *                  emptyRoleSemantic = EmptyRoleSemantic.DENY))
-     * @throws Exception
+     * @throws Exception if test fails
      */
     @Test
     public void testSecurityElementExample13_7() throws Exception
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java
index f730e8f..5f9cb7d 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/DataConstraintsTest.java
@@ -20,7 +20,9 @@
 
 import java.io.IOException;
 import java.util.Arrays;
+
 import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -375,10 +377,10 @@
         response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n\r\n");
         Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden"));
 
-        response = _connector.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n Authorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n");
+        response = _connector.getResponses("GET /ctx/restricted/info HTTP/1.0\r\nAuthorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n");
         Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden"));
 
-        response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\n Authorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n");
+        response = _connectorS.getResponses("GET /ctx/restricted/info HTTP/1.0\r\nAuthorization: Basic YWRtaW46cGFzc3dvcmQ=\r\n\r\n");
         Assert.assertThat(response, Matchers.containsString("HTTP/1.1 403 Forbidden"));
 
     }
@@ -436,7 +438,7 @@
         }
 
         @Override
-        public UserIdentity login(String username, Object credentials)
+        public UserIdentity login(String username, Object credentials, ServletRequest request)
         {
             if("admin".equals(username) && "password".equals(credentials))
                     return new DefaultUserIdentity(null,null,new String[] { "admin" } );
diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java
index fc1a2f3..2ae011f 100644
--- a/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java
+++ b/jetty-security/src/test/java/org/eclipse/jetty/security/PropertyUserStoreTest.java
@@ -18,178 +18,176 @@
 
 package org.eclipse.jetty.security;
 
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.Writer;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.OS;
+import org.eclipse.jetty.toolchain.test.TestingDir;
 import org.eclipse.jetty.util.security.Credential;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
+import org.hamcrest.Matcher;
+import org.junit.Rule;
 import org.junit.Test;
 
 public class PropertyUserStoreTest
 {
-    String testFileDir = "target" + File.separator + "property-user-store-test";
-    String testFile = testFileDir + File.separator + "users.txt";
-
-    @Before
-    public void before() throws Exception
+    private final class UserCount implements PropertyUserStore.UserListener
     {
-        File file = new File(testFileDir);
-        file.mkdirs();
+        private final AtomicInteger userCount = new AtomicInteger();
+        private final List<String> users = new ArrayList<String>();
 
-        writeInitialUsers(testFile);
+        private UserCount()
+        {
+        }
+
+        public void update(String username, Credential credential, String[] roleArray)
+        {
+            if (!users.contains(username))
+            {
+                users.add(username);
+                userCount.getAndIncrement();
+            }
+        }
+
+        public void remove(String username)
+        {
+            users.remove(username);
+            userCount.getAndDecrement();
+        }
+
+        public void awaitCount(int expectedCount) throws InterruptedException
+        {
+            long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10);
+            
+            while (userCount.get() != expectedCount && (System.currentTimeMillis() < timeout))
+            {
+                TimeUnit.MILLISECONDS.sleep(100);
+            }
+            
+            assertThatCount(is(expectedCount));
+        }
+
+        public void assertThatCount(Matcher<Integer> matcher)
+        {
+            assertThat("User count",userCount.get(),matcher);
+        }
+
+        public void assertThatUsers(Matcher<Iterable<? super String>> matcher)
+        {
+            assertThat("Users list",users,matcher);
+        }
     }
 
-    @After
-    public void after() throws Exception
-    {
-        File file = new File(testFile);
+    @Rule
+    public TestingDir testdir = new TestingDir();
 
-        file.delete();
-    }
-
-    private void writeInitialUsers(String testFile) throws Exception
+    private File initUsersText() throws Exception
     {
-        try (Writer writer = new BufferedWriter(new FileWriter(testFile)))
+        Path dir = testdir.getDir().toPath().toRealPath();
+        FS.ensureDirExists(dir.toFile());
+        File users = dir.resolve("users.txt").toFile();
+        
+        try (Writer writer = new BufferedWriter(new FileWriter(users)))
         {
             writer.append("tom: tom, roleA\n");
             writer.append("dick: dick, roleB\n");
             writer.append("harry: harry, roleA, roleB\n");
         }
+        
+        return users;
     }
 
-    private void writeAdditionalUser(String testFile) throws Exception
+    private void addAdditionalUser(File usersFile, String userRef) throws Exception
     {
         Thread.sleep(1001);
-        try (Writer writer = new BufferedWriter(new FileWriter(testFile,true)))
+        try (Writer writer = new BufferedWriter(new FileWriter(usersFile,true)))
         {
-            writer.append("skip: skip, roleA\n");
+            writer.append(userRef);
         }
     }
 
     @Test
     public void testPropertyUserStoreLoad() throws Exception
     {
-        final AtomicInteger userCount = new AtomicInteger();
+        final UserCount userCount = new UserCount();
+        final File usersFile = initUsersText();
 
         PropertyUserStore store = new PropertyUserStore();
+        store.setConfigPath(usersFile);
 
-        store.setConfig(testFile);
-
-        store.registerUserListener(new PropertyUserStore.UserListener()
-        {
-
-            public void update(String username, Credential credential, String[] roleArray)
-            {
-                userCount.getAndIncrement();
-            }
-
-            public void remove(String username)
-            {
-
-            }
-        });
+        store.registerUserListener(userCount);
 
         store.start();
 
-        Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("tom"));
-        Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("dick"));
-        Assert.assertNotNull("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("harry"));
-        Assert.assertEquals(3,userCount.get());
+        assertThat("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("tom"), notNullValue());
+        assertThat("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("dick"), notNullValue());
+        assertThat("Failed to retrieve UserIdentity directly from PropertyUserStore", store.getUserIdentity("harry"), notNullValue());
+        userCount.assertThatCount(is(3));
+        userCount.awaitCount(3);
     }
 
     @Test
     public void testPropertyUserStoreLoadUpdateUser() throws Exception
     {
-
-        final AtomicInteger userCount = new AtomicInteger();
-
-        final List<String> users = new ArrayList<String>();
+        assumeThat("Skipping on OSX", OS.IS_OSX, is(false));
+        final UserCount userCount = new UserCount();
+        final File usersFile = initUsersText();
 
         PropertyUserStore store = new PropertyUserStore();
-        store.setRefreshInterval(1);
-        store.setConfig(testFile);
+        store.setHotReload(true);
+        store.setConfigPath(usersFile);
 
-        store.registerUserListener(new PropertyUserStore.UserListener()
-        {
-            public void update(String username, Credential credential, String[] roleArray)
-            {
-                if (!users.contains(username))
-                {
-                    users.add(username);
-                    userCount.getAndIncrement();
-                }
-            }
-
-            public void remove(String username)
-            {
-
-            }
-        });
+        store.registerUserListener(userCount);
 
         store.start();
-        Assert.assertEquals(3,userCount.get());
+        
+        userCount.assertThatCount(is(3));
 
-        writeAdditionalUser(testFile);
+        addAdditionalUser(usersFile,"skip: skip, roleA\n");
 
-        long start = System.currentTimeMillis();
-        while (userCount.get() < 4 && (System.currentTimeMillis() - start) < 10000)
-        {
-            Thread.sleep(10);
-        }
+        userCount.awaitCount(4);
 
-        Assert.assertNotNull("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip"));
-        Assert.assertEquals(4,userCount.get());
-
-        Assert.assertTrue(users.contains("skip"));
+        assertThat("Failed to retrieve UserIdentity from PropertyUserStore directly", store.getUserIdentity("skip"), notNullValue());
+        
+        userCount.assertThatCount(is(4));
+        userCount.assertThatUsers(hasItem("skip"));
     }
 
     @Test
     public void testPropertyUserStoreLoadRemoveUser() throws Exception
     {
-        writeAdditionalUser(testFile);
-
-        final AtomicInteger userCount = new AtomicInteger();
-
-        final List<String> users = new ArrayList<String>();
+        assumeThat("Skipping on OSX", OS.IS_OSX, is(false));
+        final UserCount userCount = new UserCount();
+        // initial user file (3) users
+        final File usersFile = initUsersText();
+        
+        // adding 4th user
+        addAdditionalUser(usersFile,"skip: skip, roleA\n");
 
         PropertyUserStore store = new PropertyUserStore();
-        store.setRefreshInterval(2);
-        store.setConfig(testFile);
+        store.setHotReload(true);
+        store.setConfigPath(usersFile);
 
-        store.registerUserListener(new PropertyUserStore.UserListener()
-        {
-
-            public void update(String username, Credential credential, String[] roleArray)
-            {
-                if (!users.contains(username))
-                {
-                    users.add(username);
-                    userCount.getAndIncrement();
-                }
-            }
-
-            public void remove(String username)
-            {
-                users.remove(username);
-                userCount.getAndDecrement();
-            }
-        });
+        store.registerUserListener(userCount);
 
         store.start();
 
-        Assert.assertEquals(4,userCount.get());
+        userCount.assertThatCount(is(4));
 
-        Thread.sleep(2000);
-        writeInitialUsers(testFile);
-        Thread.sleep(3000);
-        Assert.assertEquals(3,userCount.get());
+        // rewrite file with original 3 users
+        initUsersText();
+        
+        userCount.awaitCount(3);
     }
-
 }
diff --git a/jetty-security/src/test/resources/jetty-logging.properties b/jetty-security/src/test/resources/jetty-logging.properties
new file mode 100755
index 0000000..24d5e3a
--- /dev/null
+++ b/jetty-security/src/test/resources/jetty-logging.properties
@@ -0,0 +1,7 @@
+# Setup default logging implementation for during testing
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+
+#org.eclipse.jetty.LEVEL=DEBUG
+
+#org.eclipse.jetty.util.PathWatcher.LEVEL=DEBUG
+#org.eclipse.jetty.util.PathWatcher.Noisy.LEVEL=OFF
diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml
index 6e9e89f..744862e 100644
--- a/jetty-server/pom.xml
+++ b/jetty-server/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-server</artifactId>
@@ -15,63 +15,16 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <id>generate-manifest</id>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package>
-                <_nouses>true</_nouses>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <executions>
           <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-          <execution>
             <id>test-jar</id>
             <goals>
               <goal>test-jar</goal>
             </goals>
           </execution>
         </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
diff --git a/jetty-server/src/main/config/etc/home-base-warning.xml b/jetty-server/src/main/config/etc/home-base-warning.xml
index b83f36f..4d568f1 100644
--- a/jetty-server/src/main/config/etc/home-base-warning.xml
+++ b/jetty-server/src/main/config/etc/home-base-warning.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
 <!-- Display a Warning Message if {jetty.home} == {jetty.base}     -->
 <!-- ============================================================= -->
 <Configure id="homeBaseWarning" class="org.eclipse.jetty.server.HomeBaseWarning">
-</Configure>
\ No newline at end of file
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-debug.xml b/jetty-server/src/main/config/etc/jetty-debug.xml
index 52b4bdb..2e47a5f 100644
--- a/jetty-server/src/main/config/etc/jetty-debug.xml
+++ b/jetty-server/src/main/config/etc/jetty-debug.xml
@@ -1,23 +1,36 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
-<!-- Mixin the DebugHandler                                          -->
+<!-- The DebugListener                                               -->
 <!-- =============================================================== -->
 
-
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
-    <Get id="oldhandler" name="handler"/>
-    <Set name="handler">
-      <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler">
-        <Set name="handler"><Ref refid="oldhandler"/></Set>
-	<Set name="outputStream">
-	  <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
-	    <Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
-	    <Arg type="boolean">true</Arg> <!-- append -->
-	    <Arg type="int">90</Arg> <!-- retain days -->
-	  </New>
-	</Set>
+  <New id="DebugListener" class="org.eclipse.jetty.server.DebugListener">
+    <Arg name="outputStream">
+      <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
+        <Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
+        <Arg type="boolean"><Property name="jetty.debug.append" default="true"/></Arg>
+        <Arg type="int"><Property name="jetty.debug.retainDays" default="14"/></Arg>
+        <Arg>
+          <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.debug.timezone" default="GMT"/></Arg></Call>
+        </Arg>
       </New>
-    </Set>
+    </Arg>
+    <Arg name="showHeaders" type="boolean"><Property name="jetty.debug.showHeaders" default="true"/></Arg>
+    <Arg name="renameThread" type="boolean"><Property name="jetty.debug.renameThread" default="false"/></Arg>
+    <Arg name="dumpContext" type="boolean"><Property name="jetty.debug.dumpContext" default="true"/></Arg>
+  </New>
+ 
+  <Call name="addBean"><Arg><Ref refid="DebugListener"/></Arg></Call>
+ 
+  <Ref refid="DeploymentManager">
+    <Call name="addLifeCycleBinding">
+      <Arg>
+        <New class="org.eclipse.jetty.deploy.bindings.DebugListenerBinding">
+          <Arg><Ref refid="DebugListener"/></Arg>
+        </New>
+      </Arg>
+    </Call>
+  </Ref>
 </Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-debuglog.xml b/jetty-server/src/main/config/etc/jetty-debuglog.xml
new file mode 100644
index 0000000..adbb10a
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-debuglog.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- =============================================================== -->
+<!-- The DebugHandler                                                -->
+<!-- =============================================================== -->
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+  <Get id="oldhandler" name="handler"/>
+  <Set name="handler">
+    <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler">
+      <Set name="handler"><Ref refid="oldhandler"/></Set>
+      <Set name="outputStream">
+        <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
+          <Arg type="String"><Property name="jetty.debuglog.dir" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
+          <Arg type="boolean"><Property name="jetty.debuglog.append" default="true"/></Arg>
+          <Arg type="int"><Property name="jetty.debuglog.retainDays" default="90"/></Arg>
+          <Arg>
+            <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.debuglog.timezone" default="GMT"/></Arg></Call>
+          </Arg>
+        </New>
+      </Set>
+    </New>
+  </Set>
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-gzip.xml b/jetty-server/src/main/config/etc/jetty-gzip.xml
new file mode 100644
index 0000000..f26ef0b
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-gzip.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- =============================================================== -->
+<!-- Mixin the GZIP Handler                                          -->
+<!-- This applies the GZIP Handler to the entire server              -->
+<!-- If a GZIP handler is required for an individual context, then   -->
+<!-- use a context XML (see test.xml example in distribution)        -->
+<!-- =============================================================== -->
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+  <Get id="next" name="handler" />
+  <Set name="handler">
+    <New id="GzipHandler" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
+      <Set name="handler"><Ref refid="next" /></Set>
+      <Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="2048"/></Set>
+      <Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
+      <Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
+      <Set name="excludedAgentPatterns">
+        <Array type="String">
+          <Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>
+        </Array>
+      </Set>
+
+      <Set name="includedMethods">
+        <Array type="String">
+          <Item>GET</Item>
+        </Array>
+      </Set>
+
+      <!--
+      <Set name="includedPaths">
+        <Array type="String">
+          <Item>/*</Item>
+        </Array>
+      </Set>
+      -->
+
+      <!--
+      <Set name="excludedPaths">
+        <Array type="String">
+          <Item>*.gz</Item>
+        </Array>
+      </Set>
+      -->
+
+      <!--
+      <Call name="addIncludedMimeTypes">
+        <Arg><Array type="String">
+          <Item>some/type</Item>
+        </Array></Arg>
+      </Call>
+      -->
+
+      <!--
+      <Call name="addExcludedMimeTypes">
+        <Arg><Array type="String">
+          <Item>some/type</Item>
+        </Array></Arg>
+      </Call>
+      -->
+
+    </New>
+  </Set>
+</Configure>
+
+
diff --git a/jetty-server/src/main/config/etc/jetty-http.xml b/jetty-server/src/main/config/etc/jetty-http.xml
index 1459ba8..ebeed5d 100644
--- a/jetty-server/src/main/config/etc/jetty-http.xml
+++ b/jetty-server/src/main/config/etc/jetty-http.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
 <!-- Configure the Jetty Server instance with an ID "Server"       -->
@@ -20,10 +20,10 @@
   <!-- =========================================================== -->
   <Call name="addConnector">
     <Arg>
-      <New class="org.eclipse.jetty.server.ServerConnector">
+      <New id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
         <Arg name="server"><Ref refid="Server" /></Arg>
-        <Arg name="acceptors" type="int"><Property name="http.acceptors" default="-1"/></Arg>
-        <Arg name="selectors" type="int"><Property name="http.selectors" default="-1"/></Arg>
+        <Arg name="acceptors" type="int"><Property name="jetty.http.acceptors" deprecated="http.acceptors" default="-1"/></Arg>
+        <Arg name="selectors" type="int"><Property name="jetty.http.selectors" deprecated="http.selectors" default="-1"/></Arg>
         <Arg name="factories">
           <Array type="org.eclipse.jetty.server.ConnectionFactory">
             <Item>
@@ -33,13 +33,12 @@
             </Item>
           </Array>
         </Arg>
-        <Set name="host"><Property name="jetty.host" /></Set>
-        <Set name="port"><Property name="jetty.port" default="80" /></Set>
-        <Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set>
-        <Set name="soLingerTime"><Property name="http.soLingerTime" default="-1"/></Set>
-        <Set name="acceptorPriorityDelta"><Property name="http.acceptorPriorityDelta" default="0"/></Set>
-        <Set name="selectorPriorityDelta"><Property name="http.selectorPriorityDelta" default="0"/></Set>
-        <Set name="acceptQueueSize"><Property name="http.acceptQueueSize" default="0"/></Set>
+        <Set name="host"><Property name="jetty.http.host" deprecated="jetty.host" /></Set>
+        <Set name="port"><Property name="jetty.http.port" deprecated="jetty.port" default="8080" /></Set>
+        <Set name="idleTimeout"><Property name="jetty.http.idleTimeout" deprecated="http.timeout" default="30000"/></Set>
+        <Set name="soLingerTime"><Property name="jetty.http.soLingerTime" deprecated="http.soLingerTime" default="-1"/></Set>
+        <Set name="acceptorPriorityDelta"><Property name="jetty.http.acceptorPriorityDelta" deprecated="http.acceptorPriorityDelta" default="0"/></Set>
+        <Set name="acceptQueueSize"><Property name="jetty.http.acceptQueueSize" deprecated="http.acceptQueueSize" default="0"/></Set>
       </New>
     </Arg>
   </Call>
diff --git a/jetty-server/src/main/config/etc/jetty-https.xml b/jetty-server/src/main/config/etc/jetty-https.xml
index 5eab5c5..c9d497e 100644
--- a/jetty-server/src/main/config/etc/jetty-https.xml
+++ b/jetty-server/src/main/config/etc/jetty-https.xml
@@ -1,53 +1,28 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
 <!-- Configure a HTTPS connector.                                  -->
 <!-- This configuration must be used in conjunction with jetty.xml -->
 <!-- and jetty-ssl.xml.                                            -->
 <!-- ============================================================= -->
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
 
-  <!-- =========================================================== -->
-  <!-- Add a HTTPS Connector.                                      -->
-  <!-- Configure an o.e.j.server.ServerConnector with connection   -->
-  <!-- factories for TLS (aka SSL) and HTTP to provide HTTPS.      -->
-  <!-- All accepted TLS connections are wired to a HTTP connection.-->
-  <!--                                                             -->
-  <!-- Consult the javadoc of o.e.j.server.ServerConnector,        -->
-  <!-- o.e.j.server.SslConnectionFactory and                       -->
-  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
-  <!-- that may be set here.                                       -->
-  <!-- =========================================================== -->
-  <Call id="httpsConnector" name="addConnector">
+  <Call name="addIfAbsentConnectionFactory">
     <Arg>
-      <New class="org.eclipse.jetty.server.ServerConnector">
-        <Arg name="server"><Ref refid="Server" /></Arg>
-        <Arg name="acceptors" type="int"><Property name="ssl.acceptors" default="-1"/></Arg>
-        <Arg name="selectors" type="int"><Property name="ssl.selectors" default="-1"/></Arg>
-        <Arg name="factories">
-          <Array type="org.eclipse.jetty.server.ConnectionFactory">
-            <Item>
-              <New class="org.eclipse.jetty.server.SslConnectionFactory">
-                <Arg name="next">http/1.1</Arg>
-                <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
-              </New>
-            </Item>
-            <Item>
-              <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                <Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
-              </New>
-            </Item>
-          </Array>
-        </Arg>
-        <Set name="host"><Property name="jetty.host" /></Set>
-        <Set name="port"><Property name="https.port" default="443" /></Set>
-        <Set name="idleTimeout"><Property name="https.timeout" default="30000"/></Set>
-        <Set name="soLingerTime"><Property name="https.soLingerTime" default="-1"/></Set>
-        <Set name="acceptorPriorityDelta"><Property name="ssl.acceptorPriorityDelta" default="0"/></Set>
-        <Set name="selectorPriorityDelta"><Property name="ssl.selectorPriorityDelta" default="0"/></Set>
-        <Set name="acceptQueueSize"><Property name="https.acceptQueueSize" default="0"/></Set>
+      <New class="org.eclipse.jetty.server.SslConnectionFactory">
+        <Arg name="next">http/1.1</Arg>
+        <Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
       </New>
     </Arg>
   </Call>
+
+  <Call name="addConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.server.HttpConnectionFactory">
+        <Arg name="config"><Ref refid="sslHttpConfig" /></Arg>
+      </New>
+    </Arg>
+  </Call>
+  
 </Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-ipaccess.xml b/jetty-server/src/main/config/etc/jetty-ipaccess.xml
index a44aa1d..d8236a9 100644
--- a/jetty-server/src/main/config/etc/jetty-ipaccess.xml
+++ b/jetty-server/src/main/config/etc/jetty-ipaccess.xml
@@ -1,31 +1,31 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
-<!-- Mixin the Statistics Handler                                    -->
+<!-- The IP Access Handler                                           -->
 <!-- =============================================================== -->
 
-
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
-    <Get id="oldhandler" name="handler"/>
+  <Get id="oldhandler" name="handler"/>
 
-    <Set name="handler">
-     <New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
+  <Set name="handler">
+    <New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
       <Set name="handler"><Ref refid="oldhandler"/></Set>
       <Set name="white">
         <Array type="String">
-	      <Item>127.0.0.1</Item>
-	      <Item>127.0.0.2/*.html</Item>
-	    </Array>
+          <Item>127.0.0.1</Item>
+          <Item>127.0.0.2/*.html</Item>
+        </Array>
       </Set>
       <Set name="black">
         <Array type="String">
-	      <Item>127.0.0.1/blacklisted</Item>
-	      <Item>127.0.0.2/black.html</Item>
-	    </Array>
+          <Item>127.0.0.1/blacklisted</Item>
+          <Item>127.0.0.2/black.html</Item>
+        </Array>
       </Set>
       <Set name="whiteListByPath">false</Set>
-     </New>
-    </Set>
+    </New>
+  </Set>
+
 </Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-jdbc-sessions.xml b/jetty-server/src/main/config/etc/jetty-jdbc-sessions.xml
new file mode 100644
index 0000000..46beaf2
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-jdbc-sessions.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+
+  <!-- ===================================================================== -->
+  <!-- Configure a SessionIdManager                                          -->
+  <!-- ===================================================================== -->
+  <Set name="sessionIdManager">
+    <New id="idMgr" class="org.eclipse.jetty.server.session.JDBCSessionIdManager">
+      <Arg>
+        <Ref refid="Server"/>
+      </Arg>
+      <Set name="workerName"><Property name="jetty.jdbcSession.workerName" default="node1"/></Set>
+      <Set name="scavengeInterval"><Property name="jetty.jdbcSession.scavenge" default="1800"/></Set>
+
+      <!-- ===================================================================== -->
+      <!-- Uncomment either the datasource or driver setup and configure         -->
+      <!-- ===================================================================== -->
+
+      <!--
+          <Set name="DatasourceName"><Property name="jetty.jdbcSession.datasource" default="javax.sql.DataSource/default"/></Set>
+      -->
+      <!--
+        <Call name="setDriverInfo">
+          <Arg><Property name="jetty.jdbcSession.driverClass"/></Arg>
+          <Arg><Property name="jetty.jdbcSession.connectionURL"/></Arg>
+        </Call>
+      -->
+    </New>
+  </Set>
+
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-lowresources.xml b/jetty-server/src/main/config/etc/jetty-lowresources.xml
index 060919a..f6442c8 100644
--- a/jetty-server/src/main/config/etc/jetty-lowresources.xml
+++ b/jetty-server/src/main/config/etc/jetty-lowresources.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Mixin the Low Resources Monitor                                 -->
@@ -10,12 +10,12 @@
     <Arg>
       <New class="org.eclipse.jetty.server.LowResourceMonitor">
         <Arg name="server"><Ref refid='Server'/></Arg>
-        <Set name="period"><Property name="lowresources.period" default="1000"/></Set>
-        <Set name="lowResourcesIdleTimeout"><Property name="lowresources.lowResourcesIdleTimeout" default="200"/></Set>
-        <Set name="monitorThreads"><Property name="lowresources.monitorThreads" default="true"/></Set>
-        <Set name="maxConnections"><Property name="lowresources.maxConnections" default="0"/></Set>
-        <Set name="maxMemory"><Property name="lowresources.maxMemory" default="0"/></Set>
-        <Set name="maxLowResourcesTime"><Property name="lowresources.maxLowResourcesTime" default="5000"/></Set>
+        <Set name="period"><Property name="jetty.lowresources.period" deprecated="lowresources.period" default="1000"/></Set>
+        <Set name="lowResourcesIdleTimeout"><Property name="jetty.lowresources.idleTimeout" deprecated="lowresources.lowResourcesIdleTimeout" default="1000"/></Set>
+        <Set name="monitorThreads"><Property name="jetty.lowresources.monitorThreads" deprecated="lowresources.monitorThreads" default="true"/></Set>
+        <Set name="maxConnections"><Property name="jetty.lowresources.maxConnections" deprecated="lowresources.maxConnections" default="0"/></Set>
+        <Set name="maxMemory"><Property name="jetty.lowresources.maxMemory" deprecated="lowresources.maxMemory" default="0"/></Set>
+        <Set name="maxLowResourcesTime"><Property name="jetty.lowresources.maxLowResourcesTime" deprecated="lowresources.maxLowResourcesTime" default="5000"/></Set>
       </New>
     </Arg>
   </Call>
diff --git a/jetty-server/src/main/config/etc/jetty-proxy-protocol-ssl.xml b/jetty-server/src/main/config/etc/jetty-proxy-protocol-ssl.xml
new file mode 100644
index 0000000..91452f2
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-proxy-protocol-ssl.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+  <Call name="addFirstConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.server.ProxyConnectionFactory"/>
+    </Arg>
+  </Call>
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-proxy-protocol.xml b/jetty-server/src/main/config/etc/jetty-proxy-protocol.xml
new file mode 100644
index 0000000..5169c4f
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-proxy-protocol.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
+  <Call name="addFirstConnectionFactory">
+    <Arg>
+      <New class="org.eclipse.jetty.server.ProxyConnectionFactory"/>
+    </Arg>
+  </Call>
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-requestlog.xml b/jetty-server/src/main/config/etc/jetty-requestlog.xml
index 135885e..3ef2c32 100644
--- a/jetty-server/src/main/config/etc/jetty-requestlog.xml
+++ b/jetty-server/src/main/config/etc/jetty-requestlog.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the Jetty Request Log                                 -->
@@ -7,26 +7,23 @@
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
   <!-- =========================================================== -->
-  <!-- Configure Request Log -->
+  <!-- Configure Request Log for Server                            -->
+  <!-- (Use RequestLogHandler for a context specific RequestLog    -->
   <!-- =========================================================== -->
-  <Ref refid="Handlers">
-    <Call name="addHandler">
-      <Arg>
-        <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
-          <Set name="requestLog">
-            <New id="RequestLogImpl" class="org.eclipse.jetty.server.AsyncNCSARequestLog">
-              <Set name="filename"><Property name="jetty.base" default="." /><Property name="requestlog.filename" default="/logs/yyyy_mm_dd.request.log"/></Set>
-              <Set name="filenameDateFormat"><Property name="requestlog.filenameDateFormat" default="yyyy_MM_dd"/></Set>
-              <Set name="retainDays"><Property name="requestlog.retain" default="90"/></Set>
-              <Set name="append"><Property name="requestlog.append" default="false"/></Set>
-              <Set name="extended"><Property name="requestlog.extended" default="false"/></Set>
-              <Set name="logCookies"><Property name="requestlog.cookies" default="false"/></Set>
-              <Set name="LogTimeZone"><Property name="requestlog.timezone" default="GMT"/></Set>
-            </New>
-          </Set>
-        </New>
-      </Arg>
-    </Call>
-  </Ref>
-
+  <Set name="RequestLog">
+    <New id="RequestLog" class="org.eclipse.jetty.server.AsyncNCSARequestLog">
+      <Set name="filename"><Property name="jetty.base" default="." /><Property>
+          <Name>jetty.requestlog.filePath</Name>
+          <Deprecated>requestlog.filename</Deprecated>
+          <Default><Property name="jetty.requestlog.dir" default="/logs"/>/yyyy_mm_dd.request.log</Default>
+        </Property>
+      </Set>
+      <Set name="filenameDateFormat"><Property name="jetty.requestlog.filenameDateFormat" deprecated="requestlog.filenameDateFormat" default="yyyy_MM_dd"/></Set>
+      <Set name="retainDays"><Property name="jetty.requestlog.retainDays" deprecated="requestlog.retain" default="90"/></Set>
+      <Set name="append"><Property name="jetty.requestlog.append" deprecated="requestlog.append" default="false"/></Set>
+      <Set name="extended"><Property name="jetty.requestlog.extended" deprecated="requestlog.extended" default="false"/></Set>
+      <Set name="logCookies"><Property name="jetty.requestlog.cookies" deprecated="requestlog.cookies" default="false"/></Set>
+      <Set name="LogTimeZone"><Property name="jetty.requestlog.timezone" deprecated="requestlog.timezone" default="GMT"/></Set>
+    </New>
+  </Set>
 </Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-ssl-context.xml b/jetty-server/src/main/config/etc/jetty-ssl-context.xml
new file mode 100644
index 0000000..68b802c
--- /dev/null
+++ b/jetty-server/src/main/config/etc/jetty-ssl-context.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<!-- ============================================================= -->
+<!-- SSL ContextFactory configuration                              -->
+<!-- ============================================================= -->
+<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
+  <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" deprecated="jetty.keystore" default="etc/keystore"/></Set>
+  <Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" deprecated="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
+  <Set name="KeyStoreType"><Property name="jetty.sslContext.keyStoreType" default="JKS"/></Set>
+  <Set name="KeyStoreProvider"><Property name="jetty.sslContext.keyStoreProvider"/></Set>
+  <Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" deprecated="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
+  <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" deprecated="jetty.truststore" default="etc/keystore"/></Set>
+  <Set name="TrustStorePassword"><Property name="jetty.sslContext.trustStorePassword" deprecated="jetty.truststore.password"/></Set>
+  <Set name="TrustStoreType"><Property name="jetty.sslContext.trustStoreType"/></Set>
+  <Set name="TrustStoreProvider"><Property name="jetty.sslContext.trustStoreProvider"/></Set>
+  <Set name="EndpointIdentificationAlgorithm"></Set>
+  <Set name="NeedClientAuth"><Property name="jetty.sslContext.needClientAuth" deprecated="jetty.ssl.needClientAuth" default="false"/></Set>
+  <Set name="WantClientAuth"><Property name="jetty.sslContext.wantClientAuth" deprecated="jetty.ssl.wantClientAuth" default="false"/></Set>
+  <Set name="ExcludeCipherSuites">
+   <Array type="String">
+    <Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
+    <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
+    <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
+    <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
+    <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
+    <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
+    <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
+   </Array>
+  </Set>
+  <Set name="useCipherSuitesOrder"><Property name="jetty.sslContext.useCipherSuitesOrder" default="true"/></Set>
+</Configure>
diff --git a/jetty-server/src/main/config/etc/jetty-ssl.xml b/jetty-server/src/main/config/etc/jetty-ssl.xml
index 4ac2d3e..a079c1f 100644
--- a/jetty-server/src/main/config/etc/jetty-ssl.xml
+++ b/jetty-server/src/main/config/etc/jetty-ssl.xml
@@ -1,31 +1,40 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ============================================================= -->
-<!-- Configure a TLS (SSL) Context Factory                         -->
-<!-- This configuration must be used in conjunction with jetty.xml -->
-<!-- and either jetty-https.xml or jetty-spdy.xml (but not both)   -->
+<!-- Base SSL configuration                                        -->
+<!-- This configuration needs to be used together with 1 or more   -->
+<!-- of jetty-https.xml or jetty-http2.xml                         -->
 <!-- ============================================================= -->
-<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-  <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set>
-  <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
-  <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
-  <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set>
-  <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
-  <Set name="EndpointIdentificationAlgorithm"></Set>
-  <Set name="NeedClientAuth"><Property name="jetty.ssl.needClientAuth" default="false"/></Set>
-  <Set name="WantClientAuth"><Property name="jetty.ssl.wantClientAuth" default="false"/></Set>
-  <Set name="ExcludeCipherSuites">
-    <Array type="String">
-      <Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
-      <Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
-      <Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
-      <Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
-      <Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
-      <Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
-      <Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
-    </Array>
-  </Set>
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+  <!-- =========================================================== -->
+  <!-- Add a SSL Connector with no protocol factories              -->
+  <!-- =========================================================== -->
+  <Call  name="addConnector">
+    <Arg>
+      <New id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
+        <Arg name="server"><Ref refid="Server" /></Arg>
+        <Arg name="acceptors" type="int"><Property name="jetty.ssl.acceptors" deprecated="ssl.acceptors" default="-1"/></Arg>
+        <Arg name="selectors" type="int"><Property name="jetty.ssl.selectors" deprecated="ssl.selectors" default="-1"/></Arg>
+        <Arg name="factories">
+          <Array type="org.eclipse.jetty.server.ConnectionFactory">
+            <!-- uncomment to support proxy protocol
+            <Item>
+              <New class="org.eclipse.jetty.server.ProxyConnectionFactory"/>
+            </Item>-->
+          </Array>
+        </Arg>
+
+        <Set name="host"><Property name="jetty.ssl.host" deprecated="jetty.host" /></Set>
+        <Set name="port"><Property name="jetty.ssl.port" deprecated="ssl.port" default="8443" /></Set>
+        <Set name="idleTimeout"><Property name="jetty.ssl.idleTimeout" deprecated="ssl.timeout" default="30000"/></Set>
+        <Set name="soLingerTime"><Property name="jetty.ssl.soLingerTime" deprecated="ssl.soLingerTime" default="-1"/></Set>
+        <Set name="acceptorPriorityDelta"><Property name="jetty.ssl.acceptorPriorityDelta" deprecated="ssl.acceptorPriorityDelta" default="0"/></Set>
+        <Set name="acceptQueueSize"><Property name="jetty.ssl.acceptQueueSize" deprecated="ssl.acceptQueueSize" default="0"/></Set>
+      </New>
+    </Arg>
+  </Call>
 
   <!-- =========================================================== -->
   <!-- Create a TLS specific HttpConfiguration based on the        -->
@@ -36,7 +45,13 @@
   <New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
     <Arg><Ref refid="httpConfig"/></Arg>
     <Call name="addCustomizer">
-      <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
+      <Arg>
+        <New class="org.eclipse.jetty.server.SecureRequestCustomizer">
+          <Arg name="sniHostCheck" type="boolean"><Property name="jetty.ssl.sniHostCheck" default="true"/></Arg>
+          <Arg name="stsMaxAgeSeconds" type="int"><Property name="jetty.ssl.stsMaxAgeSeconds" default="-1"/></Arg>
+          <Arg name="stsIncludeSubdomains" type="boolean"><Property name="jetty.ssl.stsIncludeSubdomains" default="false"/></Arg>
+        </New>
+      </Arg>
     </Call>
   </New>
 
diff --git a/jetty-server/src/main/config/etc/jetty-stats.xml b/jetty-server/src/main/config/etc/jetty-stats.xml
index 2e7a57c..4e01490 100644
--- a/jetty-server/src/main/config/etc/jetty-stats.xml
+++ b/jetty-server/src/main/config/etc/jetty-stats.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Mixin the Statistics Handler                                    -->
diff --git a/jetty-server/src/main/config/etc/jetty-xinetd.xml b/jetty-server/src/main/config/etc/jetty-xinetd.xml
deleted file mode 100644
index a4750de..0000000
--- a/jetty-server/src/main/config/etc/jetty-xinetd.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<!-- =============================================================== -->
-<!-- Configuration for starting up Jetty using inetd/xinetd          -->
-<!-- This feature requires at least Java 5                           -->
-<!--                                                                 -->
-<!-- Making it a mixin for convenience, but note that if used        -->
-<!-- with jetty.xml, Jetty will use multiple connectors              -->
-<!-- =============================================================== -->
-
-<!-- Sample xinetd configuration (restart xinetd after adding the configuration file)
-
-service jetty
-{
-    disable     = no
-
-    id          = jetty
-    type        = UNLISTED
-    wait        = yes
-    socket_type = stream
-
-    # change this
-    user        = username
-    group       = groupname
-    port        = 2001
-
-    # sample script for running jetty as a service
-    # replace $JETTY_HOME with /path/to/jetty_home/
-    server      = $JETTY_HOME/bin/jetty-xinetd.sh
-}
-
--->
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-    <Call name="addConnector">
-      <Arg>
-          <!-- Inherited channel (from inetd/xinetd) -->
-          <New class="org.eclipse.jetty.server.nio.InheritedChannelConnector">
-
-
-            <!-- Optional. Fallback in case System.inheritedChannel() does not give a ServerSocketChannel
-            <Set name="port"><Property name="jetty.service.port" default="8082"/></Set>
-            -->
-
-            <!-- sane defaults -->
-            <Set name="idleTimeout"><Property name="jetty.xinetd.idleTimeout" default="300000"/></Set>
-            <Set name="Acceptors"><Property name="jetty.xinetd.acceptors" default="2"/></Set>
-            <Set name="statsOn"><Property name="jetty.xinetd.statsOn" default="false"/></Set>
-          </New>
-      </Arg>
-    </Call>
-</Configure>
-
diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml
index d8708ef..5412979 100644
--- a/jetty-server/src/main/config/etc/jetty.xml
+++ b/jetty-server/src/main/config/etc/jetty.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Documentation of this file format can be found at:              -->
@@ -46,9 +46,9 @@
     <Arg name="threadpool"><New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool"/></Arg>
     -->
     <Get name="ThreadPool">
-      <Set name="minThreads" type="int"><Property name="threads.min" default="10"/></Set>
-      <Set name="maxThreads" type="int"><Property name="threads.max" default="200"/></Set>
-      <Set name="idleTimeout" type="int"><Property name="threads.timeout" default="60000"/></Set>
+      <Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
+      <Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
+      <Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
       <Set name="detailedDump">false</Set>
     </Get>
 
@@ -64,29 +64,31 @@
     <!-- =========================================================== -->
     <!-- Http Configuration.                                         -->
     <!-- This is a common configuration instance used by all         -->
-    <!-- connectors that can carry HTTP semantics (HTTP, HTTPS, SPDY)-->
+    <!-- connectors that can carry HTTP semantics (HTTP, HTTPS, etc.)-->
     <!-- It configures the non wire protocol aspects of the HTTP     -->
     <!-- semantic.                                                   -->
     <!--                                                             -->
     <!-- This configuration is only defined here and is used by      -->
-    <!-- reference from the jetty-http.xml, jetty-https.xml and      -->
-    <!-- jetty-spdy.xml configuration files which instantiate the    -->
-    <!-- connectors.                                                 -->
+    <!-- reference from other XML files such as jetty-http.xml,      -->
+    <!-- jetty-https.xml and other configuration files which         -->
+    <!-- instantiate the connectors.                                 -->
     <!--                                                             -->
     <!-- Consult the javadoc of o.e.j.server.HttpConfiguration       -->
     <!-- for all configuration that may be set here.                 -->
     <!-- =========================================================== -->
     <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-      <Set name="secureScheme">https</Set>
-      <Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
-      <Set name="outputBufferSize"><Property name="jetty.output.buffer.size" default="32768" /></Set>
-      <Set name="outputAggregationSize"><Property name="jetty.output.aggregation.size" default="8192" /></Set>
-      <Set name="requestHeaderSize"><Property name="jetty.request.header.size" default="8192" /></Set>
-      <Set name="responseHeaderSize"><Property name="jetty.response.header.size" default="8192" /></Set>
-      <Set name="sendServerVersion"><Property name="jetty.send.server.version" default="true" /></Set>
-      <Set name="sendDateHeader"><Property name="jetty.send.date.header" default="false" /></Set>
-      <Set name="headerCacheSize">512</Set>
-      <Set name="delayDispatchUntilContent"><Property name="jetty.delayDispatchUntilContent" default="false"/></Set>
+      <Set name="secureScheme"><Property name="jetty.httpConfig.secureScheme" default="https" /></Set>
+      <Set name="securePort"><Property name="jetty.httpConfig.securePort" deprecated="jetty.secure.port" default="8443" /></Set>
+      <Set name="outputBufferSize"><Property name="jetty.httpConfig.outputBufferSize" deprecated="jetty.output.buffer.size" default="32768" /></Set>
+      <Set name="outputAggregationSize"><Property name="jetty.httpConfig.outputAggregationSize" deprecated="jetty.output.aggregation.size" default="8192" /></Set>
+      <Set name="requestHeaderSize"><Property name="jetty.httpConfig.requestHeaderSize" deprecated="jetty.request.header.size" default="8192" /></Set>
+      <Set name="responseHeaderSize"><Property name="jetty.httpConfig.responseHeaderSize" deprecated="jetty.response.header.size" default="8192" /></Set>
+      <Set name="sendServerVersion"><Property name="jetty.httpConfig.sendServerVersion" deprecated="jetty.send.server.version" default="true" /></Set>
+      <Set name="sendDateHeader"><Property name="jetty.httpConfig.sendDateHeader" deprecated="jetty.send.date.header" default="false" /></Set>
+      <Set name="headerCacheSize"><Property name="jetty.httpConfig.headerCacheSize" default="512" /></Set>
+      <Set name="delayDispatchUntilContent"><Property name="jetty.httpConfig.delayDispatchUntilContent" deprecated="jetty.delayDispatchUntilContent" default="true"/></Set>
+      <Set name="maxErrorDispatches"><Property name="jetty.httpConfig.maxErrorDispatches" default="10"/></Set>
+      <Set name="blockingTimeout"><Property name="jetty.httpConfig.blockingTimeout" default="-1"/></Set>
       <!-- Uncomment to enable handling of X-Forwarded- style headers
       <Call name="addCustomizer">
         <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
@@ -94,7 +96,6 @@
       -->
     </New>
 
-
     <!-- =========================================================== -->
     <!-- Set the default handler structure for the Server            -->
     <!-- A handler collection is used to pass received requests to   -->
@@ -124,9 +125,9 @@
     <!-- =========================================================== -->
     <!-- extra server options                                        -->
     <!-- =========================================================== -->
-    <Set name="stopAtShutdown">true</Set>
+    <Set name="stopAtShutdown"><Property name="jetty.server.stopAtShutdown" default="true"/></Set>
     <Set name="stopTimeout">5000</Set>
-    <Set name="dumpAfterStart"><Property name="jetty.dump.start" default="false"/></Set>
-    <Set name="dumpBeforeStop"><Property name="jetty.dump.stop" default="false"/></Set>
+    <Set name="dumpAfterStart"><Property name="jetty.server.dumpAfterStart" deprecated="jetty.dump.start" default="false"/></Set>
+    <Set name="dumpBeforeStop"><Property name="jetty.server.dumpBeforeStop" deprecated="jetty.dump.stop" default="false"/></Set>
 
 </Configure>
diff --git a/jetty-server/src/main/config/etc/keystore b/jetty-server/src/main/config/etc/keystore
index 08f6cda..d6592f9 100644
--- a/jetty-server/src/main/config/etc/keystore
+++ b/jetty-server/src/main/config/etc/keystore
Binary files differ
diff --git a/jetty-server/src/main/config/modules/debug.mod b/jetty-server/src/main/config/modules/debug.mod
index f740ea2..0141699 100644
--- a/jetty-server/src/main/config/modules/debug.mod
+++ b/jetty-server/src/main/config/modules/debug.mod
@@ -3,7 +3,27 @@
 #
 
 [depend]
-server
+deploy
+
+[files]
+logs/
 
 [xml]
 etc/jetty-debug.xml
+
+[ini-template]
+
+## How many days to retain old log files
+# jetty.debug.retainDays=14
+
+## Timezone of the log entries
+# jetty.debug.timezone=GMT
+
+## Show Request/Response headers
+# jetty.debug.showHeaders=true
+
+## Rename threads while in context scope
+# jetty.debug.renameThread=false
+
+## Dump context as deployed
+# jetty.debug.dumpContext=true
diff --git a/jetty-server/src/main/config/modules/debuglog.mod b/jetty-server/src/main/config/modules/debuglog.mod
new file mode 100644
index 0000000..ba8b60a
--- /dev/null
+++ b/jetty-server/src/main/config/modules/debuglog.mod
@@ -0,0 +1,25 @@
+#
+# Debug module
+#
+
+[depend]
+server
+
+[files]
+logs/
+
+[xml]
+etc/jetty-debuglog.xml
+
+[ini-template]
+## Logging directory (relative to $jetty.base)
+# jetty.debuglog.dir=logs
+
+## Whether to append to existing file
+# jetty.debuglog.append=false
+
+## How many days to retain old log files
+# jetty.debuglog.retainDays=90
+
+## Timezone of the log entries
+# jetty.debuglog.timezone=GMT
diff --git a/jetty-server/src/main/config/modules/gzip.mod b/jetty-server/src/main/config/modules/gzip.mod
new file mode 100644
index 0000000..1efc834
--- /dev/null
+++ b/jetty-server/src/main/config/modules/gzip.mod
@@ -0,0 +1,23 @@
+#
+# GZIP module
+# Applies GzipHandler to entire server
+#
+
+[depend]
+server
+
+[xml]
+etc/jetty-gzip.xml
+
+[ini-template]
+## Minimum content length after which gzip is enabled
+# jetty.gzip.minGzipSize=2048
+
+## Check whether a file with *.gz extension exists
+# jetty.gzip.checkGzExists=false
+
+## Gzip compression level (-1 for default)
+# jetty.gzip.compressionLevel=-1
+
+## User agents for which gzip is disabled
+# jetty.gzip.excludedUserAgent=.*MSIE.6\.0.*
diff --git a/jetty-server/src/main/config/modules/http.mod b/jetty-server/src/main/config/modules/http.mod
index dc34bc3..01e9862 100644
--- a/jetty-server/src/main/config/modules/http.mod
+++ b/jetty-server/src/main/config/modules/http.mod
@@ -11,17 +11,26 @@
 [ini-template]
 ### HTTP Connector Configuration
 
-## HTTP port to listen on
-jetty.port=8080
+## Connector host/address to bind to
+# jetty.http.host=0.0.0.0
 
-## HTTP idle timeout in milliseconds
-http.timeout=30000
+## Connector port to listen on
+# jetty.http.port=8080
 
-## HTTP Socket.soLingerTime in seconds. (-1 to disable)
-# http.soLingerTime=-1
+## Connector idle timeout in milliseconds
+# jetty.http.idleTimeout=30000
 
-## Parameters to control the number and priority of acceptors and selectors
-# http.selectors=1
-# http.acceptors=1
-# http.selectorPriorityDelta=0
-# http.acceptorPriorityDelta=0
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.http.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.http.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.http.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.http.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.http.acceptorPriorityDelta=0
diff --git a/jetty-server/src/main/config/modules/https.mod b/jetty-server/src/main/config/modules/https.mod
index bd1b718..092e0d7 100644
--- a/jetty-server/src/main/config/modules/https.mod
+++ b/jetty-server/src/main/config/modules/https.mod
@@ -5,15 +5,9 @@
 [depend]
 ssl
 
+[optional]
+http2
+
 [xml]
 etc/jetty-https.xml
 
-[ini-template]
-## HTTPS Configuration
-# HTTP port to listen on
-https.port=8443
-# HTTPS idle timeout in milliseconds
-https.timeout=30000
-# HTTPS Socket.soLingerTime in seconds. (-1 to disable)
-# https.soLingerTime=-1
-
diff --git a/jetty-server/src/main/config/modules/jdbc-sessions.mod b/jetty-server/src/main/config/modules/jdbc-sessions.mod
new file mode 100644
index 0000000..d77ff04
--- /dev/null
+++ b/jetty-server/src/main/config/modules/jdbc-sessions.mod
@@ -0,0 +1,27 @@
+#
+# Jetty JDBC Session module
+#
+
+[depend]
+annotations
+webapp
+
+[xml]
+etc/jetty-jdbc-sessions.xml
+
+
+[ini-template]
+## JDBC Session config
+
+## Unique identifier for this node in the cluster
+# jetty.jdbcSession.workerName=node1
+
+## The interval in seconds between sweeps of the scavenger
+# jetty.jdbcSession.scavenge=600
+
+## Uncomment either the datasource name or driverClass and connectionURL
+# jetty.jdbcSession.datasource=sessions
+# jetty.jdbcSession.driverClass=changeme
+# jetty.jdbcSession.connectionURL=changeme
+
+
diff --git a/jetty-server/src/main/config/modules/lowresources.mod b/jetty-server/src/main/config/modules/lowresources.mod
index 99112d5..2f765d9 100644
--- a/jetty-server/src/main/config/modules/lowresources.mod
+++ b/jetty-server/src/main/config/modules/lowresources.mod
@@ -9,10 +9,20 @@
 etc/jetty-lowresources.xml
 
 [ini-template]
-## Low Resources Configuration
-# lowresources.period=1050
-# lowresources.lowResourcesIdleTimeout=200
-# lowresources.monitorThreads=true
-# lowresources.maxConnections=0
-# lowresources.maxMemory=0
-# lowresources.maxLowResourcesTime=5000
+## Scan period to look for low resources (in milliseconds)
+# jetty.lowresources.period=1000
+
+## The idle timeout to apply to low resources (in milliseconds)
+# jetty.lowresources.idleTimeout=1000
+
+## Whether to monitor ThreadPool threads for low resources
+# jetty.lowresources.monitorThreads=true
+
+## Max number of connections allowed before being in low resources mode
+# jetty.lowresources.maxConnections=0
+
+## Max memory allowed before being in low resources mode (in bytes)
+# jetty.lowresources.maxMemory=0
+
+## Max time a resource may stay in low resource mode before actions are taken (in milliseconds)
+# jetty.lowresources.maxLowResourcesTime=5000
diff --git a/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod
new file mode 100644
index 0000000..764d24b
--- /dev/null
+++ b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod
@@ -0,0 +1,9 @@
+#
+# PROXY Protocol Module - SSL
+#
+
+[depend]
+ssl
+
+[xml]
+etc/jetty-proxy-protocol-ssl.xml
diff --git a/jetty-server/src/main/config/modules/proxy-protocol.mod b/jetty-server/src/main/config/modules/proxy-protocol.mod
new file mode 100644
index 0000000..9df2700
--- /dev/null
+++ b/jetty-server/src/main/config/modules/proxy-protocol.mod
@@ -0,0 +1,9 @@
+#
+# PROXY Protocol Module - HTTP
+#
+
+[depend]
+http
+
+[xml]
+etc/jetty-proxy-protocol.xml
diff --git a/jetty-server/src/main/config/modules/requestlog.mod b/jetty-server/src/main/config/modules/requestlog.mod
index f5e0614..e27b246 100644
--- a/jetty-server/src/main/config/modules/requestlog.mod
+++ b/jetty-server/src/main/config/modules/requestlog.mod
@@ -12,19 +12,26 @@
 logs/
 
 [ini-template]
-## Request Log Configuration
-# Filename for Request Log output (relative to jetty.base)
-# requestlog.filename=/logs/yyyy_mm_dd.request.log
-# Date format for rollovered files (uses SimpleDateFormat syntax)
-# requestlog.filenameDateFormat=yyyy_MM_dd
-# How many days to retain the logs
-# requestlog.retain=90
-# If an existing log with the same name is found, just append to it
-# requestlog.append=true
-# Use the extended log output
-# requestlog.extended=true
-# Log http cookie information as well
-# requestlog.cookies=true
-# Set the log output timezone
-# requestlog.timezone=GMT
+## Logging directory (relative to $jetty.base)
+# jetty.requestlog.dir=logs
 
+## File path
+# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
+
+## Date format for rollovered files (uses SimpleDateFormat syntax)
+# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
+
+## How many days to retain old log files
+# jetty.requestlog.retainDays=90
+
+## Whether to append to existing file
+# jetty.requestlog.append=true
+
+## Whether to use the extended log output
+# jetty.requestlog.extended=true
+
+## Whether to log http cookie information
+# jetty.requestlog.cookies=true
+
+## Timezone of the log entries
+# jetty.requestlog.timezone=GMT
diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod
index b3f87de..14d6b58 100644
--- a/jetty-server/src/main/config/modules/server.mod
+++ b/jetty-server/src/main/config/modules/server.mod
@@ -20,30 +20,60 @@
 etc/jetty.xml
 
 [ini-template]
-##
-## Server Threading Configuration
-##
-# minimum number of threads
-threads.min=10
-# maximum number of threads
-threads.max=200
-# thread idle timeout in milliseconds
-threads.timeout=60000
-# buffer size for output
-jetty.output.buffer.size=32768
-# request header buffer size
-jetty.request.header.size=8192
-# response header buffer size
-jetty.response.header.size=8192
-# should jetty send the server version header?
-jetty.send.server.version=true
-# should jetty send the date header?
-jetty.send.date.header=false
-# What host to listen on (leave commented to listen on all interfaces)
-#jetty.host=myhost.com
-# Dump the state of the Jetty server, components, and webapps after startup
-jetty.dump.start=false
-# Dump the state of the Jetty server, before stop
-jetty.dump.stop=false
-# Enable delayed dispatch optimisation
-jetty.delayDispatchUntilContent=false
+### ThreadPool configuration
+## Minimum number of threads
+# jetty.threadPool.minThreads=10
+
+## Maximum number of threads
+# jetty.threadPool.maxThreads=200
+
+## Thread idle timeout (in milliseconds)
+# jetty.threadPool.idleTimeout=60000
+
+### Common HTTP configuration
+## Scheme to use to build URIs for secure redirects
+# jetty.httpConfig.secureScheme=https
+
+## Port to use to build URIs for secure redirects
+# jetty.httpConfig.securePort=8443
+
+## Response content buffer size (in bytes)
+# jetty.httpConfig.outputBufferSize=32768
+
+## Max response content write length that is buffered (in bytes)
+# jetty.httpConfig.outputAggregationSize=8192
+
+## Max request headers size (in bytes)
+# jetty.httpConfig.requestHeaderSize=8192
+
+## Max response headers size (in bytes)
+# jetty.httpConfig.responseHeaderSize=8192
+
+## Whether to send the Server: header
+# jetty.httpConfig.sendServerVersion=true
+
+## Whether to send the Date: header
+# jetty.httpConfig.sendDateHeader=false
+
+## Max per-connection header cache size (in nodes)
+# jetty.httpConfig.headerCacheSize=512
+
+## Whether, for requests with content, delay dispatch until some content has arrived
+# jetty.httpConfig.delayDispatchUntilContent=true
+
+## Maximum number of error dispatches to prevent looping
+# jetty.httpConfig.maxErrorDispatches=10
+
+## Maximum time to block in total for a blocking IO operation (default -1 is to use idleTimeout on progress)
+# jetty.httpConfig.blockingTimeout=-1
+
+### Server configuration
+## Whether ctrl+c on the console gracefully stops the Jetty server
+# jetty.server.stopAtShutdown=true
+
+## Dump the state of the Jetty server, components, and webapps after startup
+# jetty.server.dumpAfterStart=false
+
+## Dump the state of the Jetty server, components, and webapps before shutdown
+# jetty.server.dumpBeforeStop=false
+
diff --git a/jetty-server/src/main/config/modules/ssl.mod b/jetty-server/src/main/config/modules/ssl.mod
index ef47192..97195c1 100644
--- a/jetty-server/src/main/config/modules/ssl.mod
+++ b/jetty-server/src/main/config/modules/ssl.mod
@@ -2,39 +2,88 @@
 # SSL Keystore module
 #
 
+[name]
+ssl
+
 [depend]
 server
 
 [xml]
 etc/jetty-ssl.xml
+etc/jetty-ssl-context.xml
 
 [files]
-http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
+http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/test/config/etc/keystore?id=${jetty.tag.version}|etc/keystore
 
 [ini-template]
-### SSL Keystore Configuration
-# define the port to use for secure redirection
-jetty.secure.port=8443
+### TLS(SSL) Connector Configuration
 
-## Setup a demonstration keystore and truststore
-jetty.keystore=etc/keystore
-jetty.truststore=etc/keystore
+## Connector host/address to bind to
+# jetty.ssl.host=0.0.0.0
 
-## Set the demonstration passwords.
+## Connector port to listen on
+# jetty.ssl.port=8443
+
+## Connector idle timeout in milliseconds
+# jetty.ssl.idleTimeout=30000
+
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.ssl.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.ssl.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.ssl.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.ssl.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.ssl.acceptorPriorityDelta=0
+
+## Whether request host names are checked to match any SNI names
+# jetty.ssl.sniHostCheck=true
+
+## max age in seconds for a Strict-Transport-Security response header (default -1)
+# jetty.ssl.stsMaxAgeSeconds=31536000
+
+## include subdomain property in any Strict-Transport-Security header (default false)
+# jetty.ssl.stsIncludeSubdomains=true
+
+### SslContextFactory Configuration
 ## Note that OBF passwords are not secure, just protected from casual observation
 ## See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
-jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
-jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
 
-### Set the client auth behavior
-## Set to true if client certificate authentication is required
-# jetty.ssl.needClientAuth=true
-## Set to true if client certificate authentication is desired
-# jetty.ssl.wantClientAuth=true
+## Keystore file path (relative to $jetty.base)
+# jetty.sslContext.keyStorePath=etc/keystore
 
-## Parameters to control the number and priority of acceptors and selectors
-# ssl.selectors=1
-# ssl.acceptors=1
-# ssl.selectorPriorityDelta=0
-# ssl.acceptorPriorityDelta=0
+## Truststore file path (relative to $jetty.base)
+# jetty.sslContext.trustStorePath=etc/keystore
+
+## Keystore password
+# jetty.sslContext.keyStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+
+## Keystore type and provider
+# jetty.sslContext.keyStoreType=JKS
+# jetty.sslContext.keyStoreProvider=
+
+## KeyManager password
+# jetty.sslContext.keyManagerPassword=OBF:1u2u1wml1z7s1z7a1wnl1u2g
+
+## Truststore password
+# jetty.sslContext.trustStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+
+## Truststore type and provider
+# jetty.sslContext.trustStoreType=JKS
+# jetty.sslContext.trustStoreProvider=
+
+## whether client certificate authentication is required
+# jetty.sslContext.needClientAuth=false
+
+## Whether client certificate authentication is desired
+# jetty.sslContext.wantClientAuth=false
+
+## Whether cipher order is significant (since java 8 only)
+# jetty.sslContext.useCipherSuitesOrder=true
+
diff --git a/jetty-server/src/main/config/modules/xinetd.mod b/jetty-server/src/main/config/modules/xinetd.mod
deleted file mode 100644
index e53618e..0000000
--- a/jetty-server/src/main/config/modules/xinetd.mod
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Xinetd module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-xinetd.xml
-
-[ini-template]
-## Xinetd Configuration
-## See ${jetty.home}/etc/jetty-xinetd.xml for example service entry
-jetty.xinetd.idleTimeout=300000
-jetty.xinetd.acceptors=2
-jetty.xinetd.statsOn=false
-
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java
index bbbb165..8cc53e6 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnectionFactory.java
@@ -18,29 +18,65 @@
 
 package org.eclipse.jetty.server;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.ArrayUtil;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 
+/**
+ * <p>Provides the common handling for {@link ConnectionFactory} implementations including:</p>
+ * <ul>
+ * <li>Protocol identification</li>
+ * <li>Configuration of new Connections:
+ *     <ul>
+ *     <li>Setting inputbuffer size</li>
+ *     <li>Calling {@link Connection#addListener(Connection.Listener)} for all
+ *     Connection.Listener instances found as beans on the {@link Connector}
+ *     and this {@link ConnectionFactory}</li>
+ *     </ul>
+ * </ul>
+ */
+@ManagedObject
 public abstract class AbstractConnectionFactory extends ContainerLifeCycle implements ConnectionFactory
 {
     private final String _protocol;
+    private final List<String> _protocols;
     private int _inputbufferSize = 8192;
 
     protected AbstractConnectionFactory(String protocol)
     {
         _protocol=protocol;
+        _protocols=Collections.unmodifiableList(Arrays.asList(new String[]{protocol}));
+    }
+
+    protected AbstractConnectionFactory(String... protocols)
+    {
+        _protocol=protocols[0];
+        _protocols=Collections.unmodifiableList(Arrays.asList(protocols));
     }
 
     @Override
+    @ManagedAttribute(value = "The protocol name", readonly = true)
     public String getProtocol()
     {
         return _protocol;
     }
 
+    @Override
+    public List<String> getProtocols()
+    {
+        return _protocols;
+    }
+
+    @ManagedAttribute("The buffer size used to read from the network")
     public int getInputBufferSize()
     {
         return _inputbufferSize;
@@ -55,19 +91,24 @@
     {
         connection.setInputBufferSize(getInputBufferSize());
 
+        // Add Connection.Listeners from Connector
         if (connector instanceof ContainerLifeCycle)
         {
             ContainerLifeCycle aggregate = (ContainerLifeCycle)connector;
             for (Connection.Listener listener : aggregate.getBeans(Connection.Listener.class))
                 connection.addListener(listener);
         }
+        // Add Connection.Listeners from this factory
+        for (Connection.Listener listener : getBeans(Connection.Listener.class))
+            connection.addListener(listener);
+
         return connection;
     }
 
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s}",this.getClass().getSimpleName(),hashCode(),getProtocol());
+        return String.format("%s@%x%s",this.getClass().getSimpleName(),hashCode(),getProtocols());
     }
 
     public static ConnectionFactory[] getFactories(SslContextFactory sslContextFactory, ConnectionFactory... factories)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
index c758add..15b5655 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
@@ -19,12 +19,14 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
+import java.net.Socket;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -36,19 +38,22 @@
 import org.eclipse.jetty.io.ArrayByteBufferPool;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.util.FutureCallback;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 /**
  * <p>An abstract implementation of {@link Connector} that provides a {@link ConnectionFactory} mechanism
- * for creating {@link Connection} instances for various protocols (HTTP, SSL, SPDY, etc).</p>
+ * for creating {@link org.eclipse.jetty.io.Connection} instances for various protocols (HTTP, SSL, etc).</p>
  *
  * <h2>Connector Services</h2>
  * The abstract connector manages the dependent services needed by all specific connector instances:
@@ -69,12 +74,12 @@
  *
  * <h2>Connection Factories</h2>
  * The connector keeps a collection of {@link ConnectionFactory} instances, each of which are known by their
- * protocol name.  The protocol name may be a real protocol (eg http/1.1 or spdy/3) or it may be a private name
+ * protocol name.  The protocol name may be a real protocol (e.g. "http/1.1" or "h2") or it may be a private name
  * that represents a special connection factory. For example, the name "SSL-http/1.1" is used for
  * an {@link SslConnectionFactory} that has been instantiated with the {@link HttpConnectionFactory} as it's
  * next protocol.
  *
- * <h4>Configuring Connection Factories</h4>
+ * <h2>Configuring Connection Factories</h2>
  * The collection of available {@link ConnectionFactory} may be constructor injected or modified with the
  * methods {@link #addConnectionFactory(ConnectionFactory)}, {@link #removeConnectionFactory(String)} and
  * {@link #setConnectionFactories(Collection)}.  Only a single {@link ConnectionFactory} instance may be configured
@@ -86,48 +91,47 @@
  * <p>
  * Each Connection factory type is responsible for the configuration of the protocols that it accepts. Thus to
  * configure the HTTP protocol, you pass a {@link HttpConfiguration} instance to the {@link HttpConnectionFactory}
- * (or the SPDY factories that can also provide HTTP Semantics).  Similarly the {@link SslConnectionFactory} is
+ * (or other factories that can also provide HTTP Semantics).  Similarly the {@link SslConnectionFactory} is
  * configured by passing it a {@link SslContextFactory} and a next protocol name.
  *
- * <h4>Connection Factory Operation</h4>
- * {@link ConnectionFactory}s may simply create a {@link Connection} instance to support a specific
+ * <h2>Connection Factory Operation</h2>
+ * {@link ConnectionFactory}s may simply create a {@link org.eclipse.jetty.io.Connection} instance to support a specific
  * protocol.  For example, the {@link HttpConnectionFactory} will create a {@link HttpConnection} instance
  * that can handle http/1.1, http/1.0 and http/0.9.
  * <p>
- * {@link ConnectionFactory}s may also create a chain of {@link Connection} instances, using other {@link ConnectionFactory} instances.
+ * {@link ConnectionFactory}s may also create a chain of {@link org.eclipse.jetty.io.Connection} instances, using other {@link ConnectionFactory} instances.
  * For example, the {@link SslConnectionFactory} is configured with a next protocol name, so that once it has accepted
  * a connection and created an {@link SslConnection}, it then used the next {@link ConnectionFactory} from the
- * connector using the {@link #getConnectionFactory(String)} method, to create a {@link Connection} instance that
- * will handle the unecrypted bytes from the {@link SslConnection}.   If the next protocol is "http/1.1", then the
+ * connector using the {@link #getConnectionFactory(String)} method, to create a {@link org.eclipse.jetty.io.Connection} instance that
+ * will handle the unencrypted bytes from the {@link SslConnection}.   If the next protocol is "http/1.1", then the
  * {@link SslConnectionFactory} will have a protocol name of "SSL-http/1.1" and lookup "http/1.1" for the protocol
  * to run over the SSL connection.
  * <p>
- * {@link ConnectionFactory}s may also create temporary {@link Connection} instances that will exchange bytes
- * over the connection to determine what is the next protocol to use.  For example the NPN protocol is an extension
- * of SSL to allow a protocol to be specified during the SSL handshake. NPN is used by the SPDY protocol to
- * negotiate the version of SPDY or HTTP that the client and server will speak.  Thus to accept a SPDY connection, the
- * connector will be configured with {@link ConnectionFactory}s for "SSL-NPN", "NPN", "spdy/3", "spdy/2", "http/1.1"
- * with the default protocol being "SSL-NPN".  Thus a newly accepted connection uses "SSL-NPN", which specifies a
- * SSLConnectionFactory with "NPN" as the next protocol.  Thus an SslConnection instance is created chained to an NPNConnection
- * instance.  The NPN connection then negotiates with the client to determined the next protocol, which could be
- * "spdy/3", "spdy/2" or the default of "http/1.1".  Once the next protocol is determined, the NPN connection
- * calls {@link #getConnectionFactory(String)} to create a connection instance that will replace the NPN connection as
- * the connection chained to the SSLConnection.
- * <p>
+ * {@link ConnectionFactory}s may also create temporary {@link org.eclipse.jetty.io.Connection} instances that will exchange bytes
+ * over the connection to determine what is the next protocol to use.  For example the ALPN protocol is an extension
+ * of SSL to allow a protocol to be specified during the SSL handshake. ALPN is used by the HTTP/2 protocol to
+ * negotiate the protocol that the client and server will speak.  Thus to accept a HTTP/2 connection, the
+ * connector will be configured with {@link ConnectionFactory}s for "SSL-ALPN", "h2", "http/1.1"
+ * with the default protocol being "SSL-ALPN".  Thus a newly accepted connection uses "SSL-ALPN", which specifies a
+ * SSLConnectionFactory with "ALPN" as the next protocol.  Thus an SSL connection instance is created chained to an ALPN
+ * connection instance.  The ALPN connection then negotiates with the client to determined the next protocol, which
+ * could be "h2" or the default of "http/1.1".  Once the next protocol is determined, the ALPN connection
+ * calls {@link #getConnectionFactory(String)} to create a connection instance that will replace the ALPN connection as
+ * the connection chained to the SSL connection.
  * <h2>Acceptors</h2>
  * The connector will execute a number of acceptor tasks to the {@link Exception} service passed to the constructor.
  * The acceptor tasks run in a loop while the connector is running and repeatedly call the abstract {@link #accept(int)} method.
  * The implementation of the accept method must:
- * <nl>
- * <li>block waiting for new connections
- * <li>accept the connection (eg socket accept)
- * <li>perform any configuration of the connection (eg. socket linger times)
+ * <ol>
+ * <li>block waiting for new connections</li>
+ * <li>accept the connection (eg socket accept)</li>
+ * <li>perform any configuration of the connection (eg. socket linger times)</li>
  * <li>call the {@link #getDefaultConnectionFactory()} {@link ConnectionFactory#newConnection(Connector, org.eclipse.jetty.io.EndPoint)}
- * method to create a new Connection instance.
- * </nl>
+ * method to create a new Connection instance.</li>
+ * </ol>
  * The default number of acceptor tasks is the minimum of 1 and half the number of available CPUs. Having more acceptors may reduce
  * the latency for servers that see a high rate of new connections (eg HTTP/1.0 without keep-alive).  Typically the default is
- * sufficient for modern persistent protocols (HTTP/1.1, SPDY etc.)
+ * sufficient for modern persistent protocols (HTTP/1.1, HTTP/2 etc.)
  */
 @ManagedObject("Abstract implementation of the Connector Interface")
 public abstract class AbstractConnector extends ContainerLifeCycle implements Connector, Dumpable
@@ -140,7 +144,7 @@
     private final Scheduler _scheduler;
     private final ByteBufferPool _byteBufferPool;
     private final Thread[] _acceptors;
-    private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<EndPoint, Boolean>());
+    private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<>());
     private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
     private volatile CountDownLatch _stopping;
     private long _idleTimeout = 30000;
@@ -187,7 +191,7 @@
 
         int cores = Runtime.getRuntime().availableProcessors();
         if (acceptors < 0)
-            acceptors=Math.max(1, Math.min(4,cores/8));        
+            acceptors=Math.max(1, Math.min(4,cores/8));
         if (acceptors > cores)
             LOG.warn("Acceptors should be <= availableProcessors: " + this);
         _acceptors = new Thread[acceptors];
@@ -299,7 +303,7 @@
         _stopping=null;
 
         super.doStop();
-        
+
         for (Acceptor a : getBeans(Acceptor.class))
             removeBean(a);
 
@@ -338,7 +342,7 @@
     {
         synchronized (_factories)
         {
-            return _factories.get(protocol.toLowerCase(Locale.ENGLISH));
+            return _factories.get(StringUtil.asciiToLowerCase(protocol));
         }
     }
 
@@ -358,13 +362,73 @@
     {
         synchronized (_factories)
         {
-            ConnectionFactory old=_factories.remove(factory.getProtocol());
-            if (old!=null)
+            Set<ConnectionFactory> to_remove = new HashSet<>();
+            for (String key:factory.getProtocols())
+            {
+                key=StringUtil.asciiToLowerCase(key);
+                ConnectionFactory old=_factories.remove(key);
+                if (old!=null)
+                {
+                    if (old.getProtocol().equals(_defaultProtocol))
+                        _defaultProtocol=null;
+                    to_remove.add(old);
+                }
+                _factories.put(key, factory);
+            }
+
+            // keep factories still referenced
+            for (ConnectionFactory f : _factories.values())
+                to_remove.remove(f);
+
+            // remove old factories
+            for (ConnectionFactory old: to_remove)
+            {
                 removeBean(old);
-            _factories.put(factory.getProtocol().toLowerCase(Locale.ENGLISH), factory);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} removed {}", this, old);
+            }
+
+            // add new Bean
             addBean(factory);
             if (_defaultProtocol==null)
                 _defaultProtocol=factory.getProtocol();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} added {}", this, factory);
+        }
+    }
+
+    public void addFirstConnectionFactory(ConnectionFactory factory)
+    {
+        synchronized (_factories)
+        {
+            List<ConnectionFactory> existings = new ArrayList<>(_factories.values());
+            _factories.clear();
+            addConnectionFactory(factory);
+            for (ConnectionFactory existing : existings)
+                addConnectionFactory(existing);
+            _defaultProtocol = factory.getProtocol();
+        }
+    }
+
+    public void addIfAbsentConnectionFactory(ConnectionFactory factory)
+    {
+        synchronized (_factories)
+        {
+            String key=StringUtil.asciiToLowerCase(factory.getProtocol());
+            if (_factories.containsKey(key))
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} addIfAbsent ignored {}", this, factory);
+            }
+            else
+            {
+                _factories.put(key, factory);
+                addBean(factory);
+                if (_defaultProtocol==null)
+                    _defaultProtocol=factory.getProtocol();
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} addIfAbsent added {}", this, factory);
+            }
         }
     }
 
@@ -372,7 +436,7 @@
     {
         synchronized (_factories)
         {
-            ConnectionFactory factory= _factories.remove(protocol.toLowerCase(Locale.ENGLISH));
+            ConnectionFactory factory= _factories.remove(StringUtil.asciiToLowerCase(protocol));
             removeBean(factory);
             return factory;
         }
@@ -409,10 +473,10 @@
     /* ------------------------------------------------------------ */
     /** Set the acceptor thread priority delta.
      * <p>This allows the acceptor thread to run at a different priority.
-     * Typically this would be used to lower the priority to give preference 
-     * to handling previously accepted connections rather than accepting 
+     * Typically this would be used to lower the priority to give preference
+     * to handling previously accepted connections rather than accepting
      * new connections</p>
-     * @param acceptorPriorityDelta
+     * @param acceptorPriorityDelta the acceptor priority delta
      */
     public void setAcceptorPriorityDelta(int acceptorPriorityDelta)
     {
@@ -451,7 +515,7 @@
 
     public void setDefaultProtocol(String defaultProtocol)
     {
-        _defaultProtocol = defaultProtocol.toLowerCase(Locale.ENGLISH);
+        _defaultProtocol = StringUtil.asciiToLowerCase(defaultProtocol);
         if (isRunning())
             _defaultConnectionFactory=getConnectionFactory(_defaultProtocol);
     }
@@ -466,12 +530,12 @@
 
     private class Acceptor implements Runnable
     {
-        private final int _acceptor;
+        private final int _id;
         private String _name;
 
         private Acceptor(int id)
         {
-            _acceptor = id;
+            _id = id;
         }
 
         @Override
@@ -479,16 +543,16 @@
         {
             final Thread thread = Thread.currentThread();
             String name=thread.getName();
-            _name=String.format("%s-acceptor-%d@%x-%s",name,_acceptor,hashCode(),AbstractConnector.this.toString());
+            _name=String.format("%s-acceptor-%d@%x-%s",name,_id,hashCode(),AbstractConnector.this.toString());
             thread.setName(_name);
-            
+
             int priority=thread.getPriority();
             if (_acceptorPriorityDelta!=0)
                 thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,priority+_acceptorPriorityDelta)));
 
             synchronized (AbstractConnector.this)
             {
-                _acceptors[_acceptor] = thread;
+                _acceptors[_id] = thread;
             }
 
             try
@@ -497,7 +561,7 @@
                 {
                     try
                     {
-                        accept(_acceptor);
+                        accept(_id);
                     }
                     catch (Throwable e)
                     {
@@ -516,23 +580,23 @@
 
                 synchronized (AbstractConnector.this)
                 {
-                    _acceptors[_acceptor] = null;
+                    _acceptors[_id] = null;
                 }
                 CountDownLatch stopping=_stopping;
                 if (stopping!=null)
                     stopping.countDown();
             }
         }
-        
+
         @Override
         public String toString()
         {
             String name=_name;
             if (name==null)
-                return String.format("acceptor-%d@%x", _acceptor, hashCode());
+                return String.format("acceptor-%d@%x", _id, hashCode());
             return name;
         }
-        
+
     }
 
 
@@ -585,7 +649,7 @@
     {
         return _name;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * Set a connector name.   A context may be configured with
@@ -597,13 +661,13 @@
     {
         _name=name;
     }
-    
+
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s}",
+        return String.format("%s@%x{%s,%s}",
                 _name==null?getClass().getSimpleName():_name,
                 hashCode(),
-                getDefaultProtocol());
+                getDefaultProtocol(),getProtocols());
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java
index 7861d1a..36a5f61 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractNCSARequestLog.java
@@ -25,6 +25,7 @@
 
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.PathMap;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
 import org.eclipse.jetty.util.DateCache;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -67,6 +68,7 @@
 
     /**
      * Is logging enabled
+     * @return true if logging is enabled
      */
     protected abstract boolean isEnabled();
     
@@ -74,22 +76,34 @@
 
     /**
      * Write requestEntry out. (to disk or slf4j log)
+     * @param requestEntry the request entry
+     * @throws IOException if unable to write the entry
      */
     public abstract void write(String requestEntry) throws IOException;
 
     /* ------------------------------------------------------------ */
-
+    
+    private void append(StringBuilder buf,String s)
+    {
+        if (s==null || s.length()==0)
+            buf.append('-');
+        else
+            buf.append(s);
+    }
+    
     /**
      * Writes the request and response information to the output stream.
      *
-     * @see org.eclipse.jetty.server.RequestLog#log(org.eclipse.jetty.server.Request,
-     *      org.eclipse.jetty.server.Response)
+     * @see org.eclipse.jetty.server.RequestLog#log(Request, Response)
      */
     @Override
     public void log(Request request, Response response)
     {
         try
         {
+            int status = response.getCommittedMetaData().getStatus();
+            long written = response.getHttpChannel().getBytesWritten();
+            
             if (_ignorePathMap != null && _ignorePathMap.getMatch(request.getRequestURI()) != null)
                 return;
 
@@ -101,7 +115,7 @@
 
             if (_logServer)
             {
-                buf.append(request.getServerName());
+                append(buf,request.getServerName());
                 buf.append(' ');
             }
 
@@ -117,10 +131,7 @@
             buf.append(addr);
             buf.append(" - ");
             Authentication authentication = request.getAuthentication();
-            if (authentication instanceof Authentication.User)
-                buf.append(((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName());
-            else
-                buf.append("-");
+            append(buf,(authentication instanceof Authentication.User)?((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName():null);
 
             buf.append(" [");
             if (_logDateCache != null)
@@ -129,37 +140,38 @@
                 buf.append(request.getTimeStamp());
 
             buf.append("] \"");
-            buf.append(request.getMethod());
+            append(buf,request.getMethod());
             buf.append(' ');
-            buf.append(request.getUri().toString());
+            append(buf,request.getHttpURI().toString());
             buf.append(' ');
-            buf.append(request.getProtocol());
+            append(buf,request.getProtocol());
             buf.append("\" ");
 
-            int status = response.getStatus();
-            if (status <= 0)
-                status = 404;
-            buf.append((char)('0' + ((status / 100) % 10)));
-            buf.append((char)('0' + ((status / 10) % 10)));
-            buf.append((char)('0' + (status % 10)));
+            if (status >=0)
+            {
+                buf.append((char)('0' + ((status / 100) % 10)));
+                buf.append((char)('0' + ((status / 10) % 10)));
+                buf.append((char)('0' + (status % 10)));
+            }
+            else
+                buf.append(status);
 
-            long responseLength = response.getLongContentLength();
-            if (responseLength >= 0)
+            if (written >= 0)
             {
                 buf.append(' ');
-                if (responseLength > 99999)
-                    buf.append(responseLength);
+                if (written > 99999)
+                    buf.append(written);
                 else
                 {
-                    if (responseLength > 9999)
-                        buf.append((char)('0' + ((responseLength / 10000) % 10)));
-                    if (responseLength > 999)
-                        buf.append((char)('0' + ((responseLength / 1000) % 10)));
-                    if (responseLength > 99)
-                        buf.append((char)('0' + ((responseLength / 100) % 10)));
-                    if (responseLength > 9)
-                        buf.append((char)('0' + ((responseLength / 10) % 10)));
-                    buf.append((char)('0' + (responseLength) % 10));
+                    if (written > 9999)
+                        buf.append((char)('0' + ((written / 10000) % 10)));
+                    if (written > 999)
+                        buf.append((char)('0' + ((written / 1000) % 10)));
+                    if (written > 99)
+                        buf.append((char)('0' + ((written / 100) % 10)));
+                    if (written > 9)
+                        buf.append((char)('0' + ((written / 10) % 10)));
+                    buf.append((char)('0' + (written) % 10));
                 }
                 buf.append(' ');
             }
@@ -168,7 +180,7 @@
 
 
             if (_extended)
-                logExtended(request, response, buf);
+                logExtended(request, buf);
 
             if (_logCookies)
             {
@@ -216,12 +228,10 @@
      * Writes extended request and response information to the output stream.
      *
      * @param request  request object
-     * @param response response object
      * @param b        StringBuilder to write to
-     * @throws IOException
+     * @throws IOException if unable to log the extended information
      */
     protected void logExtended(Request request,
-                               Response response,
                                StringBuilder b) throws IOException
     {
         String referer = request.getHeader(HttpHeader.REFERER.toString());
@@ -329,15 +339,19 @@
     }
 
     /**
+     * @param value true to log dispatch
      * @deprecated use {@link StatisticsHandler}
      */
+    @Deprecated
     public void setLogDispatch(boolean value)
     {
     }
 
     /**
+     * @return true if logging dispatches
      * @deprecated use {@link StatisticsHandler}
      */
+    @Deprecated
     public boolean isLogDispatch()
     {
         return false;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java
index 4c8d3fa..001ac0f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java
@@ -77,7 +77,7 @@
     {
         return _context;
     }
-    
+
     public Context getContext()
     {
         return _context;
@@ -100,12 +100,12 @@
     {
         return _dispatchPath;
     }
-    
+
     public void setTimeoutTask(Scheduler.Task task)
     {
         _timeoutTask = task;
     }
-    
+
     public void cancelTimeoutTask()
     {
         Scheduler.Task task=_timeoutTask;
@@ -119,28 +119,28 @@
     {
         return _asyncContext;
     }
-    
+
     @Override
     public Throwable getThrowable()
     {
         return _throwable;
     }
-    
-    public void setThrowable(Throwable throwable)
-    {
-        _throwable=throwable;
-    }
+
+//    public void setThrowable(Throwable throwable)
+//    {
+//        _throwable=throwable;
+//    }
 
     public void setDispatchContext(ServletContext context)
     {
         _dispatchContext=context;
     }
-    
+
     public void setDispatchPath(String path)
     {
         _dispatchPath=path;
     }
-    
+
     public void completed()
     {
         _timeoutTask=null;
@@ -158,7 +158,15 @@
         Scheduler.Task task=_timeoutTask;
         _timeoutTask=null;
         if (task!=null)
-            _state.expired();
+            _state.onTimeout();
+    }
+
+    public void addThrowable(Throwable e)
+    {
+        if (_throwable==null)
+            _throwable=e;
+        else
+            _throwable.addSuppressed(e);
     }
 
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
index 40e4a09..3d75551 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java
@@ -33,11 +33,18 @@
 
 public class AsyncContextState implements AsyncContext
 {
+    private final HttpChannel _channel;
     volatile HttpChannelState _state;
 
     public AsyncContextState(HttpChannelState state)
     {
         _state=state;
+        _channel=_state.getHttpChannel();
+    }
+    
+    public HttpChannel getHttpChannel()
+    {
+        return _channel;
     }
     
     HttpChannelState state()
@@ -68,7 +75,7 @@
             @Override
             public void onError(AsyncEvent event) throws IOException
             {
-                listener.onComplete(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
+                listener.onError(new AsyncEvent(event.getAsyncContext(),request,response,event.getThrowable()));
             }
             
             @Override
@@ -147,7 +154,7 @@
     @Override
     public boolean hasOriginalRequestAndResponse()
     {
-        HttpChannel<?> channel=state().getHttpChannel();
+        HttpChannel channel=state().getHttpChannel();
         return channel.getRequest()==getRequest() && channel.getResponse()==getResponse();
     }
 
@@ -160,12 +167,13 @@
     @Override
     public void start(final Runnable task)
     {
-        state().getHttpChannel().execute(new Runnable()
+        final HttpChannel channel = state().getHttpChannel();
+        channel.execute(new Runnable()
         {
             @Override
             public void run()
             {
-                state().getAsyncContextEvent().getContext().getContextHandler().handle(task);
+                state().getAsyncContextEvent().getContext().getContextHandler().handle(channel.getRequest(),task);
             }
         });
     }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Authentication.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Authentication.java
index 7bacc3e..991cef8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Authentication.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Authentication.java
@@ -24,14 +24,12 @@
 import javax.servlet.http.HttpServletResponse;
 
 
-/* ------------------------------------------------------------ */
 /** The Authentication state of a request.
  * <p>
  * The Authentication state can be one of several sub-types that
  * reflects where the request is in the many different authentication
  * cycles. Authentication might not yet be checked or it might be checked
  * and failed, checked and deferred or succeeded. 
- * 
  */
 public interface Authentication
 {
@@ -75,6 +73,7 @@
         /** Authenticate if possible without sending a challenge.
          * This is used to check credentials that have been sent for 
          * non-manditory authentication.
+         * @param request the request
          * @return The new Authentication state.
          */
         Authentication authenticate(ServletRequest request);
@@ -83,6 +82,8 @@
         /** Authenticate and possibly send a challenge.
          * This is used to initiate authentication for previously 
          * non-manditory authentication.
+         * @param request the request
+         * @param response the response
          * @return The new Authentication state.
          */
         Authentication authenticate(ServletRequest request,ServletResponse response);
@@ -90,8 +91,9 @@
         
         /* ------------------------------------------------------------ */
         /** Login with the LOGIN authenticator
-         * @param username
-         * @param password
+         * @param username the username
+         * @param password the password
+         * @param request the request
          * @return The new Authentication state
          */
         Authentication login(String username,Object password,ServletRequest request);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java
deleted file mode 100644
index 60e62a3..0000000
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server;
-
-import java.nio.ByteBuffer;
-
-/**
- * <p>An implementation of HttpInput using {@link ByteBuffer} as items.</p>
- */
-public class ByteBufferQueuedHttpInput extends QueuedHttpInput<ByteBuffer>
-{
-    @Override
-    protected int remaining(ByteBuffer item)
-    {
-        return item.remaining();
-    }
-
-    @Override
-    protected int get(ByteBuffer item, byte[] buffer, int offset, int length)
-    {
-        int l = Math.min(item.remaining(), length);
-        item.get(buffer, offset, l);
-        return l;
-    }
-    
-    @Override
-    protected void consume(ByteBuffer item, int length)
-    {
-        item.position(item.position()+length);
-    }
-
-    @Override
-    protected void onContentConsumed(ByteBuffer item)
-    {
-    }
-
-}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ClassLoaderDump.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ClassLoaderDump.java
index 56c3b6d..d2904d7 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ClassLoaderDump.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ClassLoaderDump.java
@@ -53,13 +53,10 @@
             Object parent = _loader.getParent();
             if (parent != null)
             {
-                if (!(parent instanceof Dumpable))
-                    parent = new ClassLoaderDump((ClassLoader)parent);
-
                 if (_loader instanceof URLClassLoader)
-                    ContainerLifeCycle.dump(out,indent,TypeUtil.asList(((URLClassLoader)_loader).getURLs()),Collections.singleton(parent));
+                    ContainerLifeCycle.dump(out,indent,TypeUtil.asList(((URLClassLoader)_loader).getURLs()),Collections.singleton(parent.toString()));
                 else
-                    ContainerLifeCycle.dump(out,indent,Collections.singleton(parent));
+                    ContainerLifeCycle.dump(out,indent,Collections.singleton(parent.toString()));
             }
         }
     }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
index a9599c4..f8a3a14 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectionFactory.java
@@ -19,22 +19,29 @@
 package org.eclipse.jetty.server;
 
 
+import java.util.List;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 
 /**
- * <p>A Factory to create {@link Connection} instances for {@link Connector}s.</p>
- * <p>A Connection factory is responsible for instantiating and configuring a {@link Connection} instance
- * to handle an {@link EndPoint} accepted by a {@link Connector}.</p>
+ * A Factory to create {@link Connection} instances for {@link Connector}s.
+ * <p>
+ * A Connection factory is responsible for instantiating and configuring a {@link Connection} instance
+ * to handle an {@link EndPoint} accepted by a {@link Connector}.
  * <p>
  * A ConnectionFactory has a protocol name that represents the protocol of the Connections
- * created.  Example of protocol names include:<dl>
+ * created.  Example of protocol names include:
+ * <dl>
  * <dt>http</dt><dd>Creates a HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1</dd>
- * <dt>spdy/2</dt><dd>Creates a HTTP connection that handles a specific version of the SPDY protocol</dd>
+ * <dt>h2</dt><dd>Creates a HTTP/2 connection that handles the HTTP/2 protocol</dd>
  * <dt>SSL-XYZ</dt><dd>Create an SSL connection chained to a connection obtained from a connection factory 
  * with a protocol "XYZ".</dd>
  * <dt>SSL-http</dt><dd>Create an SSL connection chained to a HTTP connection (aka https)</dd>
- * <dt>SSL-npn</dt><dd>Create an SSL connection chained to a NPN connection, that uses a negotiation with
+ * <dt>SSL-ALPN</dt><dd>Create an SSL connection chained to a ALPN connection, that uses a negotiation with
  * the client to determine the next protocol.</dd>
  * </dl>
  */
@@ -42,9 +49,15 @@
 {
     /* ------------------------------------------------------------ */
     /**
-     * @return A string representing the protocol name.
+     * @return A string representing the primary protocol name.
      */
     public String getProtocol();
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return A list of alternative protocol names/versions including the primary protocol.
+     */
+    public List<String> getProtocols();
     
     /**
      * <p>Creates a new {@link Connection} with the given parameters</p>
@@ -54,4 +67,23 @@
      */
     public Connection newConnection(Connector connector, EndPoint endPoint);
     
+    
+    public interface Upgrading extends ConnectionFactory
+    {
+        /* ------------------------------------------------------------ */
+        /** Create a connection for an upgrade request.
+         * <p>This is a variation of {@link #newConnection(Connector, EndPoint)} that can create (and/or customise)
+         * a connection for an upgrade request.  Implementations may call {@link #newConnection(Connector, EndPoint)} or 
+         * may construct the connection instance themselves.</p>
+         *  
+         * @param connector  The connector to upgrade for.
+         * @param endPoint The endpoint of the connection.
+         * @param upgradeRequest The meta data of the upgrade request.
+         * @param responseFields  The fields to be sent with the 101 response
+         * @return Null to indicate that request processing should continue normally without upgrading. A new connection instance to
+         * indicate that the upgrade should proceed.
+         * @throws BadMessageException Thrown to indicate the upgrade attempt was illegal and that a bad message response should be sent.
+         */
+        public Connection upgradeConnection(Connector connector, EndPoint endPoint, MetaData.Request upgradeRequest,HttpFields responseFields) throws BadMessageException;
+    }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java
index be958ad..62c2ed7 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Connector.java
@@ -24,6 +24,7 @@
 
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.Graceful;
@@ -59,6 +60,7 @@
     public ByteBufferPool getByteBufferPool();
 
     /**
+     * @param nextProtocol the next protocol
      * @return the {@link ConnectionFactory} associated with the protocol name
      */
     public ConnectionFactory getConnectionFactory(String nextProtocol);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java
new file mode 100644
index 0000000..3d377ab
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/DebugListener.java
@@ -0,0 +1,334 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Locale;
+
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandler.Context;
+import org.eclipse.jetty.server.handler.ContextHandler.ContextScopeListener;
+import org.eclipse.jetty.util.DateCache;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.Name;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/** A Context Listener that produces additional debug.
+ * This listener if added to a ContextHandler, will produce additional debug information to
+ * either/or a specific log stream or the standard debug log.
+ * The events produced by {@link ServletContextListener}, {@link ServletRequestListener}, 
+ * {@link AsyncListener} and {@link ContextScopeListener} are logged.
+ */
+@ManagedObject("Debug Listener")
+public class DebugListener extends AbstractLifeCycle implements ServletContextListener
+{
+    private static final Logger LOG = Log.getLogger(DebugListener.class);
+    private static final DateCache __date=new DateCache("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
+    
+    private final String _attr = String.format("__R%s@%x",this.getClass().getSimpleName(),System.identityHashCode(this));
+
+    private final PrintStream _out;
+    private boolean _renameThread;
+    private boolean _showHeaders;
+    private boolean _dumpContext;
+
+    public DebugListener()
+    {
+        this(null,false,false,false);
+    }
+    
+    public DebugListener(@Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
+    {
+        this(null,renameThread,showHeaders,dumpContext);
+    }
+    
+    public DebugListener(@Name("outputStream") OutputStream out, @Name("renameThread") boolean renameThread, @Name("showHeaders") boolean showHeaders, @Name("dumpContext") boolean dumpContext)
+    {
+        _out=out==null?null:new PrintStream(out);
+        _renameThread=renameThread;
+        _showHeaders=showHeaders;
+        _dumpContext=dumpContext;
+    }
+    
+    @ManagedAttribute("Rename thread within context scope")
+    public boolean isRenameThread()
+    {
+        return _renameThread;
+    }
+
+    public void setRenameThread(boolean renameThread)
+    {
+        _renameThread = renameThread;
+    }
+
+    @ManagedAttribute("Show request headers")
+    public boolean isShowHeaders()
+    {
+        return _showHeaders;
+    }
+
+    public void setShowHeaders(boolean showHeaders)
+    {
+        _showHeaders = showHeaders;
+    }
+
+    @ManagedAttribute("Dump contexts at start")
+    public boolean isDumpContext()
+    {
+        return _dumpContext;
+    }
+
+    public void setDumpContext(boolean dumpContext)
+    {
+        _dumpContext = dumpContext;
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce)
+    {
+        sce.getServletContext().addListener(_servletRequestListener);        
+        ContextHandler handler =  ContextHandler.getContextHandler(sce.getServletContext());
+        handler.addEventListener(_contextScopeListener);
+        String cname=findContextName(sce.getServletContext());
+        log("^  ctx=%s %s",cname,sce.getServletContext());
+        if (_dumpContext)
+        {
+            if (_out==null)
+                handler.dumpStdErr();
+            else
+            {
+                try
+                {
+                    handler.dump(_out);
+                }
+                catch(Exception e)
+                {
+                    LOG.warn(e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce)
+    {
+        String cname=findContextName(sce.getServletContext());
+        log("v  ctx=%s %s",cname,sce.getServletContext());
+    }
+    
+    protected String findContextName(ServletContext context)
+    {
+        if (context==null)
+            return null;
+        String n = (String)context.getAttribute(_attr);
+        if (n==null)
+        {
+            n=String.format("%s@%x",context.getContextPath(),context.hashCode());
+            context.setAttribute(_attr,n);
+        }
+        return n;
+    }
+
+    protected String findRequestName(ServletRequest request)
+    {
+        if (request==null)
+            return null;
+        HttpServletRequest r = (HttpServletRequest)request;
+        String n = (String)request.getAttribute(_attr);
+        if (n==null)
+        {
+            n=String.format("%s@%x",r.getRequestURI(),request.hashCode());
+            request.setAttribute(_attr,n);
+        }
+        return n;
+    }
+    
+    protected void log(String format, Object... arg)
+    {
+        if (!isRunning())
+            return;
+        
+        String s=String.format(format,arg);
+        
+        long now = System.currentTimeMillis();
+        long ms = now%1000;
+        if (_out!=null)
+            _out.printf("%s.%03d:%s%n",__date.formatNow(now),ms,s);
+        if (LOG.isDebugEnabled())
+            LOG.info(s);
+    }
+    
+    final AsyncListener _asyncListener = new AsyncListener()
+    { 
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {
+            String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+            String rname=findRequestName(event.getAsyncContext().getRequest());
+            log("!  ctx=%s r=%s onTimeout %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
+        }
+        
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+            String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+            String rname=findRequestName(event.getAsyncContext().getRequest());
+            log("!  ctx=%s r=%s onStartAsync %s",cname,rname,((AsyncContextEvent)event).getHttpChannelState());
+        }
+        
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            String cname=findContextName(((AsyncContextEvent)event).getServletContext());
+            String rname=findRequestName(event.getAsyncContext().getRequest());
+            log("!! ctx=%s r=%s onError %s %s",cname,rname,event.getThrowable(),((AsyncContextEvent)event).getHttpChannelState());
+        }
+        
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            AsyncContextEvent ace=(AsyncContextEvent)event;
+            String cname=findContextName(ace.getServletContext());
+            String rname=findRequestName(ace.getAsyncContext().getRequest());
+            
+            Request br=Request.getBaseRequest(ace.getAsyncContext().getRequest());
+            Response response = br.getResponse();
+            String headers=_showHeaders?("\n"+response.getHttpFields().toString()):"";
+            
+            log("!  ctx=%s r=%s onComplete %s %d%s",cname,rname,ace.getHttpChannelState(),response.getStatus(),headers);
+        }
+    };
+    
+    final ServletRequestListener _servletRequestListener = new ServletRequestListener()
+    {
+        @Override
+        public void requestInitialized(ServletRequestEvent sre)
+        {
+            String cname=findContextName(sre.getServletContext());
+            HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
+           
+            String rname=findRequestName(r);
+            DispatcherType d = r.getDispatcherType();
+            if (d==DispatcherType.REQUEST)
+            {
+                Request br=Request.getBaseRequest(r);
+
+                String headers=_showHeaders?("\n"+br.getMetaData().getFields().toString()):"";
+                
+                
+                StringBuffer url=r.getRequestURL();
+                if (r.getQueryString()!=null)
+                    url.append('?').append(r.getQueryString());
+                log(">> %s ctx=%s r=%s %s %s %s %s %s%s",d,
+                        cname,
+                        rname,
+                        d,
+                        r.getMethod(),
+                        url.toString(),
+                        r.getProtocol(),
+                        br.getHttpChannel(),
+                        headers);
+            }
+            else
+                log(">> %s ctx=%s r=%s",d,cname,rname);
+        }
+        
+        @Override
+        public void requestDestroyed(ServletRequestEvent sre)
+        {
+            String cname=findContextName(sre.getServletContext());
+            HttpServletRequest r = (HttpServletRequest)sre.getServletRequest();
+            String rname=findRequestName(r);
+            DispatcherType d = r.getDispatcherType();
+            if (sre.getServletRequest().isAsyncStarted())
+            {
+                sre.getServletRequest().getAsyncContext().addListener(_asyncListener);
+                log("<< %s ctx=%s r=%s async=true",d,cname,rname);
+            }
+            else
+            {
+                Request br=Request.getBaseRequest(r);
+                String headers=_showHeaders?("\n"+br.getResponse().getHttpFields().toString()):"";
+                log("<< %s ctx=%s r=%s async=false %d%s",d,cname,rname,Request.getBaseRequest(r).getResponse().getStatus(),headers);
+            }
+        }
+    };
+    
+    final ContextHandler.ContextScopeListener _contextScopeListener = new ContextHandler.ContextScopeListener()
+    {
+        @Override
+        public void enterScope(Context context, Request request, Object reason)
+        {
+            String cname=findContextName(context);
+            if (request==null)
+                log(">  ctx=%s %s",cname,reason);
+            else
+            {
+                String rname=findRequestName(request);
+
+                if (_renameThread)
+                {
+                    Thread thread=Thread.currentThread();
+                    thread.setName(String.format("%s#%s",thread.getName(),rname));
+                }
+            
+                log(">  ctx=%s r=%s %s",cname,rname,reason);
+            }
+        }
+        
+
+        @Override
+        public void exitScope(Context context, Request request)
+        {
+            String cname=findContextName(context);
+            if (request==null)
+                log("<  ctx=%s",cname);
+            else
+            {
+                String rname=findRequestName(request);
+
+                log("<  ctx=%s r=%s",cname,rname);
+                if (_renameThread)
+                {
+                    Thread thread=Thread.currentThread();
+                    if (thread.getName().endsWith(rname))
+                        thread.setName(thread.getName().substring(0,thread.getName().length()-rname.length()-1));
+                }
+            }
+        }   
+    };
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
index a34a83d..01a8d69 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Dispatcher.java
@@ -22,6 +22,7 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
+
 import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
@@ -30,6 +31,10 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.Attributes;
 import org.eclipse.jetty.util.MultiMap;
@@ -43,27 +48,24 @@
     public final static String __FORWARD_PREFIX="javax.servlet.forward.";
 
     private final ContextHandler _contextHandler;
-    private final String _uri;
-    private final String _path;
-    private final String _query;
+    private final HttpURI _uri;
+    private final String _pathInContext;
     private final String _named;
 
-    public Dispatcher(ContextHandler contextHandler, String uri, String pathInContext, String query)
+    public Dispatcher(ContextHandler contextHandler, HttpURI uri, String pathInContext)
     {
         _contextHandler=contextHandler;
         _uri=uri;
-        _path=pathInContext;
-        _query=query;
+        _pathInContext=pathInContext;
         _named=null;
     }
 
     public Dispatcher(ContextHandler contextHandler, String name) throws IllegalStateException
     {
         _contextHandler=contextHandler;
-        _named=name;
         _uri=null;
-        _path=null;
-        _query=null;
+        _pathInContext=null;
+        _named=name;
     }
 
     @Override
@@ -80,7 +82,7 @@
     @Override
     public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
     {
-        Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
+        Request baseRequest=Request.getBaseRequest(request);
 
         if (!(request instanceof HttpServletRequest))
             request = new ServletRequestHttpWrapper(request);
@@ -102,17 +104,17 @@
             {
                 IncludeAttributes attr = new IncludeAttributes(old_attr);
 
-                attr._requestURI=_uri;
+                attr._requestURI=_uri.getPath();
                 attr._contextPath=_contextHandler.getContextPath();
                 attr._servletPath=null; // set by ServletHandler
-                attr._pathInfo=_path;
-                attr._query=_query;
+                attr._pathInfo=_pathInContext;
+                attr._query=_uri.getQuery();
 
-                if (_query!=null)
-                    baseRequest.mergeQueryParameters(_query, false);
+                if (attr._query!=null)
+                    baseRequest.mergeQueryParameters(baseRequest.getQueryString(),attr._query, false);
                 baseRequest.setAttributes(attr);
 
-                _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
+                _contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
             }
         }
         finally
@@ -127,7 +129,7 @@
 
     protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch) throws ServletException, IOException
     {
-        Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
+        Request baseRequest=Request.getBaseRequest(request);
         Response base_response=baseRequest.getResponse();
         base_response.resetForForward();
 
@@ -137,11 +139,12 @@
             response = new ServletResponseHttpWrapper(response);
 
         final boolean old_handled=baseRequest.isHandled();
-        final String old_uri=baseRequest.getRequestURI();
+
+        final HttpURI old_uri=baseRequest.getHttpURI();
         final String old_context_path=baseRequest.getContextPath();
         final String old_servlet_path=baseRequest.getServletPath();
         final String old_path_info=baseRequest.getPathInfo();
-        final String old_query=baseRequest.getQueryString();
+
         final MultiMap<String> old_query_params=baseRequest.getQueryParameters();
         final Attributes old_attr=baseRequest.getAttributes();
         final DispatcherType old_type=baseRequest.getDispatcherType();
@@ -174,21 +177,26 @@
                 else
                 {
                     attr._pathInfo=old_path_info;
-                    attr._query=old_query;
-                    attr._requestURI=old_uri;
+                    attr._query=old_uri.getQuery();
+                    attr._requestURI=old_uri.getPath();
                     attr._contextPath=old_context_path;
                     attr._servletPath=old_servlet_path;
                 }
 
-                baseRequest.setRequestURI(_uri);
+                HttpURI uri = new HttpURI(old_uri.getScheme(),old_uri.getHost(),old_uri.getPort(),
+                        _uri.getPath(),_uri.getParam(),_uri.getQuery(),_uri.getFragment());
+
+                baseRequest.setHttpURI(uri);
+
                 baseRequest.setContextPath(_contextHandler.getContextPath());
                 baseRequest.setServletPath(null);
-                baseRequest.setPathInfo(_uri);
-                if (_query!=null)
-                    baseRequest.mergeQueryParameters(_query, true);
+                baseRequest.setPathInfo(_pathInContext);
+                if (_uri.getQuery()!=null || old_uri.getQuery()!=null)
+                    baseRequest.mergeQueryParameters(old_uri.getQuery(),_uri.getQuery(), true);
+
                 baseRequest.setAttributes(attr);
 
-                _contextHandler.handle(_path, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
+                _contextHandler.handle(_pathInContext, baseRequest, (HttpServletRequest)request, (HttpServletResponse)response);
 
                 if (!baseRequest.getHttpChannelState().isAsync())
                     commitResponse(response,baseRequest);
@@ -197,11 +205,10 @@
         finally
         {
             baseRequest.setHandled(old_handled);
-            baseRequest.setRequestURI(old_uri);
+            baseRequest.setHttpURI(old_uri);
             baseRequest.setContextPath(old_context_path);
             baseRequest.setServletPath(old_servlet_path);
             baseRequest.setPathInfo(old_path_info);
-            baseRequest.setQueryString(old_query);
             baseRequest.setQueryParameters(old_query_params);
             baseRequest.resetParameters();
             baseRequest.setAttributes(old_attr);
@@ -209,6 +216,40 @@
         }
     }
 
+    /**
+     * <p>Pushes a secondary resource identified by this dispatcher.</p>
+     *
+     * @param request the primary request
+     * @deprecated Use {@link Request#getPushBuilder()} instead
+     */
+    @Deprecated
+    public void push(ServletRequest request)
+    {
+        Request baseRequest = Request.getBaseRequest(request);
+        HttpFields fields = new HttpFields(baseRequest.getHttpFields());
+
+        String query=baseRequest.getQueryString();
+        if (_uri.hasQuery())
+        {
+            if (query==null)
+                query=_uri.getQuery();
+            else
+                query=query+"&"+_uri.getQuery(); // TODO is this correct semantic?
+        }
+
+        HttpURI uri = HttpURI.createHttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),_uri.getPath(),baseRequest.getHttpURI().getParam(),query,null);
+
+        MetaData.Request push = new MetaData.Request(HttpMethod.GET.asString(),uri,baseRequest.getHttpVersion(),fields);
+
+        baseRequest.getHttpChannel().getHttpTransport().push(push);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("Dispatcher@0x%x{%s,%s}",hashCode(),_named,_uri);
+    }
+
     private void commitResponse(ServletResponse response, Request baseRequest) throws IOException
     {
         if (baseRequest.getResponse().isWriting())
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
index 1e9d174..4a398ce 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
@@ -20,6 +20,9 @@
 
 import java.net.InetSocketAddress;
 
+import javax.servlet.ServletRequest;
+
+import org.eclipse.jetty.http.HostPortHttpField;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpScheme;
@@ -46,7 +49,7 @@
  */
 public class ForwardedRequestCustomizer implements Customizer
 {
-    private String _hostHeader;
+    private HostPortHttpField _hostHeader;
     private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
     private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
     private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
@@ -58,7 +61,7 @@
     /* ------------------------------------------------------------ */
     public String getHostHeader()
     {
-        return _hostHeader;
+        return _hostHeader.getValue();
     }
 
     /* ------------------------------------------------------------ */
@@ -70,7 +73,7 @@
      */
     public void setHostHeader(String hostHeader)
     {
-        _hostHeader = hostHeader;
+        _hostHeader = new HostPortHttpField(hostHeader);
     }
 
     /* ------------------------------------------------------------ */
@@ -201,13 +204,13 @@
         // Do SSL first
         if (getForwardedCipherSuiteHeader()!=null)
         {
-            String cipher_suite=httpFields.getStringField(getForwardedCipherSuiteHeader());
+            String cipher_suite=httpFields.get(getForwardedCipherSuiteHeader());
             if (cipher_suite!=null)
                 request.setAttribute("javax.servlet.request.cipher_suite",cipher_suite);
         }
         if (getForwardedSslSessionIdHeader()!=null)
         {
-            String ssl_session_id=httpFields.getStringField(getForwardedSslSessionIdHeader());
+            String ssl_session_id=httpFields.get(getForwardedSslSessionIdHeader());
             if(ssl_session_id!=null)
             {
                 request.setAttribute("javax.servlet.request.ssl_session_id", ssl_session_id);
@@ -224,23 +227,20 @@
         if (_hostHeader != null)
         {
             // Update host header
-            httpFields.put(HttpHeader.HOST.toString(),_hostHeader);
-            request.setServerName(null);
-            request.setServerPort(-1);
-            request.getServerName();
+            httpFields.put(_hostHeader);
+            request.setAuthority(_hostHeader.getHost(),_hostHeader.getPort());
         }
         else if (forwardedHost != null)
         {
             // Update host header
-            httpFields.put(HttpHeader.HOST.toString(),forwardedHost);
-            request.setServerName(null);
-            request.setServerPort(-1);
-            request.getServerName();
+            HostPortHttpField auth = new HostPortHttpField(forwardedHost);
+            httpFields.put(auth);
+            request.setAuthority(auth.getHost(),auth.getPort());
         }
         else if (forwardedServer != null)
         {
             // Use provided server name
-            request.setServerName(forwardedServer);
+            request.setAuthority(forwardedServer,request.getServerPort());
         }
 
         if (forwardedFor != null)
@@ -262,7 +262,7 @@
         if (header == null)
             return null;
 
-        String headerValue = fields.getStringField(header);
+        String headerValue = fields.get(header);
 
         if (headerValue == null)
             return null;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java
index b32cc82..1b627e9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Handler.java
@@ -24,17 +24,21 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.ManagedOperation;
 import org.eclipse.jetty.util.component.Destroyable;
 import org.eclipse.jetty.util.component.LifeCycle;
 
-/* ------------------------------------------------------------ */
 /** A Jetty Server Handler.
- *
+ * <p>
  * A Handler instance is required by a {@link Server} to handle incoming
- * HTTP requests.  A Handler may: <ul>
+ * HTTP requests.
+ * <p>  
+ * A Handler may: 
+ * <ul>
  * <li>Completely generate the HTTP Response</li>
  * <li>Examine/modify the request and call another Handler (see {@link HandlerWrapper}).
  * <li>Pass the request to one or more other Handlers (see {@link HandlerCollection}).
@@ -49,18 +53,25 @@
 @ManagedObject("Jetty Handler")
 public interface Handler extends LifeCycle, Destroyable
 {
-    /* ------------------------------------------------------------ */
-    /** Handle a request.
-     * @param target The target of the request - either a URI or a name.
-     * @param baseRequest The original unwrapped request object.
-     * @param request The request either as the {@link Request}
-     * object or a wrapper of that request. The {@link HttpChannel#getCurrentHttpChannel()}
-     * method can be used access the Request object if required.
-     * @param response The response as the {@link Response}
-     * object or a wrapper of that request. The {@link HttpChannel#getCurrentHttpChannel()}
-     * method can be used access the Response object if required.
+    /**
+     * Handle a request.
+     * 
+     * @param target
+     *            The target of the request - either a URI or a name.
+     * @param baseRequest
+     *            The original unwrapped request object.
+     * @param request
+     *            The request either as the {@link Request} object or a wrapper of that request. The
+     *            <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getRequest() getRequest()}</code>
+     *            method can be used access the Request object if required.
+     * @param response
+     *            The response as the {@link Response} object or a wrapper of that request. The
+     *            <code>{@link HttpConnection#getCurrentConnection()}.{@link HttpConnection#getHttpChannel() getHttpChannel()}.{@link HttpChannel#getResponse() getResponse()}</code>
+     *            method can be used access the Response object if required.
      * @throws IOException
+     *             if unable to handle the request or response processing
      * @throws ServletException
+     *             if unable to handle the request or response due to underlying servlet issue
      */
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException;
@@ -72,6 +83,5 @@
 
     @ManagedOperation(value="destroy associated resources", impact="ACTION")
     public void destroy();
-
 }
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java
index 5f67527..42ad64d 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HandlerContainer.java
@@ -48,15 +48,16 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param byclass
+     * @param byclass the child handler class to get
      * @return array of all handlers contained by this handler and it's children of the passed type.
      */
     public Handler[] getChildHandlersByClass(Class<?> byclass);
     
     /* ------------------------------------------------------------ */
     /**
-     * @param byclass
+     * @param byclass the child handler class to get
      * @return first handler of all handlers contained by this handler and it's children of the passed type.
+     * @param <T> the type of handler
      */
     public <T extends Handler> T getChildHandlerByClass(Class<T> byclass);
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java
index 464f1d2..2181ebd 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HostHeaderCustomizer.java
@@ -20,15 +20,17 @@
 
 import java.util.Objects;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * Customizes requests that lack the {@code Host} header (for example, HTTP 1.0 requests).
- * <p />
+ * <p>
  * In case of HTTP 1.0 requests that lack the {@code Host} header, the application may issue
  * a redirect, and the {@code Location} header is usually constructed from the {@code Host}
  * header; if the {@code Host} header is missing, the server may query the connector for its
  * IP address in order to construct the {@code Location} header, and thus leak to clients
  * internal IP addresses.
- * <p />
+ * <p>
  * This {@link HttpConfiguration.Customizer} is configured with a {@code serverName} and
  * optionally a {@code serverPort}.
  * If the {@code Host} header is absent, the configured {@code serverName} will be set on
@@ -62,10 +64,6 @@
     public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
     {
         if (request.getHeader("Host") == null)
-        {
-            request.setServerName(serverName);
-            if (serverPort > 0)
-                request.setServerPort(serverPort);
-        }
+            request.setAuthority(serverName,serverPort);  // TODO set the field as well?
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
index 8093f46..4ba55f7 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java
@@ -22,27 +22,24 @@
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedChannelException;
-import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.RequestDispatcher;
+import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServletRequest;
 
-import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.BadMessageException;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpParser;
 import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.ChannelEndPoint;
 import org.eclipse.jetty.io.EndPoint;
@@ -50,17 +47,16 @@
 import org.eclipse.jetty.server.HttpChannelState.Action;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
-import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 
-/* ------------------------------------------------------------ */
-/** HttpChannel.
- * Represents a single endpoint for HTTP semantic processing.
+/**
+ * HttpChannel represents a single endpoint for HTTP semantic processing.
  * The HttpChannel is both a HttpParser.RequestHandler, where it passively receives events from
  * an incoming HTTP request, and a Runnable, where it actively takes control of the request/response
  * life cycle and calls the application (perhaps suspending and resuming with multiple calls to run).
@@ -69,69 +65,59 @@
  * HttpTransport.completed().
  *
  */
-public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, HttpParser.ProxyHandler
+public class HttpChannel implements Runnable, HttpOutput.Interceptor
 {
     private static final Logger LOG = Log.getLogger(HttpChannel.class);
-    private static final ThreadLocal<HttpChannel<?>> __currentChannel = new ThreadLocal<>();
-
-    /* ------------------------------------------------------------ */
-    /** Get the current channel that this thread is dispatched to.
-     * @see Request#getAttribute(String) for a more general way to access the HttpChannel
-     * @return the current HttpChannel or null
-     */
-    public static HttpChannel<?> getCurrentHttpChannel()
-    {
-        return __currentChannel.get();
-    }
-
-    protected static HttpChannel<?> setCurrentHttpChannel(HttpChannel<?> channel)
-    {
-        HttpChannel<?> last=__currentChannel.get();
-        __currentChannel.set(channel);
-        return last;
-    }
-
     private final AtomicBoolean _committed = new AtomicBoolean();
     private final AtomicInteger _requests = new AtomicInteger();
     private final Connector _connector;
     private final HttpConfiguration _configuration;
     private final EndPoint _endPoint;
     private final HttpTransport _transport;
-    private final HttpURI _uri;
     private final HttpChannelState _state;
     private final Request _request;
     private final Response _response;
-    private HttpVersion _version = HttpVersion.HTTP_1_1;
-    private boolean _expect = false;
-    private boolean _expect100Continue = false;
-    private boolean _expect102Processing = false;
+    private MetaData.Response _committedMetaData;
+    private RequestLog _requestLog;
 
-    public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput<T> input)
+    /** Bytes written after interception (eg after compression) */
+    private long _written;
+
+    public HttpChannel(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport)
     {
         _connector = connector;
         _configuration = configuration;
         _endPoint = endPoint;
         _transport = transport;
 
-        _uri = new HttpURI(URIUtil.__CHARSET);
         _state = new HttpChannelState(this);
-        input.init(_state);
-        _request = new Request(this, input);
-        _response = new Response(this, new HttpOutput(this));
-
+        _request = new Request(this, newHttpInput(_state));
+        _response = new Response(this, newHttpOutput());
+        _requestLog=_connector==null?null:_connector.getServer().getRequestLog();
         if (LOG.isDebugEnabled())
             LOG.debug("new {} -> {},{},{}",this,_endPoint,_endPoint.getConnection(),_state);
     }
 
+    protected HttpInput newHttpInput(HttpChannelState state)
+    {
+        return new HttpInput(state);
+    }
+
+    protected HttpOutput newHttpOutput()
+    {
+        return new HttpOutput(this);
+    }
+
     public HttpChannelState getState()
     {
         return _state;
     }
 
-    public HttpVersion getHttpVersion()
+    public long getBytesWritten()
     {
-        return _version;
+        return _written;
     }
+
     /**
      * @return the number of requests handled by this connection
      */
@@ -150,10 +136,36 @@
         return _transport;
     }
 
+    public RequestLog getRequestLog()
+    {
+        return _requestLog;
+    }
+
+    public void setRequestLog(RequestLog requestLog)
+    {
+        _requestLog = requestLog;
+    }
+
+    public void addRequestLog(RequestLog requestLog)
+    {
+        if (_requestLog==null)
+            _requestLog = requestLog;
+        else if (_requestLog instanceof RequestLogCollection)
+            ((RequestLogCollection) _requestLog).add(requestLog);
+        else
+            _requestLog = new RequestLogCollection(_requestLog, requestLog);
+    }
+
+    public MetaData.Response getCommittedMetaData()
+    {
+        return _committedMetaData;
+    }
+
     /**
      * Get the idle timeout.
      * <p>This is implemented as a call to {@link EndPoint#getIdleTimeout()}, but may be
      * overridden by channels that have timeouts different from their connections.
+     * @return the idle timeout (in milliseconds)
      */
     public long getIdleTimeout()
     {
@@ -164,6 +176,7 @@
      * Set the idle timeout.
      * <p>This is implemented as a call to {@link EndPoint#setIdleTimeout(long)}, but may be
      * overridden by channels that have timeouts different from their connections.
+     * @param timeoutMs the idle timeout in milliseconds
      */
     public void setIdleTimeout(long timeoutMs)
     {
@@ -180,6 +193,12 @@
         return _configuration;
     }
 
+    @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        return getHttpTransport().isOptimizedForDirectBuffers();
+    }
+
     public Server getServer()
     {
         return _connector.getServer();
@@ -210,50 +229,31 @@
         return _endPoint.getRemoteAddress();
     }
 
-    @Override
-    public int getHeaderCacheSize()
-    {
-        return _configuration.getHeaderCacheSize();
-    }
-
     /**
      * If the associated response has the Expect header set to 100 Continue,
      * then accessing the input stream indicates that the handler/servlet
      * is ready for the request body and thus a 100 Continue response is sent.
      *
+     * @param available estimate of the number of bytes that are available
      * @throws IOException if the InputStream cannot be created
      */
     public void continue100(int available) throws IOException
     {
-        // If the client is expecting 100 CONTINUE, then send it now.
-        // TODO: consider using an AtomicBoolean ?
-        if (isExpecting100Continue())
-        {
-            _expect100Continue = false;
-
-            // is content missing?
-            if (available == 0)
-            {
-                if (_response.isCommitted())
-                    throw new IOException("Committed before 100 Continues");
-
-                // TODO: break this dependency with HttpGenerator
-                boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false);
-                if (!committed)
-                    throw new IOException("Concurrent commit while trying to send 100-Continue");
-            }
-        }
+        throw new UnsupportedOperationException();
     }
 
-    public void reset()
+    public void recycle()
     {
         _committed.set(false);
-        _expect = false;
-        _expect100Continue = false;
-        _expect102Processing = false;
         _request.recycle();
         _response.recycle();
-        _uri.clear();
+        _committedMetaData=null;
+        _requestLog=_connector==null?null:_connector.getServer().getRequestLog();
+        _written=0;
+    }
+
+    public void asyncReadFillInterested()
+    {
     }
 
     @Override
@@ -262,192 +262,224 @@
         handle();
     }
 
-    /* ------------------------------------------------------------ */
     /**
      * @return True if the channel is ready to continue handling (ie it is not suspended)
      */
     public boolean handle()
     {
         if (LOG.isDebugEnabled())
-            LOG.debug("{} handle enter", this);
-
-        final HttpChannel<?>last = setCurrentHttpChannel(this);
-
-        String threadName = null;
-        if (LOG.isDebugEnabled())
-        {
-            threadName = Thread.currentThread().getName();
-            Thread.currentThread().setName(threadName + " - " + _uri);
-        }
+            LOG.debug("{} handle {} ", this,_request.getHttpURI());
 
         HttpChannelState.Action action = _state.handling();
-        try
+
+        // Loop here to handle async request redispatches.
+        // The loop is controlled by the call to async.unhandle in the
+        // finally block below.  Unhandle will return false only if an async dispatch has
+        // already happened when unhandle is called.
+        loop: while (!getServer().isStopped())
         {
-            // Loop here to handle async request redispatches.
-            // The loop is controlled by the call to async.unhandle in the
-            // finally block below.  Unhandle will return false only if an async dispatch has
-            // already happened when unhandle is called.
-            loop: while (action.ordinal()<HttpChannelState.Action.WAIT.ordinal() && getServer().isRunning())
+            try
             {
-                boolean error=false;
-                try
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} action {}",this,action);
+
+                switch(action)
                 {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("{} action {}",this,action);
+                    case TERMINATED:
+                    case WAIT:
+                        break loop;
 
-                    switch(action)
+                    case DISPATCH:
                     {
-                        case REQUEST_DISPATCH:
-                            _request.setHandled(false);
-                            _response.getHttpOutput().reopen();
+                        if (!_request.hasMetaData())
+                            throw new IllegalStateException("state=" + _state);
+                        _request.setHandled(false);
+                        _response.getHttpOutput().reopen();
+
+                        List<HttpConfiguration.Customizer> customizers = _configuration.getCustomizers();
+                        if (!customizers.isEmpty())
+                        {
+                            for (HttpConfiguration.Customizer customizer : customizers)
+                                customizer.customize(getConnector(), _configuration, _request);
+                        }
+                        try
+                        {
                             _request.setDispatcherType(DispatcherType.REQUEST);
-
-                            List<HttpConfiguration.Customizer> customizers = _configuration.getCustomizers();
-                            if (!customizers.isEmpty())
-                            {
-                                for (HttpConfiguration.Customizer customizer : customizers)
-                                    customizer.customize(getConnector(), _configuration, _request);
-                            }
                             getServer().handle(this);
-                            break;
+                        }
+                        finally
+                        {
+                            _request.setDispatcherType(null);
+                        }
+                        break;
+                    }
 
-                        case ASYNC_DISPATCH:
-                            _request.setHandled(false);
-                            _response.getHttpOutput().reopen();
+                    case ASYNC_DISPATCH:
+                    {
+                        _request.setHandled(false);
+                        _response.getHttpOutput().reopen();
+                        
+                        try
+                        {
                             _request.setDispatcherType(DispatcherType.ASYNC);
                             getServer().handleAsync(this);
-                            break;
-
-                        case ASYNC_EXPIRED:
-                            _request.setHandled(false);
-                            _response.getHttpOutput().reopen();
-                            _request.setDispatcherType(DispatcherType.ERROR);
-
-                            Throwable ex=_state.getAsyncContextEvent().getThrowable();
-                            String reason="Async Timeout";
-                            if (ex!=null)
-                            {
-                                reason="Async Exception";
-                                _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,ex);
-                            }
-                            _request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
-                            _request.setAttribute(RequestDispatcher.ERROR_MESSAGE,reason);
-                            _request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
-
-                            _response.setStatusWithReason(500,reason);
-
-
-                            ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(),_state.getContextHandler());
-                            if (eh instanceof ErrorHandler.ErrorPageMapper)
-                            {
-                                String error_page=((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_state.getAsyncContextEvent().getSuppliedRequest());
-                                if (error_page!=null)
-                                    _state.getAsyncContextEvent().setDispatchPath(error_page);
-                            }
-
-                            getServer().handleAsync(this);
-                            break;
-
-                        case READ_CALLBACK:
-                        {
-                            ContextHandler handler=_state.getContextHandler();
-                            if (handler!=null)
-                                handler.handle(_request.getHttpInput());
-                            else
-                                _request.getHttpInput().run();
-                            break;
                         }
-
-                        case WRITE_CALLBACK:
+                        finally
                         {
-                            ContextHandler handler=_state.getContextHandler();
-
-                            if (handler!=null)
-                                handler.handle(_response.getHttpOutput());
-                            else
-                                _response.getHttpOutput().run();
-                            break;
+                            _request.setDispatcherType(null);
                         }
-
-                        default:
-                            break loop;
-
+                        break;
                     }
-                }
-                catch (Error e)
-                {
-                    if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
-                        LOG.ignore(e);
-                    else
+
+                    case ERROR_DISPATCH:
                     {
-                        error=true;
-                        LOG.warn(String.valueOf(_uri), e);
-                        _state.error(e);
+                        Throwable ex = _state.getAsyncContextEvent().getThrowable();
+
+                        // Check for error dispatch loops
+                        Integer loop_detect = (Integer)_request.getAttribute("org.eclipse.jetty.server.ERROR_DISPATCH");
+                        if (loop_detect==null)
+                            loop_detect=1;
+                        else
+                            loop_detect=loop_detect+1;
+                        _request.setAttribute("org.eclipse.jetty.server.ERROR_DISPATCH",loop_detect);
+                        if (loop_detect > getHttpConfiguration().getMaxErrorDispatches())
+                        {
+                            LOG.warn("ERROR_DISPATCH loop detected on {} {}",_request,ex);
+                            try
+                            {
+                                _response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500);
+                            }
+                            finally
+                            {
+                                _state.errorComplete();
+                            }
+                            break loop;
+                        }
+
+                        _request.setHandled(false);
+                        _response.resetBuffer();
+                        _response.getHttpOutput().reopen();
+
+
+                        String reason;
+                        if (ex == null || ex instanceof TimeoutException)
+                        {
+                            reason = "Async Timeout";
+                        }
+                        else
+                        {
+                            reason = HttpStatus.Code.INTERNAL_SERVER_ERROR.getMessage();
+                            _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ex);
+                        }
+
+                        _request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 500);
+                        _request.setAttribute(RequestDispatcher.ERROR_MESSAGE, reason);
+                        _request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, _request.getRequestURI());
+
+                        _response.setStatusWithReason(HttpStatus.INTERNAL_SERVER_ERROR_500, reason);
+
+                        ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(), _state.getContextHandler());
+                        if (eh instanceof ErrorHandler.ErrorPageMapper)
+                        {
+                            String error_page = ((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_state.getAsyncContextEvent().getSuppliedRequest());
+                            if (error_page != null)
+                                _state.getAsyncContextEvent().setDispatchPath(error_page);
+                        }
+
+                        
+                        try
+                        {
+                            _request.setDispatcherType(DispatcherType.ERROR);
+                            getServer().handleAsync(this);
+                        }
+                        finally
+                        {
+                            _request.setDispatcherType(null);
+                        }
+                        break;
+                    }
+
+                    case READ_CALLBACK:
+                    {
+                        ContextHandler handler=_state.getContextHandler();
+                        if (handler!=null)
+                            handler.handle(_request,_request.getHttpInput());
+                        else
+                            _request.getHttpInput().run();
+                        break;
+                    }
+
+                    case WRITE_CALLBACK:
+                    {
+                        ContextHandler handler=_state.getContextHandler();
+                        if (handler!=null)
+                            handler.handle(_request,_response.getHttpOutput());
+                        else
+                            _response.getHttpOutput().run();
+                        break;
+                    }
+
+                    case ASYNC_ERROR:
+                    {
+                        _state.onError();
+                        break;
+                    }
+
+                    case COMPLETE:
+                    {
+                        // TODO do onComplete here for continuations to work
+//                        _state.onComplete();
+
+                        if (!_response.isCommitted() && !_request.isHandled())
+                            _response.sendError(404);
+                        else
+                            _response.closeOutput();
                         _request.setHandled(true);
-                        handleException(e);
+
+                        // TODO do onComplete here to detect errors in final flush
+                         _state.onComplete();
+
+                        onCompleted();
+
+                        break loop;
+                    }
+
+                    default:
+                    {
+                        throw new IllegalStateException("state="+_state);
                     }
                 }
-                catch (Exception e)
+            }
+            catch (EofException|QuietServletException|BadMessageException e)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug(e);
+                handleException(e);
+            }
+            catch (Throwable e)
+            {
+                if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
                 {
-                    error=true;
-                    if (e instanceof EofException)
-                        LOG.debug(e);
+                    LOG.ignore(e);
+                }
+                else
+                {
+                    if (_connector.isStarted())
+                        LOG.warn(String.valueOf(_request.getHttpURI()), e);
                     else
-                        LOG.warn(String.valueOf(_uri), e);
-                    _state.error(e);
-                    _request.setHandled(true);
+                        LOG.debug(String.valueOf(_request.getHttpURI()), e);
                     handleException(e);
                 }
-                finally
-                {
-                    if (error && _state.isAsyncStarted())
-                        _state.errorComplete();
-                    action = _state.unhandle();
-                }
             }
 
-            if (action==Action.COMPLETE)
-            {
-                try
-                {
-                    _state.completed();
-
-                    if (!_response.isCommitted() && !_request.isHandled())
-                    {
-                        _response.sendError(404);
-                    }
-                    else
-                    {
-                        // Complete generating the response
-                        _response.closeOutput();
-                    }
-                }
-                catch(EofException|ClosedChannelException e)
-                {
-                    LOG.debug(e);
-                }
-                catch(Exception e)
-                {
-                    LOG.warn("complete failed",e);
-                }
-                finally
-                {
-                    _request.setHandled(true);
-                    _transport.completed();
-                }
-            }
-        }
-        finally
-        {
-            setCurrentHttpChannel(last);
-            if (threadName != null && LOG.isDebugEnabled())
-                Thread.currentThread().setName(threadName);
+            action = _state.unhandle();
         }
 
         if (LOG.isDebugEnabled())
             LOG.debug("{} handle exit, result {}", this, action);
 
-        return action!=Action.WAIT;
+        boolean suspended=action==Action.WAIT;
+        return !suspended;
     }
 
     /**
@@ -461,47 +493,76 @@
      */
     protected void handleException(Throwable x)
     {
-        try
+        if (_state.isAsyncStarted())
         {
-            _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,x);
-            _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,x.getClass());
-            if (_state.isSuspended())
+            // Handle exception via AsyncListener onError
+            Throwable root = _state.getAsyncContextEvent().getThrowable();
+            if (root==null)
             {
-                HttpFields fields = new HttpFields();
-                fields.add(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
-                ResponseInfo info = new ResponseInfo(_request.getHttpVersion(), fields, 0, HttpStatus.INTERNAL_SERVER_ERROR_500, null, _request.isHead());
-                boolean committed = sendResponse(info, null, true);
-                if (!committed)
-                    LOG.warn("Could not send response error 500: "+x);
-                _request.getAsyncContext().complete();
-            }
-            else if (isCommitted())
-            {
-                abort();
-                if (!(x instanceof EofException))
-                    LOG.warn("Could not send response error 500: "+x);
+                _state.error(x);
             }
             else
             {
-                _response.setHeader(HttpHeader.CONNECTION.asString(),HttpHeaderValue.CLOSE.asString());
-                _response.sendError(500, x.getMessage());
+                // TODO Can this happen?  Should this just be ISE???
+                // We've already processed an error before!
+                root.addSuppressed(x);
+                LOG.warn("Error while handling async error: ", root);
+                abort(x);
+                _state.errorComplete();
             }
         }
-        catch (IOException e)
+        else
         {
-            // We tried our best, just log
-            LOG.debug("Could not commit response error 500", e);
+            try
+            {
+                // Handle error normally
+                _request.setHandled(true);
+                _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, x);
+                _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, x.getClass());
+
+                if (isCommitted())
+                {
+                    abort(x);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Could not send response error 500, already committed", x);
+                }
+                else
+                {
+                    _response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
+
+                    if (x instanceof BadMessageException)
+                    {
+                        BadMessageException bme = (BadMessageException)x;
+                        _response.sendError(bme.getCode(), bme.getReason());
+                    }
+                    else if (x instanceof UnavailableException)
+                    {
+                        if (((UnavailableException)x).isPermanent())
+                            _response.sendError(HttpStatus.NOT_FOUND_404);
+                        else
+                            _response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
+                    }
+                    else
+                        _response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500);
+                }
+            }
+            catch (Throwable e)
+            {
+                abort(e);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Could not commit response error 500", e);
+            }
         }
     }
 
     public boolean isExpecting100Continue()
     {
-        return _expect100Continue;
+        return false;
     }
 
     public boolean isExpecting102Processing()
     {
-        return _expect102Processing;
+        return false;
     }
 
     @Override
@@ -513,215 +574,56 @@
                 _requests,
                 _committed.get(),
                 _state.getState(),
-                _uri);
+                _request.getHttpURI());
     }
 
-    @Override
-    public void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort)
-    {
-        _request.setAttribute("PROXY", protocol);
-        _request.setServerName(sAddr);
-        _request.setServerPort(dPort);
-        _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort));
-    }
-
-    @Override
-    public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
-    {
-        _expect = false;
-        _expect100Continue = false;
-        _expect102Processing = false;
-
-        _request.setTimeStamp(System.currentTimeMillis());
-        _request.setMethod(httpMethod, method);
-
-        if (httpMethod == HttpMethod.CONNECT)
-            _uri.parseConnect(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
-        else
-            _uri.parse(uri.array(),uri.arrayOffset()+uri.position(),uri.remaining());
-        _request.setUri(_uri);
-
-        String path;
-        try
-        {
-            path = _uri.getDecodedPath();
-        }
-        catch (Exception e)
-        {
-            LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1");
-            LOG.ignore(e);
-            path = _uri.getDecodedPath(StandardCharsets.ISO_8859_1);
-        }
-
-        String info = URIUtil.canonicalPath(path);
-
-        if (info == null)
-        {
-            if( path==null && _uri.getScheme()!=null &&_uri.getHost()!=null)
-            {
-                info = "/";
-                _request.setRequestURI("");
-            }
-            else
-            {
-                badMessage(400,null);
-                return true;
-            }
-        }
-        _request.setPathInfo(info);
-        _version = version == null ? HttpVersion.HTTP_0_9 : version;
-        _request.setHttpVersion(_version);
-
-        return false;
-    }
-
-    @Override
-    public boolean parsedHeader(HttpField field)
-    {
-        HttpHeader header=field.getHeader();
-        String value=field.getValue();
-        if (value == null)
-            value = "";
-        if (header != null)
-        {
-            switch (header)
-            {
-                case EXPECT:
-                    if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
-                    {
-                        HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
-                        switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
-                        {
-                            case CONTINUE:
-                                _expect100Continue = true;
-                                break;
-
-                            case PROCESSING:
-                                _expect102Processing = true;
-                                break;
-
-                            default:
-                                String[] values = value.split(",");
-                                for (int i = 0; i < values.length; i++)
-                                {
-                                    expect = HttpHeaderValue.CACHE.get(values[i].trim());
-                                    if (expect == null)
-                                        _expect = true;
-                                    else
-                                    {
-                                        switch (expect)
-                                        {
-                                            case CONTINUE:
-                                                _expect100Continue = true;
-                                                break;
-                                            case PROCESSING:
-                                                _expect102Processing = true;
-                                                break;
-                                            default:
-                                                _expect = true;
-                                        }
-                                    }
-                                }
-                        }
-                    }
-                    break;
-
-                case CONTENT_TYPE:
-                    MimeTypes.Type mime = MimeTypes.CACHE.get(value);
-                    String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(value) : mime.getCharset().toString();
-                    if (charset != null)
-                        _request.setCharacterEncodingUnchecked(charset);
-                    break;
-                default:
-            }
-        }
-
-        if (field.getName()!=null)
-            _request.getHttpFields().add(field);
-        return false;
-    }
-
-    @Override
-    public boolean parsedHostHeader(String host, int port)
-    {
-        if (_uri.getHost()==null)
-        {
-            _request.setServerName(host);
-            _request.setServerPort(port);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean headerComplete()
+    public void onRequest(MetaData.Request request)
     {
         _requests.incrementAndGet();
+        _request.setTimeStamp(System.currentTimeMillis());
         HttpFields fields = _response.getHttpFields();
-        switch (_version)
-        {
-            case HTTP_0_9:
-                break;
+        if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE))
+            fields.put(_connector.getServer().getDateField());
 
-            case HTTP_1_0:
-                if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE))
-                    _response.getHttpFields().add(_connector.getServer().getDateField());
-                break;
-
-            case HTTP_1_1:
-                if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE))
-                    _response.getHttpFields().add(_connector.getServer().getDateField());
-
-                if (_expect)
-                {
-                    badMessage(HttpStatus.EXPECTATION_FAILED_417,null);
-                    return true;
-                }
-
-                break;
-
-            default:
-                throw new IllegalStateException();
-        }
-
-        return true;
+        _request.setMetaData(request);
     }
 
-    @Override
-    public boolean content(T item)
+    public boolean onContent(HttpInput.Content content)
     {
         if (LOG.isDebugEnabled())
-            LOG.debug("{} content {}", this, item);
-        @SuppressWarnings("unchecked")
-        HttpInput<T> input = (HttpInput<T>)_request.getHttpInput();
-        input.content(item);
+            LOG.debug("{} content {}", this, content);
 
-        return false;
+        return _request.getHttpInput().addContent(content);
     }
 
-    @Override
-    public boolean messageComplete()
+    public boolean onRequestComplete()
     {
         if (LOG.isDebugEnabled())
-            LOG.debug("{} messageComplete", this);
-        _request.getHttpInput().messageComplete();
-        return true;
+            LOG.debug("{} onRequestComplete", this);
+        return _request.getHttpInput().eof();
     }
 
-    @Override
-    public void earlyEOF()
+    public void onCompleted()
     {
-        _request.getHttpInput().earlyEOF();
+        if (_requestLog!=null )
+            _requestLog.log(_request, _response);
+
+        _transport.onCompleted();
     }
 
-    @Override
-    public void badMessage(int status, String reason)
+    public boolean onEarlyEOF()
+    {
+        return _request.getHttpInput().earlyEOF();
+    }
+
+    public void onBadMessage(int status, String reason)
     {
         if (status < 400 || status > 599)
             status = HttpStatus.BAD_REQUEST_400;
 
         try
         {
-            if (_state.handling()==Action.REQUEST_DISPATCH)
+            if (_state.handling()==Action.DISPATCH)
             {
                 ByteBuffer content=null;
                 HttpFields fields=new HttpFields();
@@ -730,7 +632,7 @@
                 if (handler!=null)
                     content=handler.badMessageError(status,reason,fields);
 
-                sendResponse(new ResponseInfo(HttpVersion.HTTP_1_1,fields,0,status,reason,false),content ,true);
+                sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1,status,reason,fields,BufferUtil.length(content)),content ,true);
             }
         }
         catch (IOException e)
@@ -739,33 +641,36 @@
         }
         finally
         {
+            // TODO: review whether it's the right state to check.
             if (_state.unhandle()==Action.COMPLETE)
-                _state.completed();
+                _state.onComplete();
             else
-                throw new IllegalStateException();
+                throw new IllegalStateException(); // TODO: don't throw from finally blocks !
+            onCompleted();
         }
     }
 
-    protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback)
+    protected boolean sendResponse(MetaData.Response info, ByteBuffer content, boolean complete, final Callback callback)
     {
         boolean committing = _committed.compareAndSet(false, true);
         if (committing)
         {
             // We need an info to commit
             if (info==null)
-                info = _response.newResponseInfo();
+                info = _response.newResponseMetaData();
+            commit(info);
 
             // wrap callback to process 100 responses
             final int status=info.getStatus();
             final Callback committed = (status<200&&status>=100)?new Commit100Callback(callback):new CommitCallback(callback);
 
             // committing write
-            _transport.send(info, content, complete, committed);
+            _transport.send(info, _request.isHead(), content, complete, committed);
         }
         else if (info==null)
         {
             // This is a normal write
-            _transport.send(content, complete, callback);
+            _transport.send(null,_request.isHead(), content, complete, callback);
         }
         else
         {
@@ -774,7 +679,7 @@
         return committing;
     }
 
-    protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete) throws IOException
+    protected boolean sendResponse(MetaData.Response info, ByteBuffer content, boolean complete) throws IOException
     {
         try(Blocker blocker = _response.getHttpOutput().acquireWriteBlockingCallback())
         {
@@ -782,6 +687,20 @@
             blocker.block();
             return committing;
         }
+        catch (Throwable failure)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(failure);
+            abort(failure);
+            throw failure;
+        }
+    }
+
+    protected void commit (MetaData.Response info)
+    {
+        _committedMetaData=info;
+        if (LOG.isDebugEnabled())
+            LOG.debug("Commit {} to {}",info,this);
     }
 
     public boolean isCommitted()
@@ -791,16 +710,23 @@
 
     /**
      * <p>Non-Blocking write, committing the response if needed.</p>
-     *
+     * Called as last link in HttpOutput.Filter chain
      * @param content  the content buffer to write
      * @param complete whether the content is complete for the response
      * @param callback Callback when complete or failed
      */
-    protected void write(ByteBuffer content, boolean complete, Callback callback)
+    @Override
+    public void write(ByteBuffer content, boolean complete, Callback callback)
     {
+        _written+=BufferUtil.length(content);
         sendResponse(null,content,complete,callback);
     }
 
+    public HttpOutput.Interceptor getNextInterceptor()
+    {
+        return null;
+    }
+
     protected void execute(Runnable task)
     {
         _connector.getExecutor().execute(task);
@@ -811,7 +737,6 @@
         return _connector.getScheduler();
     }
 
-    /* ------------------------------------------------------------ */
     /**
      * @return true if the HttpChannel can efficiently use direct buffer (typically this means it is not over SSL or a multiplexed protocol)
      */
@@ -821,12 +746,16 @@
     }
 
     /**
-     * If a write or similar to this channel fails this method should be called. The standard implementation
-     * is to call {@link HttpTransport#abort()}
+     * If a write or similar operation to this channel fails,
+     * then this method should be called.
+     * <p>
+     * The standard implementation calls {@link HttpTransport#abort(Throwable)}.
+     *
+     * @param failure the failure that caused the abort.
      */
-    public void abort()
+    public void abort(Throwable failure)
     {
-        _transport.abort();
+        _transport.abort(failure);
     }
 
     private class CommitCallback implements Callback
@@ -839,6 +768,12 @@
         }
 
         @Override
+        public boolean isNonBlocking()
+        {
+            return _callback.isNonBlocking();
+        }
+
+        @Override
         public void succeeded()
         {
             _callback.succeeded();
@@ -847,16 +782,17 @@
         @Override
         public void failed(final Throwable x)
         {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Commit failed", x);
+
             if (x instanceof EofException || x instanceof ClosedChannelException)
             {
-                LOG.debug(x);
                 _callback.failed(x);
                 _response.getHttpOutput().closed();
             }
             else
             {
-                LOG.warn("Commit failed",x);
-                _transport.send(HttpGenerator.RESPONSE_500_INFO,null,true,new Callback()
+                _transport.send(HttpGenerator.RESPONSE_500_INFO, false, null, true, new Callback()
                 {
                     @Override
                     public void succeeded()
@@ -868,7 +804,6 @@
                     @Override
                     public void failed(Throwable th)
                     {
-                        LOG.ignore(th);
                         _callback.failed(x);
                         _response.getHttpOutput().closed();
                     }
@@ -895,4 +830,5 @@
 
     }
 
+
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
new file mode 100644
index 0000000..9530c3d9
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
@@ -0,0 +1,451 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HostPortHttpField;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpParser;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * A HttpChannel customized to be transported over the HTTP/1 protocol
+ */
+class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler
+{
+    private static final Logger LOG = Log.getLogger(HttpChannelOverHttp.class);
+    private final static HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE,"h2c");
+
+    private final HttpFields _fields = new HttpFields();
+    private final MetaData.Request _metadata = new MetaData.Request(_fields);
+    private final HttpConnection _httpConnection;
+    private HttpField _connection;
+    private HttpField _upgrade = null;
+    private boolean _delayedForContent;
+    private boolean _unknownExpectation = false;
+    private boolean _expect100Continue = false;
+    private boolean _expect102Processing = false;
+
+
+    public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport)
+    {
+        super(connector,config,endPoint,transport);
+        _httpConnection = httpConnection;
+        _metadata.setURI(new HttpURI());
+    }
+
+    @Override
+    protected HttpInput newHttpInput(HttpChannelState state)
+    {
+        return new HttpInputOverHTTP(state);
+    }
+
+    @Override
+    public void recycle()
+    {
+        super.recycle();
+        _unknownExpectation = false;
+        _expect100Continue = false;
+        _expect102Processing = false;
+        _metadata.recycle();
+        _connection=null;
+        _fields.clear();
+        _upgrade=null;
+    }
+
+    @Override
+    public boolean isExpecting100Continue()
+    {
+        return _expect100Continue;
+    }
+
+    @Override
+    public boolean isExpecting102Processing()
+    {
+        return _expect102Processing;
+    }
+
+    @Override
+    public boolean startRequest(String method, String uri, HttpVersion version)
+    {
+        _metadata.setMethod(method);
+        if (HttpMethod.CONNECT.is(method))
+            _metadata.getURI().parseConnect(uri);
+        else
+            _metadata.getURI().parse(uri);
+        _metadata.setHttpVersion(version);
+        _unknownExpectation = false;
+        _expect100Continue = false;
+        _expect102Processing = false;
+        return false;
+    }
+
+    @Override
+    public void parsedHeader(HttpField field)
+    {
+        HttpHeader header=field.getHeader();
+        String value=field.getValue();
+        if (header!=null)
+        {
+            switch(header)
+            {
+                case CONNECTION:
+                    _connection=field;
+                    break;
+
+                case HOST:
+                    if (!_metadata.getURI().isAbsolute() && field instanceof HostPortHttpField)
+                    {
+                        HostPortHttpField hp = (HostPortHttpField)field;
+                        _metadata.getURI().setAuthority(hp.getHost(),hp.getPort());
+                    }
+                    break;
+
+                case EXPECT:
+                {
+                    if (_metadata.getVersion()==HttpVersion.HTTP_1_1)
+                    {
+                        HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
+                        switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
+                        {
+                            case CONTINUE:
+                                _expect100Continue = true;
+                                break;
+
+                            case PROCESSING:
+                                _expect102Processing = true;
+                                break;
+
+                            default:
+                                String[] values = field.getValues();
+                                for (int i = 0; values != null && i < values.length; i++)
+                                {
+                                    expect = HttpHeaderValue.CACHE.get(values[i].trim());
+                                    if (expect == null)
+                                        _unknownExpectation = true;
+                                    else
+                                    {
+                                        switch (expect)
+                                        {
+                                            case CONTINUE:
+                                                _expect100Continue = true;
+                                                break;
+                                            case PROCESSING:
+                                                _expect102Processing = true;
+                                                break;
+                                            default:
+                                                _unknownExpectation = true;
+                                        }
+                                    }
+                                }
+                        }
+                    }
+                    break;
+                }
+
+                case UPGRADE:
+                    _upgrade=field;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+        _fields.add(field);
+    }
+
+    /**
+     * If the associated response has the Expect header set to 100 Continue,
+     * then accessing the input stream indicates that the handler/servlet
+     * is ready for the request body and thus a 100 Continue response is sent.
+     *
+     * @throws IOException if the InputStream cannot be created
+     */
+    @Override
+    public void continue100(int available) throws IOException
+    {
+        // If the client is expecting 100 CONTINUE, then send it now.
+        // TODO: consider using an AtomicBoolean ?
+        if (isExpecting100Continue())
+        {
+            _expect100Continue = false;
+
+            // is content missing?
+            if (available == 0)
+            {
+                if (getResponse().isCommitted())
+                    throw new IOException("Committed before 100 Continues");
+
+                boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false);
+                if (!committed)
+                    throw new IOException("Concurrent commit while trying to send 100-Continue");
+            }
+        }
+    }
+
+    @Override
+    public void earlyEOF()
+    {
+        // If we have no request yet, just close
+        if (_metadata.getMethod()==null)
+            _httpConnection.close();
+        else
+            onEarlyEOF();
+    }
+
+    @Override
+    public boolean content(ByteBuffer content)
+    {
+        HttpInput.Content c = _httpConnection.newContent(content);
+        boolean handle = onContent(c) || _delayedForContent;
+        _delayedForContent=false;
+        return handle;
+    }
+
+    public void asyncReadFillInterested()
+    {
+        _httpConnection.asyncReadFillInterested();
+    }
+
+    @Override
+    public void badMessage(int status, String reason)
+    {
+        _httpConnection.getGenerator().setPersistent(false);
+        try
+        {
+            // Need to call onRequest, so RequestLog can reports as much as possible
+            onRequest(_metadata);
+        }
+        catch (Exception e)
+        {
+            LOG.ignore(e);
+        }
+
+        onBadMessage(status,reason);
+    }
+
+    @Override
+    public boolean headerComplete()
+    {
+        boolean persistent;
+
+        switch (_metadata.getVersion())
+        {
+            case HTTP_1_0:
+            {
+                if (getHttpConfiguration().isPersistentConnectionsEnabled())
+                {
+                    if (_connection!=null)
+                    {
+                        if (_connection.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
+                            persistent=true;
+                        else
+                            persistent=_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
+                    }
+                    else
+                        persistent=false;
+                }
+                else
+                    persistent=false;
+
+                if (!persistent)
+                    persistent = HttpMethod.CONNECT.is(_metadata.getMethod());
+                if (persistent)
+                    getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
+
+                break;
+            }
+
+            case HTTP_1_1:
+            {
+                if (_unknownExpectation)
+                {
+                    badMessage(HttpStatus.EXPECTATION_FAILED_417,null);
+                    return false;
+                }
+
+                if (getHttpConfiguration().isPersistentConnectionsEnabled())
+                {
+                    if (_connection!=null)
+                    {
+                        if (_connection.contains(HttpHeaderValue.CLOSE.asString()))
+                            persistent=false;
+                        else
+                            persistent=!_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()); // handle multiple connection fields
+                    }
+                    else
+                        persistent=true;
+                }
+                else
+                    persistent=false;
+
+                if (!persistent)
+                    persistent = HttpMethod.CONNECT.is(_metadata.getMethod());
+                if (!persistent)
+                    getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
+
+                if (_upgrade!=null && upgrade())
+                    return true;
+
+                break;
+            }
+
+            case HTTP_2:
+            {
+                // Allow direct "upgrade" to HTTP_2_0 only if the connector supports h2c.
+                _upgrade=PREAMBLE_UPGRADE_H2C;
+
+                if (HttpMethod.PRI.is(_metadata.getMethod()) &&
+                    "*".equals(_metadata.getURI().toString()) &&
+                    _fields.size()==0 &&
+                    upgrade())
+                    return true;
+
+                badMessage(HttpStatus.UPGRADE_REQUIRED_426,null);
+                return false;
+            }
+
+            default:
+            {
+                throw new IllegalStateException();
+            }
+        }
+
+        if (!persistent)
+            _httpConnection.getGenerator().setPersistent(false);
+
+        onRequest(_metadata);
+
+        // Should we delay dispatch until we have some content?
+        // We should not delay if there is no content expect or client is expecting 100 or the response is already committed or the request buffer already has something in it to parse
+        _delayedForContent =  (getHttpConfiguration().isDelayDispatchUntilContent() && _httpConnection.getParser().getContentLength()>0 && !isExpecting100Continue() && !isCommitted() && _httpConnection.isRequestBufferEmpty());
+
+        return !_delayedForContent;
+    }
+
+
+    /**
+     * <p>Attempts to perform a HTTP/1.1 upgrade.</p>
+     * <p>The upgrade looks up a {@link ConnectionFactory.Upgrading} from the connector
+     * matching the protocol specified in the {@code Upgrade} header.</p>
+     * <p>The upgrade may succeed, be ignored (which can allow a later handler to implement)
+     * or fail with a {@link BadMessageException}.</p>
+     * @return true if the upgrade was performed, false if it was ignored
+     * @throws BadMessageException if the upgrade failed
+     */
+    private boolean upgrade() throws BadMessageException
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("upgrade {} {}",this,_upgrade);
+
+        if (_upgrade!=PREAMBLE_UPGRADE_H2C && (_connection==null || !_connection.contains("upgrade")))
+            throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
+
+        // Find the upgrade factory
+        ConnectionFactory.Upgrading factory=null;
+        for (ConnectionFactory f : getConnector().getConnectionFactories())
+        {
+            if (f instanceof ConnectionFactory.Upgrading)
+            {
+                if (f.getProtocols().contains(_upgrade.getValue()))
+                {
+                    factory=(ConnectionFactory.Upgrading)f;
+                    break;
+                }
+            }
+        }
+
+        if (factory==null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("No factory for {} in {}",_upgrade,getConnector());
+            return false;
+        }
+
+        // Create new connection
+        HttpFields response101 = new HttpFields();
+        Connection upgrade_connection = factory.upgradeConnection(getConnector(),getEndPoint(),_metadata,response101);
+        if (upgrade_connection==null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Upgrade ignored for {} by {}",_upgrade,factory);
+            return false;
+        }
+
+        // Send 101 if needed
+        try
+        {
+            if (_upgrade!=PREAMBLE_UPGRADE_H2C)
+                sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1,HttpStatus.SWITCHING_PROTOCOLS_101,response101,0),null,true);
+        }
+        catch(IOException e)
+        {
+            throw new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500,null,e);
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Upgrade from {} to {}", getEndPoint().getConnection(),upgrade_connection);
+        getRequest().setAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE,upgrade_connection);
+        getResponse().setStatus(101);
+        getHttpTransport().onCompleted();
+        return true;
+    }
+
+    @Override
+    protected void handleException(Throwable x)
+    {
+        _httpConnection.getGenerator().setPersistent(false);
+        super.handleException(x);
+    }
+
+    @Override
+    public void abort(Throwable failure)
+    {
+        super.abort(failure);
+        _httpConnection.getGenerator().setPersistent(false);
+    }
+
+    @Override
+    public boolean messageComplete()
+    {
+        return onRequestComplete();
+    }
+
+    @Override
+    public int getHeaderCacheSize()
+    {
+        return getHttpConfiguration().getHeaderCacheSize();
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
index c0cfa2f..741496a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import javax.servlet.AsyncListener;
 import javax.servlet.RequestDispatcher;
@@ -31,6 +32,7 @@
 import org.eclipse.jetty.server.handler.ContextHandler.Context;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Locker;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 /**
@@ -42,17 +44,18 @@
 
     private final static long DEFAULT_TIMEOUT=Long.getLong("org.eclipse.jetty.server.HttpChannelState.DEFAULT_TIMEOUT",30000L);
 
-    /** The dispatched state of the HttpChannel, used to control the overall livecycle
+    /**
+     * The dispatched state of the HttpChannel, used to control the overall lifecycle
      */
     public enum State
     {
         IDLE,             // Idle request
         DISPATCHED,       // Request dispatched to filter/servlet
-        ASYNC_WAIT,       // Suspended and parked
-        ASYNC_WOKEN,      // A thread has been dispatch to handle from ASYNCWAIT
-        ASYNC_IO,         // Has been dispatched for async IO
-        COMPLETING,       // Request is completable
-        COMPLETED,        // Request is complete
+        ASYNC_WAIT,       // Suspended and waiting
+        ASYNC_WOKEN,      // Dispatch to handle from ASYNC_WAIT
+        ASYNC_IO,         // Dispatched for async IO
+        COMPLETING,       // Response is completable
+        COMPLETED,        // Response is completed
         UPGRADED          // Request upgraded the connection
     }
 
@@ -61,42 +64,48 @@
      */
     public enum Action
     {
-        REQUEST_DISPATCH, // handle a normal request dispatch  
+        DISPATCH,         // handle a normal request dispatch
         ASYNC_DISPATCH,   // handle an async request dispatch
-        ASYNC_EXPIRED,    // handle an async timeout
+        ERROR_DISPATCH,   // handle a normal error
+        ASYNC_ERROR,      // handle an async error
         WRITE_CALLBACK,   // handle an IO write callback
         READ_CALLBACK,    // handle an IO read callback
-        WAIT,             // Wait for further events 
-        COMPLETE          // Complete the channel
+        COMPLETE,         // Complete the response
+        TERMINATED,       // No further actions
+        WAIT,             // Wait for further events
     }
-    
+
     /**
-     * The state of the servlet async API.  This can lead or follow the 
+     * The state of the servlet async API.  This can lead or follow the
      * channel dispatch state and also includes reasons such as expired,
      * dispatched or completed.
      */
     public enum Async
     {
-        STARTED,
-        DISPATCH,
-        COMPLETE,
-        EXPIRING,
-        EXPIRED
+        STARTED,          // AsyncContext.startAsync() has been called
+        DISPATCH,         //
+        COMPLETE,         // AsyncContext.complete() has been called
+        EXPIRING,         // AsyncContext timeout just happened
+        EXPIRED,          // AsyncContext timeout has been processed
+        ERRORING,         // An error just happened
+        ERRORED           // The error has been processed
     }
 
     private final boolean DEBUG=LOG.isDebugEnabled();
-    private final HttpChannel<?> _channel;
+    private final Locker _locker=new Locker();
+    private final HttpChannel _channel;
 
     private List<AsyncListener> _asyncListeners;
     private State _state;
     private Async _async;
     private boolean _initial;
-    private boolean _asyncRead;
-    private boolean _asyncWrite;
+    private boolean _asyncReadPossible;
+    private boolean _asyncReadUnready;
+    private boolean _asyncWrite; // TODO refactor same as read
     private long _timeoutMs=DEFAULT_TIMEOUT;
     private AsyncContextEvent _event;
 
-    protected HttpChannelState(HttpChannel<?> channel)
+    protected HttpChannelState(HttpChannel channel)
     {
         _channel=channel;
         _state=State.IDLE;
@@ -106,7 +115,7 @@
 
     public State getState()
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _state;
         }
@@ -114,7 +123,7 @@
 
     public void addListener(AsyncListener listener)
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             if (_asyncListeners==null)
                 _asyncListeners=new ArrayList<>();
@@ -124,7 +133,7 @@
 
     public void setTimeout(long ms)
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             _timeoutMs=ms;
         }
@@ -132,7 +141,7 @@
 
     public long getTimeout()
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _timeoutMs;
         }
@@ -140,7 +149,7 @@
 
     public AsyncContextEvent getAsyncContextEvent()
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _event;
         }
@@ -149,17 +158,24 @@
     @Override
     public String toString()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
-            return String.format("%s@%x{s=%s i=%b a=%s}",getClass().getSimpleName(),hashCode(),_state,_initial,_async);
+            return String.format("%s@%x{s=%s a=%s i=%b r=%s w=%b}",getClass().getSimpleName(),hashCode(),_state,_async,_initial,
+                    _asyncReadPossible?(_asyncReadUnready?"PU":"P!U"):(_asyncReadUnready?"!PU":"!P!U"),
+                    _asyncWrite);
         }
     }
 
+    private String getStatusStringLocked()
+    {
+        return String.format("s=%s i=%b a=%s",_state,_initial,_async);
+    }
+
     public String getStatusString()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
-            return String.format("s=%s i=%b a=%s",_state,_initial,_async);
+            return getStatusStringLocked();
         }
     }
 
@@ -168,37 +184,38 @@
      */
     protected Action handling()
     {
-        synchronized (this)
+        if(DEBUG)
+            LOG.debug("{} handling {}",this,_state);
+        try(Locker.Lock lock= _locker.lock())
         {
-            if(DEBUG)
-                LOG.debug("{} handling {}",this,_state);
             switch(_state)
             {
                 case IDLE:
                     _initial=true;
                     _state=State.DISPATCHED;
-                    return Action.REQUEST_DISPATCH;
+                    return Action.DISPATCH;
 
                 case COMPLETING:
                     return Action.COMPLETE;
 
                 case COMPLETED:
-                    return Action.WAIT;
+                    return Action.TERMINATED;
 
                 case ASYNC_WOKEN:
-                    if (_asyncRead)
+                    if (_asyncReadPossible)
                     {
                         _state=State.ASYNC_IO;
-                        _asyncRead=false;
+                        _asyncReadUnready=false;
                         return Action.READ_CALLBACK;
                     }
+
                     if (_asyncWrite)
                     {
                         _state=State.ASYNC_IO;
                         _asyncWrite=false;
                         return Action.WRITE_CALLBACK;
                     }
-                    
+
                     if (_async!=null)
                     {
                         Async async=_async;
@@ -216,20 +233,27 @@
                             case EXPIRED:
                                 _state=State.DISPATCHED;
                                 _async=null;
-                                return Action.ASYNC_EXPIRED;
+                                return Action.ERROR_DISPATCH;
                             case STARTED:
-                                // TODO
-                                if (DEBUG)
-                                    LOG.debug("TODO Fix this double dispatch",new IllegalStateException(this
-                                            .getStatusString()));
                                 return Action.WAIT;
+                            case ERRORING:
+                                _state=State.DISPATCHED;
+                                return Action.ASYNC_ERROR;
+
+                            default:
+                                throw new IllegalStateException(getStatusStringLocked());
                         }
                     }
-                    
+
                     return Action.WAIT;
 
+                case ASYNC_IO:
+                case ASYNC_WAIT:
+                case DISPATCHED:
+                case UPGRADED:
                 default:
-                    throw new IllegalStateException(this.getStatusString());
+                    throw new IllegalStateException(getStatusStringLocked());
+
             }
         }
     }
@@ -237,40 +261,56 @@
     public void startAsync(AsyncContextEvent event)
     {
         final List<AsyncListener> lastAsyncListeners;
-        
-        synchronized (this)
+
+        try(Locker.Lock lock= _locker.lock())
         {
             if (_state!=State.DISPATCHED || _async!=null)
-                throw new IllegalStateException(this.getStatusString());
-            
+                throw new IllegalStateException(this.getStatusStringLocked());
+
             _async=Async.STARTED;
             _event=event;
             lastAsyncListeners=_asyncListeners;
-            _asyncListeners=null;
+            _asyncListeners=null;            
         }
 
         if (lastAsyncListeners!=null)
         {
-            for (AsyncListener listener : lastAsyncListeners)
+            Runnable callback=new Runnable()
             {
-                try
+                @Override
+                public void run()
                 {
-                    listener.onStartAsync(event);
+                    for (AsyncListener listener : lastAsyncListeners)
+                    {
+                        try
+                        {
+                            listener.onStartAsync(event);
+                        }
+                        catch(Exception e)
+                        {
+                            // TODO Async Dispatch Error
+                            LOG.warn(e);
+                        }
+                    }
                 }
-                catch(Exception e)
+                @Override
+                public String toString()
                 {
-                    LOG.warn(e);
+                    return "startAsync";
                 }
-            }
+            };
+                  
+            runInContext(event,callback);
         }
     }
 
     protected void error(Throwable th)
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             if (_event!=null)
-                _event.setThrowable(th);
+                _event.addThrowable(th);
+            _async=Async.ERRORING;
         }
     }
 
@@ -283,32 +323,27 @@
      */
     protected Action unhandle()
     {
-        synchronized (this)
+        Action action;
+        AsyncContextEvent schedule_event=null;
+        boolean read_interested=false;
+
+        if(DEBUG)
+            LOG.debug("{} unhandle {}",this,_state);
+
+        try(Locker.Lock lock= _locker.lock())
         {
-            if(DEBUG)
-                LOG.debug("{} unhandle {}",this,_state);
-            
             switch(_state)
             {
+                case COMPLETING:
+                case COMPLETED:
+                    return Action.TERMINATED;
+
                 case DISPATCHED:
                 case ASYNC_IO:
                     break;
-                default:
-                    throw new IllegalStateException(this.getStatusString());
-            }
 
-            if (_asyncRead)
-            {
-                _state=State.ASYNC_IO;
-                _asyncRead=false;
-                return Action.READ_CALLBACK;
-            }
-            
-            if (_asyncWrite)
-            {
-                _asyncWrite=false;
-                _state=State.ASYNC_IO;
-                return Action.WRITE_CALLBACK;
+                default:
+                    throw new IllegalStateException(this.getStatusStringLocked());
             }
 
             if (_async!=null)
@@ -319,146 +354,257 @@
                     case COMPLETE:
                         _state=State.COMPLETING;
                         _async=null;
-                        return Action.COMPLETE;
+                        action=Action.COMPLETE;
+                        break;
+
                     case DISPATCH:
                         _state=State.DISPATCHED;
                         _async=null;
-                        return Action.ASYNC_DISPATCH;
+                        action=Action.ASYNC_DISPATCH;
+                        break;
+
                     case EXPIRED:
                         _state=State.DISPATCHED;
                         _async=null;
-                        return Action.ASYNC_EXPIRED;
-                    case EXPIRING:
+                        action = Action.ERROR_DISPATCH;
+                        break;
+
                     case STARTED:
-                        scheduleTimeout();
+                        if (_asyncReadUnready && _asyncReadPossible)
+                        {
+                            _state=State.ASYNC_IO;
+                            _asyncReadUnready=false;
+                            action = Action.READ_CALLBACK;
+                        }
+                        else if (_asyncWrite) // TODO refactor same as read
+                        {
+                            _asyncWrite=false;
+                            _state=State.ASYNC_IO;
+                            action=Action.WRITE_CALLBACK;
+                        }
+                        else
+                        {
+                            schedule_event=_event;
+                            read_interested=_asyncReadUnready;
+                            _state=State.ASYNC_WAIT;
+                            action=Action.WAIT;
+                        }
+                        break;
+
+                    case EXPIRING:
+                        schedule_event=_event;
                         _state=State.ASYNC_WAIT;
-                        return Action.WAIT;
+                        action=Action.WAIT;
+                        break;
+
+                    case ERRORING:
+                        _state=State.DISPATCHED;
+                        action=Action.ASYNC_ERROR;
+                        break;
+
+                    case ERRORED:
+                        _state=State.DISPATCHED;
+                        action=Action.ERROR_DISPATCH;
+                        _async=null;
+                        break;
+
+                    default:
+                        _state=State.COMPLETING;
+                        action=Action.COMPLETE;
+                        break;
                 }
             }
-            
-            _state=State.COMPLETING;
-            return Action.COMPLETE;
+            else
+            {
+                _state=State.COMPLETING;
+                action=Action.COMPLETE;
+            }
         }
+
+        if (schedule_event!=null)
+            scheduleTimeout(schedule_event);
+        if (read_interested)
+            _channel.asyncReadFillInterested();
+        return action;
     }
 
     public void dispatch(ServletContext context, String path)
     {
-        boolean dispatch;
-        synchronized (this)
+        boolean dispatch=false;
+        AsyncContextEvent event=null;
+        try(Locker.Lock lock= _locker.lock())
         {
-            if (_async!=Async.STARTED && _async!=Async.EXPIRING)
-                throw new IllegalStateException("AsyncContext#dispath "+this.getStatusString());
+            boolean started=false;
+            event=_event;
+            switch(_async)
+            {
+                case STARTED:
+                    started=true;
+                    break;
+                case EXPIRING:
+                case ERRORED:
+                    break;
+                default:
+                    throw new IllegalStateException(this.getStatusStringLocked());
+            }
             _async=Async.DISPATCH;
-            
+
             if (context!=null)
                 _event.setDispatchContext(context);
             if (path!=null)
                 _event.setDispatchPath(path);
-           
-            switch(_state)
+
+            if (started)
             {
-                case DISPATCHED:
-                case ASYNC_IO:
-                    dispatch=false;
-                    break;
-                case ASYNC_WAIT:
-                    _state=State.ASYNC_WOKEN;
-                    dispatch=true;
-                    break;
-                case ASYNC_WOKEN:
-                    dispatch=false;
-                    break;
-                default:
-                    LOG.warn("async dispatched when complete {}",this);
-                    dispatch=false;
-                    break;
+                switch(_state)
+                {
+                    case DISPATCHED:
+                    case ASYNC_IO:
+                    case ASYNC_WOKEN:
+                        break;
+                    case ASYNC_WAIT:
+                        _state=State.ASYNC_WOKEN;
+                        dispatch=true;
+                        break;
+                    default:
+                        LOG.warn("async dispatched when complete {}",this);
+                        break;
+                }
             }
         }
 
-        cancelTimeout();
+        cancelTimeout(event);
         if (dispatch)
             scheduleDispatch();
     }
 
-    protected void expired()
+    protected void onTimeout()
     {
-        final List<AsyncListener> aListeners;
+        final List<AsyncListener> listeners;
         AsyncContextEvent event;
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             if (_async!=Async.STARTED)
                 return;
             _async=Async.EXPIRING;
             event=_event;
-            aListeners=_asyncListeners;
+            listeners=_asyncListeners;
+
         }
 
-        if (aListeners!=null)
+        if (LOG.isDebugEnabled())
+            LOG.debug("Async timeout {}",this);
+
+        if (listeners!=null)
         {
-            for (AsyncListener listener : aListeners)
+            Runnable callback=new Runnable()
             {
-                try
+                @Override
+                public void run()
                 {
-                    listener.onTimeout(event);
+                    for (AsyncListener listener : listeners)
+                    {
+                        try
+                        {
+                            listener.onTimeout(event);
+                        }
+                        catch(Exception e)
+                        {
+                            LOG.debug(e);
+                            event.addThrowable(e);
+                            _channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
+                            break;
+                        }
+                    }
                 }
-                catch(Exception e)
+                @Override
+                public String toString()
                 {
-                    LOG.debug(e);
-                    event.setThrowable(e);
-                    _channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
-                    break;
+                    return "onTimeout";
                 }
-            }
+            };
+            
+            runInContext(event,callback);
         }
-        
+
         boolean dispatch=false;
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
-            if (_async==Async.EXPIRING)
+            switch(_async)
             {
-                _async=Async.EXPIRED;
-                if (_state==State.ASYNC_WAIT)
-                {
-                    _state=State.ASYNC_WOKEN;
-                    dispatch=true;
-                }
+                case EXPIRING:
+                    if (event.getThrowable()==null)
+                    {
+                        _async=Async.EXPIRED;
+                        _event.addThrowable(new TimeoutException("Async API violation"));
+                    }
+                    else
+                    {
+                        _async=Async.ERRORING;
+                    }
+                    break;
+                    
+                case COMPLETE:
+                case DISPATCH:
+                    break;
+                    
+                default:
+                    throw new IllegalStateException();
+            }
+
+            if (_state==State.ASYNC_WAIT)
+            {
+                _state=State.ASYNC_WOKEN;
+                dispatch=true;
             }
         }
 
         if (dispatch)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Dispatch after async timeout {}",this);
             scheduleDispatch();
+        }
     }
 
     public void complete()
     {
         // just like resume, except don't set _dispatched=true;
         boolean handle=false;
-        synchronized (this)
+        AsyncContextEvent event=null;
+        try(Locker.Lock lock= _locker.lock())
         {
-            if (_async!=Async.STARTED && _async!=Async.EXPIRING)
-                throw new IllegalStateException(this.getStatusString());
+            boolean started=false;
+            event=_event;
+            
+            switch(_async)
+            {
+                case STARTED:
+                    started=true;
+                    break;
+                case EXPIRING:
+                case ERRORED:
+                    break;
+                default:
+                    throw new IllegalStateException(this.getStatusStringLocked());
+            }
             _async=Async.COMPLETE;
-            if (_state==State.ASYNC_WAIT)
+            
+            if (started && _state==State.ASYNC_WAIT)
             {
                 handle=true;
                 _state=State.ASYNC_WOKEN;
             }
         }
 
-        cancelTimeout();
+        cancelTimeout(event);
         if (handle)
-        {
-            ContextHandler handler=getContextHandler();
-            if (handler!=null)
-                handler.handle(_channel);
-            else
-                _channel.handle();
-        }
+            runInContext(event,_channel);
     }
 
     public void errorComplete()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             _async=Async.COMPLETE;
             _event.setDispatchContext(null);
@@ -468,22 +614,58 @@
         cancelTimeout();
     }
 
-    protected void completed()
+    protected void onError()
     {
         final List<AsyncListener> aListeners;
         final AsyncContextEvent event;
-        synchronized (this)
+
+        try(Locker.Lock lock= _locker.lock())
+        {
+            if (_state!=State.DISPATCHED/* || _async!=Async.ERRORING*/)
+                throw new IllegalStateException(this.getStatusStringLocked());
+
+            aListeners=_asyncListeners;
+            event=_event;
+            _async=Async.ERRORED;
+        }
+
+        if (event!=null && aListeners!=null)
+        {
+            event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
+            event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,event.getThrowable().getMessage());
+            for (AsyncListener listener : aListeners)
+            {
+                try
+                {
+                    listener.onError(event);
+                }
+                catch(Exception x)
+                {
+                    LOG.info("Exception while invoking listener " + listener, x);
+                }
+            }
+        }
+    }
+
+
+    protected void onComplete()
+    {
+        final List<AsyncListener> aListeners;
+        final AsyncContextEvent event;
+
+        try(Locker.Lock lock= _locker.lock())
         {
             switch(_state)
             {
                 case COMPLETING:
-                    _state=State.COMPLETED;
                     aListeners=_asyncListeners;
                     event=_event;
+                    _state=State.COMPLETED;
+                    _async=null;
                     break;
 
                 default:
-                    throw new IllegalStateException(this.getStatusString());
+                    throw new IllegalStateException(this.getStatusStringLocked());
             }
         }
 
@@ -491,41 +673,46 @@
         {
             if (aListeners!=null)
             {
-                if (event.getThrowable()!=null)
+                Runnable callback = new Runnable()
                 {
-                    event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,event.getThrowable());
-                    event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE,event.getThrowable().getMessage());
-                }
-
-                for (AsyncListener listener : aListeners)
-                {
-                    try
+                    @Override
+                    public void run()
                     {
-                        if (event.getThrowable()!=null)
-                            listener.onError(event);
-                        else
-                            listener.onComplete(event);
-                    }
-                    catch(Exception e)
+                        for (AsyncListener listener : aListeners)
+                        {
+                            try
+                            {
+                                listener.onComplete(event);
+                            }
+                            catch(Exception e)
+                            {
+                                LOG.warn(e);
+                            }
+                        }
+                    }    
+                    @Override
+                    public String toString()
                     {
-                        LOG.warn(e);
+                        return "onComplete";
                     }
-                }
+                };
+                
+                runInContext(event,callback);                
             }
-
             event.completed();
         }
     }
 
     protected void recycle()
     {
-        synchronized (this)
+        cancelTimeout();
+        try(Locker.Lock lock= _locker.lock())
         {
             switch(_state)
             {
                 case DISPATCHED:
                 case ASYNC_IO:
-                    throw new IllegalStateException(getStatusString());
+                    throw new IllegalStateException(getStatusStringLocked());
                 case UPGRADED:
                     return;
                 default:
@@ -535,17 +722,17 @@
             _state=State.IDLE;
             _async=null;
             _initial=true;
-            _asyncRead=false;
+            _asyncReadPossible=_asyncReadUnready=false;
             _asyncWrite=false;
             _timeoutMs=DEFAULT_TIMEOUT;
-            cancelTimeout();
             _event=null;
         }
     }
-    
+
     public void upgrade()
     {
-        synchronized (this)
+        cancelTimeout();
+        try(Locker.Lock lock= _locker.lock())
         {
             switch(_state)
             {
@@ -553,47 +740,58 @@
                 case COMPLETED:
                     break;
                 default:
-                    throw new IllegalStateException(getStatusString());
+                    throw new IllegalStateException(getStatusStringLocked());
             }
             _asyncListeners=null;
             _state=State.UPGRADED;
             _async=null;
             _initial=true;
-            _asyncRead=false;
+            _asyncReadPossible=_asyncReadUnready=false;
             _asyncWrite=false;
             _timeoutMs=DEFAULT_TIMEOUT;
-            cancelTimeout();
             _event=null;
         }
     }
 
-
     protected void scheduleDispatch()
     {
         _channel.execute(_channel);
     }
 
-    protected void scheduleTimeout()
+    protected void scheduleTimeout(AsyncContextEvent event)
     {
         Scheduler scheduler = _channel.getScheduler();
         if (scheduler!=null && _timeoutMs>0)
-            _event.setTimeoutTask(scheduler.schedule(_event,_timeoutMs,TimeUnit.MILLISECONDS));
+            event.setTimeoutTask(scheduler.schedule(event,_timeoutMs,TimeUnit.MILLISECONDS));
     }
 
     protected void cancelTimeout()
     {
         final AsyncContextEvent event;
-        synchronized (this)
-        { 
+        try(Locker.Lock lock= _locker.lock())
+        {
             event=_event;
         }
+        cancelTimeout(event);
+    }
+
+    protected void cancelTimeout(AsyncContextEvent event)
+    {
         if (event!=null)
             event.cancelTimeoutTask();
     }
+    
+    public boolean isIdle()
+    {
+        try(Locker.Lock lock= _locker.lock())
+        {
+            return _state==State.IDLE;
+        }
+    }
 
     public boolean isExpired()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _async==Async.EXPIRED;
         }
@@ -601,7 +799,7 @@
 
     public boolean isInitial()
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _initial;
         }
@@ -609,7 +807,7 @@
 
     public boolean isSuspended()
     {
-        synchronized(this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _state==State.ASYNC_WAIT || _state==State.DISPATCHED && _async==Async.STARTED;
         }
@@ -617,7 +815,7 @@
 
     boolean isCompleting()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _state==State.COMPLETING;
         }
@@ -625,7 +823,7 @@
 
     boolean isCompleted()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return _state == State.COMPLETED;
         }
@@ -633,8 +831,8 @@
 
     public boolean isAsyncStarted()
     {
-        synchronized (this)
-        {    
+        try(Locker.Lock lock= _locker.lock())
+        {
             if (_state==State.DISPATCHED)
                 return _async!=null;
             return _async==Async.STARTED || _async==Async.EXPIRING;
@@ -643,7 +841,7 @@
 
     public boolean isAsync()
     {
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             return !_initial || _async!=null;
         }
@@ -654,7 +852,7 @@
         return _channel.getRequest();
     }
 
-    public HttpChannel<?> getHttpChannel()
+    public HttpChannel getHttpChannel()
     {
         return _channel;
     }
@@ -662,11 +860,15 @@
     public ContextHandler getContextHandler()
     {
         final AsyncContextEvent event;
-        synchronized (this)
-        { 
+        try(Locker.Lock lock= _locker.lock())
+        {
             event=_event;
         }
-       
+        return getContextHandler(event);
+    }
+
+    ContextHandler getContextHandler(AsyncContextEvent event)
+    {
         if (event!=null)
         {
             Context context=((Context)event.getServletContext());
@@ -679,15 +881,29 @@
     public ServletResponse getServletResponse()
     {
         final AsyncContextEvent event;
-        synchronized (this)
-        { 
+        try(Locker.Lock lock= _locker.lock())
+        {
             event=_event;
         }
+        return getServletResponse(event);
+    }
+    
+    public ServletResponse getServletResponse(AsyncContextEvent event)
+    {
         if (event!=null && event.getSuppliedResponse()!=null)
             return event.getSuppliedResponse();
         return _channel.getResponse();
     }
-
+    
+    void runInContext(AsyncContextEvent event,Runnable runnable)
+    {
+        ContextHandler contextHandler = getContextHandler(event);
+        if (contextHandler==null)
+            runnable.run();
+        else
+            contextHandler.handle(_channel.getRequest(),runnable);
+    }
+    
     public Object getAttribute(String name)
     {
         return _channel.getRequest().getAttribute(name);
@@ -703,29 +919,91 @@
         _channel.getRequest().setAttribute(name,attribute);
     }
 
-    public void onReadPossible()
-    {
-        boolean handle=false;
 
-        synchronized (this)
+    /* ------------------------------------------------------------ */
+    /** Called to signal async read isReady() has returned false.
+     * This indicates that there is no content available to be consumed
+     * and that once the channel enteres the ASYNC_WAIT state it will
+     * register for read interest by calling {@link HttpChannel#asyncReadFillInterested()}
+     * either from this method or from a subsequent call to {@link #unhandle()}.
+     */
+    public void onReadUnready()
+    {
+        boolean interested=false;
+        try(Locker.Lock lock= _locker.lock())
         {
-            _asyncRead=true;
-            if (_state==State.ASYNC_WAIT)
+            // We were already unready, this is not a state change, so do nothing
+            if (!_asyncReadUnready)
             {
-                _state=State.ASYNC_WOKEN;
-                handle=true;
+                _asyncReadUnready=true;
+                _asyncReadPossible=false; // Assumes this has been checked in isReady() with lock held
+                if (_state==State.ASYNC_WAIT)
+                    interested=true;
             }
         }
 
-        if (handle)
-            _channel.execute(_channel);
+        if (interested)
+            _channel.asyncReadFillInterested();
     }
-    
-    public void onWritePossible()
+
+    /* ------------------------------------------------------------ */
+    /** Called to signal that content is now available to read.
+     * If the channel is in ASYNC_WAIT state and unready (ie isReady() has
+     * returned false), then the state is changed to ASYNC_WOKEN and true
+     * is returned.
+     * @return True IFF the channel was unready and in ASYNC_WAIT state
+     */
+    public boolean onReadPossible()
+    {
+        boolean woken=false;
+        try(Locker.Lock lock= _locker.lock())
+        {
+            _asyncReadPossible=true;
+            if (_state==State.ASYNC_WAIT && _asyncReadUnready)
+            {
+                woken=true;
+                _state=State.ASYNC_WOKEN;
+            }
+        }
+        return woken;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Called to signal that the channel is ready for a callback.
+     * This is similar to calling {@link #onReadUnready()} followed by
+     * {@link #onReadPossible()}, except that as content is already
+     * available, read interest is never set.
+     * @return true if woken
+     */
+    public boolean onReadReady()
+    {
+        boolean woken=false;
+        try(Locker.Lock lock= _locker.lock())
+        {
+            _asyncReadUnready=true;
+            _asyncReadPossible=true;
+            if (_state==State.ASYNC_WAIT)
+            {
+                woken=true;
+                _state=State.ASYNC_WOKEN;
+            }
+        }
+        return woken;
+    }
+
+    public boolean isReadPossible()
+    {
+        try(Locker.Lock lock= _locker.lock())
+        {
+            return _asyncReadPossible;
+        }
+    }
+
+    public boolean onWritePossible()
     {
         boolean handle=false;
 
-        synchronized (this)
+        try(Locker.Lock lock= _locker.lock())
         {
             _asyncWrite=true;
             if (_state==State.ASYNC_WAIT)
@@ -735,8 +1013,7 @@
             }
         }
 
-        if (handle)
-            _channel.execute(_channel);
+        return handle;
     }
-    
+
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
index f1cce65..d2ec7bd 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
@@ -18,11 +18,16 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.IOException;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.util.Jetty;
+import org.eclipse.jetty.util.TreeTrie;
+import org.eclipse.jetty.util.Trie;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 
@@ -32,7 +37,7 @@
  * <p>This class is a holder of HTTP configuration for use by the 
  * {@link HttpChannel} class.  Typically a HTTPConfiguration instance
  * is instantiated and passed to a {@link ConnectionFactory} that can 
- * create HTTP channels (eg HTTP, AJP or SPDY).</p>
+ * create HTTP channels (e.g. HTTP, AJP or FCGI).</p>
  * <p>The configuration held by this class is not for the wire protocol,
  * but for the interpretation and handling of HTTP requests that could
  * be transported by a variety of protocols.
@@ -43,18 +48,22 @@
 {
     public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")";
 
-    private List<Customizer> _customizers=new CopyOnWriteArrayList<>();
+    private final List<Customizer> _customizers=new CopyOnWriteArrayList<>();
+    private final Trie<Boolean> _formEncodedMethods = new TreeTrie<>();
     private int _outputBufferSize=32*1024;
     private int _outputAggregationSize=_outputBufferSize/4;
     private int _requestHeaderSize=8*1024;
     private int _responseHeaderSize=8*1024;
     private int _headerCacheSize=512;
     private int _securePort;
+    private long _blockingTimeout=-1;
     private String _secureScheme = HttpScheme.HTTPS.asString();
     private boolean _sendServerVersion = true;
     private boolean _sendXPoweredBy = false;
     private boolean _sendDateHeader = true;
-    private boolean _delayDispatchUntilContent = false;
+    private boolean _delayDispatchUntilContent = true;
+    private boolean _persistentConnectionsEnabled = true;
+    private int _maxErrorDispatches = 10;
 
     /* ------------------------------------------------------------ */
     /** 
@@ -84,6 +93,8 @@
     
     public HttpConfiguration()
     {
+        _formEncodedMethods.put(HttpMethod.POST.asString(),Boolean.TRUE);
+        _formEncodedMethods.put(HttpMethod.PUT.asString(),Boolean.TRUE);
     }
     
     /* ------------------------------------------------------------ */
@@ -93,15 +104,22 @@
     public HttpConfiguration(HttpConfiguration config)
     {
         _customizers.addAll(config._customizers);
+        for (String s:config._formEncodedMethods.keySet())
+            _formEncodedMethods.put(s,Boolean.TRUE);
         _outputBufferSize=config._outputBufferSize;
         _outputAggregationSize=config._outputAggregationSize;
         _requestHeaderSize=config._requestHeaderSize;
         _responseHeaderSize=config._responseHeaderSize;
-        _securePort=config._securePort;
+        _headerCacheSize=config._headerCacheSize;
         _secureScheme=config._secureScheme;
+        _securePort=config._securePort;
+        _blockingTimeout=config._blockingTimeout;
         _sendDateHeader=config._sendDateHeader;
         _sendServerVersion=config._sendServerVersion;
-        _headerCacheSize=config._headerCacheSize;
+        _sendXPoweredBy=config._sendXPoweredBy;
+        _delayDispatchUntilContent=config._delayDispatchUntilContent;
+        _persistentConnectionsEnabled=config._persistentConnectionsEnabled;
+        _maxErrorDispatches=config._maxErrorDispatches;
     }
     
     /* ------------------------------------------------------------ */
@@ -182,6 +200,46 @@
     }
 
     /* ------------------------------------------------------------ */
+    @ManagedAttribute("True if HTTP/1 persistent connection are enabled")
+    public boolean isPersistentConnectionsEnabled()
+    {
+        return _persistentConnectionsEnabled;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the timeout applied to blocking operations.
+     * <p>This timeout is in addition to the {@link Connector#getIdleTimeout()}, and applies
+     * to the total operation (as opposed to the idle timeout that applies to the time no 
+     * data is being sent).
+     * @return -1, for no blocking timeout (default), 0 for a blocking timeout equal to the 
+     * idle timeout; &gt;0 for a timeout in ms applied to the total blocking operation.
+     */
+    @ManagedAttribute("Timeout in MS for blocking operations.")
+    public long getBlockingTimeout()
+    {
+        return _blockingTimeout;
+    }
+
+    /**
+     * Set the timeout applied to blocking operations.
+     * <p>This timeout is in addition to the {@link Connector#getIdleTimeout()}, and applies
+     * to the total operation (as opposed to the idle timeout that applies to the time no 
+     * data is being sent).
+     * @param blockingTimeout -1, for no blocking timeout (default), 0 for a blocking timeout equal to the 
+     * idle timeout; &gt;0 for a timeout in ms applied to the total blocking operation.
+     */
+    public void setBlockingTimeout(long blockingTimeout)
+    {
+        _blockingTimeout = blockingTimeout;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setPersistentConnectionsEnabled(boolean persistentConnectionsEnabled)
+    {
+        _persistentConnectionsEnabled = persistentConnectionsEnabled;
+    }
+
+    /* ------------------------------------------------------------ */
     public void setSendServerVersion (boolean sendServerVersion)
     {
         _sendServerVersion = sendServerVersion;
@@ -195,6 +253,19 @@
     }
 
     /* ------------------------------------------------------------ */
+    public void writePoweredBy(Appendable out,String preamble,String postamble) throws IOException
+    {
+        if (getSendServerVersion())
+        {
+            if (preamble!=null)
+                out.append(preamble);
+            out.append(Jetty.POWERED_BY);
+            if (postamble!=null)
+                out.append(postamble);
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
     public void setSendXPoweredBy (boolean sendXPoweredBy)
     {
         _sendXPoweredBy=sendXPoweredBy;
@@ -222,7 +293,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param delay if true, delay the application dispatch until content is available
+     * @param delay if true, delay the application dispatch until content is available (default false)
      */
     public void setDelayDispatchUntilContent(boolean delay)
     {
@@ -328,6 +399,7 @@
         _secureScheme = secureScheme;
     }
 
+    /* ------------------------------------------------------------ */
     @Override
     public String toString()
     {
@@ -339,4 +411,72 @@
                 _secureScheme,_securePort,
                 _customizers);
     }
+
+    /* ------------------------------------------------------------ */
+    /** Set the form encoded methods.
+     * @param methods HTTP Methods of requests that can be decoded as 
+     * x-www-form-urlencoded content to be made available via the 
+     * {@link Request#getParameter(String)} and associated APIs 
+     */
+    public void setFormEncodedMethods(String... methods)
+    {
+        _formEncodedMethods.clear();
+        for (String method:methods)
+            addFormEncodedMethod(method);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return Set of HTTP Methods of requests that can be decoded as 
+     * x-www-form-urlencoded content to be made available via the 
+     * {@link Request#getParameter(String)} and associated APIs
+     */
+    public Set<String> getFormEncodedMethods()
+    {
+        return _formEncodedMethods.keySet();
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Add a form encoded HTTP Method 
+     * @param method HTTP Method of requests that can be decoded as 
+     * x-www-form-urlencoded content to be made available via the 
+     * {@link Request#getParameter(String)} and associated APIs
+     */
+    public void addFormEncodedMethod(String method)
+    {
+        _formEncodedMethods.put(method,Boolean.TRUE);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Test if the method type supports <code>x-www-form-urlencoded</code> content
+     * 
+     * @param method the method type
+     * @return True of the requests of this method type can be
+     * decoded as <code>x-www-form-urlencoded</code> content to be made available via the 
+     * {@link Request#getParameter(String)} and associated APIs
+     */
+    public boolean isFormEncodedMethod(String method)
+    {
+        return Boolean.TRUE.equals(_formEncodedMethods.get(method));
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return The maximum error dispatches for a request to prevent looping on an error
+     */
+    @ManagedAttribute("The maximum ERROR dispatches for a request for loop prevention (default 10)")
+    public int getMaxErrorDispatches()
+    {
+        return _maxErrorDispatches;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param max The maximum error dispatches for a request to prevent looping on an error
+     */
+    public void setMaxErrorDispatches(int max)
+    {
+        _maxErrorDispatches=max;
+    }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java
index c489ae9..b835c6c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java
@@ -22,15 +22,17 @@
 import java.nio.ByteBuffer;
 import java.nio.channels.WritePendingException;
 import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
 
+import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
-import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpParser;
+import org.eclipse.jetty.http.HttpParser.RequestHandler;
 import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http.PreEncodedHttpField;
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
@@ -47,30 +49,34 @@
  */
 public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, Connection.UpgradeFrom
 {
+    private static final Logger LOG = Log.getLogger(HttpConnection.class);
+    public static final HttpField CONNECTION_CLOSE = new PreEncodedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE.asString());
     public static final String UPGRADE_CONNECTION_ATTRIBUTE = "org.eclipse.jetty.server.HttpConnection.UPGRADE";
     private static final boolean REQUEST_BUFFER_DIRECT=false;
     private static final boolean HEADER_BUFFER_DIRECT=false;
     private static final boolean CHUNK_BUFFER_DIRECT=false;
-    private static final Logger LOG = Log.getLogger(HttpConnection.class);
     private static final ThreadLocal<HttpConnection> __currentConnection = new ThreadLocal<>();
 
     private final HttpConfiguration _config;
     private final Connector _connector;
     private final ByteBufferPool _bufferPool;
+    private final HttpInput _input;
     private final HttpGenerator _generator;
     private final HttpChannelOverHttp _channel;
     private final HttpParser _parser;
+    private final AtomicInteger _contentBufferReferences=new AtomicInteger();
     private volatile ByteBuffer _requestBuffer = null;
     private volatile ByteBuffer _chunk = null;
+    private final BlockingReadCallback _blockingReadCallback = new BlockingReadCallback();
+    private final AsyncReadCallback _asyncReadCallback = new AsyncReadCallback();
     private final SendCallback _sendCallback = new SendCallback();
 
-
-    /* ------------------------------------------------------------ */
-    /** Get the current connection that this thread is dispatched to.
+    /**
+     * Get the current connection that this thread is dispatched to.
      * Note that a thread may be processing a request asynchronously and
      * thus not be dispatched to the connection.
-     * @see Request#getAttribute(String) for a more general way to access the HttpConnection
      * @return the current HttpConnection or null
+     * @see Request#getAttribute(String) for a more general way to access the HttpConnection
      */
     public static HttpConnection getCurrentConnection()
     {
@@ -84,41 +90,33 @@
         return last;
     }
 
-    public HttpConfiguration getHttpConfiguration()
-    {
-        return _config;
-    }
-
     public HttpConnection(HttpConfiguration config, Connector connector, EndPoint endPoint)
     {
-        // Tell AbstractConnector executeOnFillable==true because we want the same thread that
-        // does the HTTP parsing to handle the request so its cache is hot
-        super(endPoint, connector.getExecutor(),true);
-
+        super(endPoint, connector.getExecutor());
         _config = config;
         _connector = connector;
         _bufferPool = _connector.getByteBufferPool();
         _generator = newHttpGenerator();
-        HttpInput<ByteBuffer> input = newHttpInput();
-        _channel = newHttpChannel(input);
+        _channel = newHttpChannel();
+        _input = _channel.getRequest().getHttpInput();
         _parser = newHttpParser();
         if (LOG.isDebugEnabled())
             LOG.debug("New HTTP Connection {}", this);
     }
 
+    public HttpConfiguration getHttpConfiguration()
+    {
+        return _config;
+    }
+
     protected HttpGenerator newHttpGenerator()
     {
         return new HttpGenerator(_config.getSendServerVersion(),_config.getSendXPoweredBy());
     }
 
-    protected HttpInput<ByteBuffer> newHttpInput()
+    protected HttpChannelOverHttp newHttpChannel()
     {
-        return new HttpInputOverHTTP(this);
-    }
-
-    protected HttpChannelOverHttp newHttpChannel(HttpInput<ByteBuffer> httpInput)
-    {
-        return new HttpChannelOverHttp(_connector, _config, getEndPoint(), this, httpInput);
+        return new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this);
     }
 
     protected HttpParser newHttpParser()
@@ -126,7 +124,7 @@
         return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize());
     }
 
-    protected HttpParser.RequestHandler<ByteBuffer> newRequestHandler()
+    protected HttpParser.RequestHandler newRequestHandler()
     {
         return _channel;
     }
@@ -141,7 +139,7 @@
         return _connector;
     }
 
-    public HttpChannel<?> getHttpChannel()
+    public HttpChannel getHttpChannel()
     {
         return _channel;
     }
@@ -151,6 +149,17 @@
         return _parser;
     }
 
+    public HttpGenerator getGenerator()
+    {
+        return _generator;
+    }
+
+    @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        return getEndPoint().isOptimizedForDirectBuffers();
+    }
+
     @Override
     public int getMessagesIn()
     {
@@ -179,6 +188,8 @@
     {
         if (_requestBuffer != null && !_requestBuffer.hasRemaining())
         {
+            if (LOG.isDebugEnabled())
+                LOG.debug("releaseRequestBuffer {}",this);
             ByteBuffer buffer=_requestBuffer;
             _requestBuffer=null;
             _bufferPool.release(buffer);
@@ -192,148 +203,156 @@
         return _requestBuffer;
     }
 
-    /**
-     * <p>Parses and handles HTTP messages.</p>
-     * <p>This method is called when this {@link Connection} is ready to read bytes from the {@link EndPoint}.
-     * However, it can also be called if there is unconsumed data in the _requestBuffer, as a result of
-     * resuming a suspended request when there is a pipelined request already read into the buffer.</p>
-     * <p>This method fills bytes and parses them until either: EOF is filled; 0 bytes are filled;
-     * the HttpChannel finishes handling; or the connection has changed.</p>
-     */
+    public boolean isRequestBufferEmpty()
+    {
+        return BufferUtil.isEmpty(_requestBuffer);
+    }
+
     @Override
     public void onFillable()
     {
         if (LOG.isDebugEnabled())
-            LOG.debug("{} onFillable {}", this, _channel.getState());
+            LOG.debug("{} onFillable enter {} {}", this, _channel.getState(),BufferUtil.toDetailString(_requestBuffer));
 
-        final HttpConnection last=setCurrentConnection(this);
-        int filled=Integer.MAX_VALUE;
-        boolean suspended=false;
+        HttpConnection last=setCurrentConnection(this);
         try
         {
-            // while not suspended and not upgraded
-            while (!suspended && getEndPoint().getConnection()==this)
+            while (true)
             {
-                // Do we need some data to parse
-                if (BufferUtil.isEmpty(_requestBuffer))
+                // Fill the request buffer (if needed)
+                int filled = fillRequestBuffer();
+
+                // Parse the request buffer
+                boolean handle = parseRequestBuffer();
+                // If there was a connection upgrade, the other
+                // connection took over, nothing more to do here.
+                if (getEndPoint().getConnection()!=this)
+                    break;
+
+                // Handle close parser
+                if (_parser.isClose() || _parser.isClosed())
                 {
-                    // If the previous iteration filled 0 bytes or saw a close, then break here
-                    if (filled<=0)
+                    close();
+                    break;
+                }
+
+                // Handle channel event
+                if (handle)
+                {
+                    boolean suspended = !_channel.handle();
+
+                    // We should break iteration if we have suspended or changed connection or this is not the handling thread.
+                    if (suspended || getEndPoint().getConnection() != this)
                         break;
-
-                    // Can we fill?
-                    if(getEndPoint().isInputShutdown())
-                    {
-                        // No pretend we read -1
-                        filled=-1;
-                        _parser.atEOF();
-                    }
-                    else
-                    {
-                        // Get a buffer
-                        // We are not in a race here for the request buffer as we have not yet received a request,
-                        // so there are not an possible legal threads calling #parseContent or #completed.
-                        _requestBuffer = getRequestBuffer();
-
-                        // fill
-                        filled = getEndPoint().fill(_requestBuffer);
-                        if (filled==0) // Do a retry on fill 0 (optimization for SSL connections)
-                            filled = getEndPoint().fill(_requestBuffer);
-
-                        // tell parser
-                        if (filled < 0)
-                            _parser.atEOF();
-                    }
                 }
 
-                // Parse the buffer
-                if (_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer))
+                // Continue or break?
+                else if (filled<=0)
                 {
-                    // The parser returned true, which indicates the channel is ready to handle a request.
-                    // Call the channel and this will either handle the request/response to completion OR,
-                    // if the request suspends, the request/response will be incomplete so the outer loop will exit.
-                    // Not that onFillable no longer manipulates the request buffer from this point and that is
-                    // left to threads calling #completed or #parseContent (which may be this thread inside handle())
-                    suspended = !_channel.handle();
-                }
-                else
-                {
-                    // We parsed what we could, recycle the request buffer
-                    // We are not in a race here for the request buffer as we have not yet received a request,
-                    // so there are not an possible legal threads calling #parseContent or #completed.
-                    releaseRequestBuffer();
+                    if (filled==0)
+                        fillInterested();
+                    break;
                 }
             }
         }
-        catch (EofException e)
-        {
-            LOG.debug(e);
-        }
-        catch (Exception e)
-        {
-            if (_parser.isIdle())
-                LOG.debug(e);
-            else
-                LOG.warn(this.toString(), e);
-            close();
-        }
         finally
         {
             setCurrentConnection(last);
-            if (!suspended && getEndPoint().isOpen() && getEndPoint().getConnection()==this)
-            {
-                fillInterested();
-            }
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} onFillable exit {} {}", this, _channel.getState(),BufferUtil.toDetailString(_requestBuffer));
         }
     }
 
     /* ------------------------------------------------------------ */
     /** Fill and parse data looking for content
-     * @throws IOException
+     * @return true if an {@link RequestHandler} method was called and it returned true;
      */
-    protected void parseContent() throws IOException
+    protected boolean fillAndParseForContent()
     {
-        // Not in a race here for the request buffer with #onFillable because an async consumer of
-        // content would only be started after onFillable has given up control.
-        // In a little bit of a race with #completed, but then not sure if it is legal to be doing
-        // async calls to IO and have a completed call at the same time.
-        ByteBuffer requestBuffer = getRequestBuffer();
-
+        boolean handled=false;
         while (_parser.inContentState())
         {
-            // Can the parser progress (even with an empty buffer)
-            boolean parsed = _parser.parseNext(requestBuffer==null?BufferUtil.EMPTY_BUFFER:requestBuffer);
-
-            // No, we can we try reading some content?
-            if (BufferUtil.isEmpty(requestBuffer) && getEndPoint().isInputShutdown())
-            {
-                _parser.atEOF();
-                if (parsed)
-                    break;
-                continue;
-            }
-
-            if (parsed)
+            int filled = fillRequestBuffer();
+            boolean handle = parseRequestBuffer();
+            handled|=handle;
+            if (handle || filled<=0 || _channel.getRequest().getHttpInput().hasContent())
                 break;
-
-            // OK lets read some data
-            int filled=getEndPoint().fill(requestBuffer);
-            if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled'
-                LOG.debug("{} filled {}",this,filled);
-            if (filled<=0)
-            {
-                if (filled<0)
-                {
-                    _parser.atEOF();
-                    continue;
-                }
-                break;
-            }
         }
+        return handled;
     }
 
+    /* ------------------------------------------------------------ */
+    private int fillRequestBuffer()
+    {
+        if (_contentBufferReferences.get()>0)
+        {
+            LOG.warn("{} fill with unconsumed content!",this);
+            return 0;
+        }
+
+        if (BufferUtil.isEmpty(_requestBuffer))
+        {
+            // Can we fill?
+            if(getEndPoint().isInputShutdown())
+            {
+                // No pretend we read -1
+                _parser.atEOF();
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} filled -1 {}",this,BufferUtil.toDetailString(_requestBuffer));
+                return -1;
+            }
+
+            // Get a buffer
+            // We are not in a race here for the request buffer as we have not yet received a request,
+            // so there are not an possible legal threads calling #parseContent or #completed.
+            _requestBuffer = getRequestBuffer();
+
+            // fill
+            try
+            {
+                int filled = getEndPoint().fill(_requestBuffer);
+                if (filled==0) // Do a retry on fill 0 (optimization for SSL connections)
+                    filled = getEndPoint().fill(_requestBuffer);
+
+                // tell parser
+                if (filled < 0)
+                    _parser.atEOF();
+
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} filled {} {}",this,filled,BufferUtil.toDetailString(_requestBuffer));
+
+                return filled;
+            }
+            catch (IOException e)
+            {
+                LOG.debug(e);
+                return -1;
+            }
+        }
+        return 0;
+    }
+
+    /* ------------------------------------------------------------ */
+    private boolean parseRequestBuffer()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} parse {} {}",this,BufferUtil.toDetailString(_requestBuffer));
+
+        boolean handle = _parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} parsed {} {}",this,handle,_parser);
+
+        // recycle buffer ?
+        if (_contentBufferReferences.get()==0)
+            releaseRequestBuffer();
+
+        return handle;
+    }
+
+    /* ------------------------------------------------------------ */
     @Override
-    public void completed()
+    public void onCompleted()
     {
         // Handle connection upgrades
         if (_channel.getResponse().getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101)
@@ -341,12 +360,21 @@
             Connection connection = (Connection)_channel.getRequest().getAttribute(UPGRADE_CONNECTION_ATTRIBUTE);
             if (connection != null)
             {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Upgrade from {} to {}", this, connection);
                 _channel.getState().upgrade();
                 getEndPoint().upgrade(connection);
-                _channel.reset();
+                _channel.recycle();
                 _parser.reset();
                 _generator.reset();
-                releaseRequestBuffer();
+                if (_contentBufferReferences.get()==0)
+                    releaseRequestBuffer();
+                else
+                {
+                    LOG.warn("{} lingering content references?!?!",this);
+                    _requestBuffer=null; // Not returned to pool!
+                    _contentBufferReferences.set(0);
+                }
                 return;
             }
         }
@@ -365,7 +393,7 @@
             {
                 if (LOG.isDebugEnabled())
                     LOG.debug("unconsumed async input {}", this);
-                _channel.abort();
+                _channel.abort(new IOException("unconsumed input"));
             }
             else
             {
@@ -373,12 +401,12 @@
                     LOG.debug("unconsumed input {}", this);
                 // Complete reading the request
                 if (!_channel.getRequest().getHttpInput().consumeAll())
-                    _channel.abort();
+                    _channel.abort(new IOException("unconsumed input"));
             }
         }
 
         // Reset the channel, parsers and generator
-        _channel.reset();
+        _channel.recycle();
         if (_generator.isPersistent() && !_parser.isClosed())
             _parser.reset();
         else
@@ -386,7 +414,6 @@
 
         // Not in a race here with onFillable, because it has given up control before calling handle.
         // in a slight race with #completed, but not sure what to do with that anyway.
-        releaseRequestBuffer();
         if (_chunk!=null)
             _bufferPool.release(_chunk);
         _chunk=null;
@@ -460,28 +487,36 @@
     }
 
     @Override
-    public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
+    public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
     {
-        // If we are still expecting a 100 continues when we commit
-        if (info!=null && _channel.isExpecting100Continue())
-            // then we can't be persistent
-            _generator.setPersistent(false);
+        if (info == null)
+        {
+            if (!lastContent && BufferUtil.isEmpty(content))
+            {
+                callback.succeeded();
+                return;
+            }
+        }
+        else
+        {
+            // If we are still expecting a 100 continues when we commit
+            if (_channel.isExpecting100Continue())
+                // then we can't be persistent
+                _generator.setPersistent(false);
+        }
 
-        if(_sendCallback.reset(info,content,lastContent,callback))
+        if(_sendCallback.reset(info,head,content,lastContent,callback))
             _sendCallback.iterate();
     }
 
-    @Override
-    public void send(ByteBuffer content, boolean lastContent, Callback callback)
+
+    HttpInput.Content newContent(ByteBuffer c)
     {
-        if (!lastContent && BufferUtil.isEmpty(content))
-            callback.succeeded();
-        else if (_sendCallback.reset(null,content,lastContent,callback))
-            _sendCallback.iterate();
+        return new Content(c);
     }
 
     @Override
-    public void abort()
+    public void abort(Throwable failure)
     {
         // Do a direct close of the output, as this may indicate to a client that the
         // response is bad either with RST or by abnormal completion of chunked response.
@@ -489,6 +524,33 @@
     }
 
     @Override
+    public boolean isPushSupported()
+    {
+        return false;
+    }
+
+    @Override
+    public void push(org.eclipse.jetty.http.MetaData.Request request)
+    {
+        LOG.debug("ignore push in {}",this);
+    }
+
+    public void asyncReadFillInterested()
+    {
+        getEndPoint().fillInterested(_asyncReadCallback);
+    }
+
+    public void blockingReadFillInterested()
+    {
+        getEndPoint().fillInterested(_blockingReadCallback);
+    }
+
+    public void blockingReadException(Throwable e)
+    {
+        _blockingReadCallback.failed(e);
+    }
+
+    @Override
     public String toString()
     {
         return String.format("%s[p=%s,g=%s,c=%s]",
@@ -498,120 +560,74 @@
                 _channel);
     }
 
-    protected class HttpChannelOverHttp extends HttpChannel<ByteBuffer>
+    private class Content extends HttpInput.Content
     {
-        public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input)
+        public Content(ByteBuffer content)
         {
-            super(connector,config,endPoint,transport,input);
+            super(content);
+            _contentBufferReferences.incrementAndGet();
         }
 
         @Override
-        public void earlyEOF()
+        public void succeeded()
         {
-            // If we have no request yet, just close
-            if (getRequest().getMethod()==null)
-                close();
-            else
-                super.earlyEOF();
+            if (_contentBufferReferences.decrementAndGet()==0)
+                releaseRequestBuffer();
         }
 
         @Override
-        public boolean content(ByteBuffer item)
+        public void failed(Throwable x)
         {
-            super.content(item);
+            succeeded();
+        }
+    }
+
+    private class BlockingReadCallback implements Callback
+    {
+        @Override
+        public void succeeded()
+        {
+            _input.unblock();
+        }
+
+        @Override
+        public void failed(Throwable x)
+        {
+            _input.failed(x);
+        }
+
+        @Override
+        public boolean isNonBlocking()
+        {
+            // This callback does not block, rather it wakes up the
+            // thread that is blocked waiting on the read.
             return true;
         }
+    }
 
+    private class AsyncReadCallback implements Callback
+    {
         @Override
-        public void badMessage(int status, String reason)
+        public void succeeded()
         {
-            _generator.setPersistent(false);
-            super.badMessage(status,reason);
+            if (fillAndParseForContent())
+                _channel.handle();
+            else if (!_input.isFinished())
+                asyncReadFillInterested();
         }
 
         @Override
-        public boolean headerComplete()
+        public void failed(Throwable x)
         {
-            boolean persistent;
-            HttpVersion version = getHttpVersion();
-
-            switch (version)
-            {
-                case HTTP_0_9:
-                {
-                    persistent = false;
-                    break;
-                }
-                case HTTP_1_0:
-                {
-                    persistent = getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
-                    if (!persistent)
-                        persistent = HttpMethod.CONNECT.is(getRequest().getMethod());
-                    if (persistent)
-                        getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
-                    break;
-                }
-                case HTTP_1_1:
-                {
-                    persistent = !getRequest().getHttpFields().contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
-                    if (!persistent)
-                        persistent = HttpMethod.CONNECT.is(getRequest().getMethod());
-                    if (!persistent)
-                        getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
-                    break;
-                }
-                case HTTP_2:
-                {
-                    persistent=false;
-                    badMessage(400,null);
-                    return true;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-
-            if (!persistent)
-                _generator.setPersistent(false);
-
-            if (!super.headerComplete())
-                return false;
-
-            // Should we delay dispatch until we have some content?
-            // We should not delay if there is no content expect or client is expecting 100 or the response is already committed or the request buffer already has something in it to parse
-            if (getHttpConfiguration().isDelayDispatchUntilContent() && _parser.getContentLength() > 0 &&
-                    !isExpecting100Continue() && !isCommitted() && BufferUtil.isEmpty(_requestBuffer))
-                return false;
-
-            return true;
-        }
-
-        @Override
-        protected void handleException(Throwable x)
-        {
-            _generator.setPersistent(false);
-            super.handleException(x);
-        }
-
-        @Override
-        public void abort()
-        {
-            super.abort();
-            _generator.setPersistent(false);
-        }
-
-        @Override
-        public boolean messageComplete()
-        {
-            super.messageComplete();
-            return false;
+            if (_input.failed(x))
+                _channel.handle();
         }
     }
 
     private class SendCallback extends IteratingCallback
     {
-        private ResponseInfo _info;
+        private MetaData.Response _info;
+        private boolean _head;
         private ByteBuffer _content;
         private boolean _lastContent;
         private Callback _callback;
@@ -623,11 +639,18 @@
             super(true);
         }
 
-        private boolean reset(ResponseInfo info, ByteBuffer content, boolean last, Callback callback)
+        @Override
+        public boolean isNonBlocking()
+        {
+            return _callback.isNonBlocking();
+        }
+
+        private boolean reset(MetaData.Response info, boolean head, ByteBuffer content, boolean last, Callback callback)
         {
             if (reset())
             {
                 _info = info;
+                _head = head;
                 _content = content;
                 _lastContent = last;
                 _callback = callback;
@@ -652,7 +675,7 @@
             ByteBuffer chunk = _chunk;
             while (true)
             {
-                HttpGenerator.Result result = _generator.generateResponse(_info, _header, chunk, _content, _lastContent);
+                HttpGenerator.Result result = _generator.generateResponse(_info, _head, _header, chunk, _content, _lastContent);
                 if (LOG.isDebugEnabled())
                     LOG.debug("{} generate: {} ({},{},{})@{}",
                         this,
@@ -667,6 +690,7 @@
                     case NEED_HEADER:
                     {
                         _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT);
+
                         continue;
                     }
                     case NEED_CHUNK:
@@ -677,7 +701,7 @@
                     case FLUSH:
                     {
                         // Don't write the chunk or the content if this is a HEAD response, or any other type of response that should have no content
-                        if (_channel.getRequest().isHead() || _generator.isNoContent())
+                        if (_head || _generator.isNoContent())
                         {
                             BufferUtil.clear(chunk);
                             BufferUtil.clear(_content);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java
index 1f402a8..ae06208 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java
@@ -16,19 +16,15 @@
 //  ========================================================================
 //
 
-
 package org.eclipse.jetty.server;
 
-
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.annotation.Name;
 
-
-/* ------------------------------------------------------------ */
 /** A Connection Factory for HTTP Connections.
- * <p>Accepts connections either directly or via SSL and/or NPN chained connection factories.  The accepted 
+ * <p>Accepts connections either directly or via SSL and/or ALPN chained connection factories.  The accepted
  * {@link HttpConnection}s are configured by a {@link HttpConfiguration} instance that is either created by
  * default or passed in to the constructor.
  */
@@ -39,13 +35,14 @@
     public HttpConnectionFactory()
     {
         this(new HttpConfiguration());
-        setInputBufferSize(16384);
     }
 
     public HttpConnectionFactory(@Name("config") HttpConfiguration config)
     {
-        super(HttpVersion.HTTP_1_1.toString());
+        super(HttpVersion.HTTP_1_1.asString());
         _config=config;
+        if (config==null)
+            throw new IllegalArgumentException("Null HttpConfiguration");
         addBean(_config);
     }
 
@@ -60,5 +57,4 @@
     {
         return configure(new HttpConnection(_config, connector, endPoint), connector, endPoint);
     }
-
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
index 963d66b..1b6c4a8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java
@@ -19,284 +19,442 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
 import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.TimeoutException;
 
 import javax.servlet.ReadListener;
 import javax.servlet.ServletInputStream;
 
 import org.eclipse.jetty.io.EofException;
 import org.eclipse.jetty.io.RuntimeIOException;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
 /**
  * {@link HttpInput} provides an implementation of {@link ServletInputStream} for {@link HttpChannel}.
- * <p/>
+ * <p>
  * Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class
  * maintains two states: the content state that tells whether there is content to consume and the EOF
  * state that tells whether an EOF has arrived.
  * Only once the content has been consumed the content state is moved to the EOF state.
  */
-public abstract class HttpInput<T> extends ServletInputStream implements Runnable
+public class HttpInput extends ServletInputStream implements Runnable
 {
     private final static Logger LOG = Log.getLogger(HttpInput.class);
+    private final static Content EOF_CONTENT = new EofContent("EOF");
+    private final static Content EARLY_EOF_CONTENT = new EofContent("EARLY_EOF");
 
     private final byte[] _oneByteBuffer = new byte[1];
-    private final Object _lock;
-    private HttpChannelState _channelState;
+    private final Queue<Content> _inputQ = new ArrayDeque<>();
+    private final HttpChannelState _channelState;
     private ReadListener _listener;
-    private Throwable _onError;
-    private boolean _notReady;
-    private State _contentState = STREAM;
-    private State _eofState;
-    private long _contentRead;
+    private State _state = STREAM;
+    private long _contentConsumed;
+    private long _blockingTimeoutAt = -1;
 
-    protected HttpInput()
+    public HttpInput(HttpChannelState state)
     {
-        this(null);
+        _channelState=state;
+        if (_channelState.getHttpChannel().getHttpConfiguration().getBlockingTimeout()>0)
+            _blockingTimeoutAt=0;
     }
 
-    protected HttpInput(Object lock)
+    protected HttpChannelState getHttpChannelState()
     {
-        _lock = lock == null ? this : lock;
-    }
-
-    public void init(HttpChannelState state)
-    {
-        synchronized (lock())
-        {
-            _channelState = state;
-        }
-    }
-
-    public final Object lock()
-    {
-        return _lock;
+        return _channelState;
     }
 
     public void recycle()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
+            Content item = _inputQ.poll();
+            while (item != null)
+            {
+                item.failed(null);
+                item = _inputQ.poll();
+            }
             _listener = null;
-            _onError = null;
-            _notReady = false;
-            _contentState = STREAM;
-            _eofState = null;
-            _contentRead = 0;
+            _state = STREAM;
+            _contentConsumed = 0;
         }
     }
 
     @Override
     public int available()
     {
-        try
+        int available=0;
+        boolean woken=false;
+        synchronized (_inputQ)
         {
-            synchronized (lock())
+            Content content = _inputQ.peek();
+            if (content==null)
             {
-                T item = getNextContent();
-                return item == null ? 0 : remaining(item);
+                try
+                {
+                    produceContent();
+                }
+                catch(IOException e)
+                {
+                    woken=failed(e);
+                }
+                content = _inputQ.peek();
             }
+
+            if (content!=null)
+                available= remaining(content);
         }
-        catch (IOException e)
-        {
-            throw new RuntimeIOException(e);
-        }
+
+        if (woken)
+            wake();
+        return available;
     }
 
+    private void wake()
+    {
+        _channelState.getHttpChannel().getConnector().getExecutor().execute(_channelState.getHttpChannel());
+    }
+
+
     @Override
     public int read() throws IOException
     {
         int read = read(_oneByteBuffer, 0, 1);
+        if (read==0)
+            throw new IllegalStateException("unready read=0");
         return read < 0 ? -1 : _oneByteBuffer[0] & 0xFF;
     }
 
     @Override
     public int read(byte[] b, int off, int len) throws IOException
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            T item = getNextContent();
-            if (item == null)
-            {
-                _contentState.waitForContent(this);
-                item = getNextContent();
-                if (item == null)
-                    return _contentState.noContent();
-            }
-            int l = get(item, b, off, len);
-            _contentRead += l;
-            return l;
-        }
-    }
+            if (_blockingTimeoutAt>=0 && !isAsync())
+                _blockingTimeoutAt=System.currentTimeMillis()+getHttpChannelState().getHttpChannel().getHttpConfiguration().getBlockingTimeout();
 
-    /**
-     * A convenience method to call nextContent and to check the return value, which if null then the
-     * a check is made for EOF and the state changed accordingly.
-     *
-     * @return Content or null if none available.
-     * @throws IOException
-     * @see #nextContent()
-     */
-    protected T getNextContent() throws IOException
-    {
-        T content = nextContent();
-        if (content == null)
-        {
-            synchronized (lock())
+            while(true)
             {
-                if (_eofState != null)
+                Content item = nextContent();
+                if (item!=null)
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("{} eof {}", this, _eofState);
-                    _contentState = _eofState;
+                        LOG.debug("{} read {} from {}",this,len,item);
+                    int l = get(item, b, off, len);
+
+                    consumeNonContent();
+
+                    return l;
                 }
+
+                if (!_state.blockForContent(this))
+                    return _state.noContent();
             }
         }
-        return content;
     }
 
     /**
-     * Access the next content to be consumed from.   Returning the next item does not consume it
-     * and it may be returned multiple times until it is consumed.
-     * <p/>
-     * Calls to {@link #get(Object, byte[], int, int)}
-     * or {@link #consume(Object, int)} are required to consume data from the content.
+     * Called when derived implementations should attempt to
+     * produce more Content and add it via {@link #addContent(Content)}.
+     * For protocols that are constantly producing (eg HTTP2) this can
+     * be left as a noop;
+     * @throws IOException if unable to produce content
+     */
+    protected void produceContent() throws IOException
+    {
+    }
+
+    /**
+     * Get the next content from the inputQ, calling {@link #produceContent()}
+     * if need be.  EOF is processed and state changed.
      *
      * @return the content or null if none available.
      * @throws IOException if retrieving the content fails
      */
-    protected abstract T nextContent() throws IOException;
+    protected Content nextContent() throws IOException
+    {
+        Content content = pollContent();
+        if (content==null && !isFinished())
+        {
+            produceContent();
+            content = pollContent();
+        }
+        return content;
+    }
+
+    /** Poll the inputQ for Content.
+     * Consumed buffers and {@link PoisonPillContent}s are removed and
+     * EOF state updated if need be.
+     * @return Content or null
+     */
+    protected Content pollContent()
+    {
+        // Items are removed only when they are fully consumed.
+        Content content = _inputQ.peek();
+        // Skip consumed items at the head of the queue.
+        while (content != null && remaining(content) == 0)
+        {
+            _inputQ.poll();
+            content.succeeded();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} consumed {}", this, content);
+
+            if (content==EOF_CONTENT)
+            {
+                if (_listener==null)
+                    _state=EOF;
+                else
+                {
+                    _state=AEOF;
+                    boolean woken = _channelState.onReadReady(); // force callback?
+                    if (woken)
+                        wake();
+                }
+            }
+            else if (content==EARLY_EOF_CONTENT)
+                _state=EARLY_EOF;
+
+            content = _inputQ.peek();
+        }
+
+        return content;
+    }
+
+    /**
+     */
+    protected void consumeNonContent()
+    {
+        // Items are removed only when they are fully consumed.
+        Content content = _inputQ.peek();
+        // Skip consumed items at the head of the queue.
+        while (content != null && remaining(content) == 0)
+        {
+            // Defer EOF until read
+            if (content instanceof EofContent)
+                break;
+
+            // Consume all other empty content
+            _inputQ.poll();
+            content.succeeded();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} consumed {}", this, content);
+            content = _inputQ.peek();
+        }
+    }
+
+    /**
+     * Get the next readable from the inputQ, calling {@link #produceContent()}
+     * if need be. EOF is NOT processed and state is not changed.
+     *
+     * @return the content or EOF or null if none available.
+     * @throws IOException if retrieving the content fails
+     */
+    protected Content nextReadable() throws IOException
+    {
+        Content content = pollReadable();
+        if (content==null && !isFinished())
+        {
+            produceContent();
+            content = pollReadable();
+        }
+        return content;
+    }
+
+    /** Poll the inputQ for Content or EOF.
+     * Consumed buffers and non EOF {@link PoisonPillContent}s are removed.
+     * EOF state is not updated.
+     * @return Content, EOF or null
+     */
+    protected Content pollReadable()
+    {
+        // Items are removed only when they are fully consumed.
+        Content content = _inputQ.peek();
+
+        // Skip consumed items at the head of the queue except EOF
+        while (content != null)
+        {
+            if (content==EOF_CONTENT || content==EARLY_EOF_CONTENT || remaining(content)>0)
+                return content;
+
+            _inputQ.poll();
+            content.succeeded();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} consumed {}", this, content);
+            content = _inputQ.peek();
+        }
+
+        return null;
+    }
 
     /**
      * @param item the content
      * @return how many bytes remain in the given content
      */
-    protected abstract int remaining(T item);
+    protected int remaining(Content item)
+    {
+        return item.remaining();
+    }
 
     /**
      * Copies the given content into the given byte buffer.
      *
-     * @param item   the content to copy from
+     * @param content   the content to copy from
      * @param buffer the buffer to copy into
      * @param offset the buffer offset to start copying from
      * @param length the space available in the buffer
      * @return the number of bytes actually copied
      */
-    protected abstract int get(T item, byte[] buffer, int offset, int length);
+    protected int get(Content content, byte[] buffer, int offset, int length)
+    {
+        int l = Math.min(content.remaining(), length);
+        content.getContent().get(buffer, offset, l);
+        _contentConsumed+=l;
+        return l;
+    }
 
     /**
      * Consumes the given content.
+     * Calls the content succeeded if all content consumed.
      *
-     * @param item   the content to consume
+     * @param content   the content to consume
      * @param length the number of bytes to consume
      */
-    protected abstract void consume(T item, int length);
+    protected void skip(Content content, int length)
+    {
+        int l = Math.min(content.remaining(), length);
+        ByteBuffer buffer = content.getContent();
+        buffer.position(buffer.position()+l);
+        _contentConsumed+=l;
+        if (l>0 && !content.hasContent())
+            pollContent(); // hungry succeed
+
+    }
 
     /**
      * Blocks until some content or some end-of-file event arrives.
      *
      * @throws IOException if the wait is interrupted
      */
-    protected abstract void blockForContent() throws IOException;
+    protected void blockForContent() throws IOException
+    {
+        try
+        {
+            long timeout=0;
+            if (_blockingTimeoutAt>=0)
+            {
+                timeout=_blockingTimeoutAt-System.currentTimeMillis();
+                if (timeout<=0)
+                    throw new TimeoutException();
+            }
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} blocking for content timeout={} ...", this,timeout);
+            if (timeout>0)
+                _inputQ.wait(timeout);
+            else
+                _inputQ.wait();
+
+            if (_blockingTimeoutAt>0 && System.currentTimeMillis()>=_blockingTimeoutAt)
+                throw new TimeoutException();
+        }
+        catch (Throwable e)
+        {
+            throw (IOException)new InterruptedIOException().initCause(e);
+        }
+    }
 
     /**
      * Adds some content to this input stream.
      *
      * @param item the content to add
+     * @return true if content channel woken for read
      */
-    public abstract void content(T item);
-
-    protected boolean onAsyncRead()
+    public boolean addContent(Content item)
     {
-        synchronized (lock())
+        boolean woken=false;
+        synchronized (_inputQ)
         {
-            if (_listener == null)
-                return false;
+            _inputQ.offer(item);
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} addContent {}", this, item);
+
+            if (_listener==null)
+                _inputQ.notify();
+            else
+                woken=_channelState.onReadPossible();
         }
-        _channelState.onReadPossible();
-        return true;
+
+        return woken;
     }
 
-    public long getContentRead()
+    public boolean hasContent()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            return _contentRead;
+            return _inputQ.size()>0;
+        }
+    }
+
+    public void unblock()
+    {
+        synchronized (_inputQ)
+        {
+            _inputQ.notify();
+        }
+    }
+
+    public long getContentConsumed()
+    {
+        synchronized (_inputQ)
+        {
+            return _contentConsumed;
         }
     }
 
     /**
      * This method should be called to signal that an EOF has been
      * detected before all the expected content arrived.
-     * <p/>
+     * <p>
      * Typically this will result in an EOFException being thrown
      * from a subsequent read rather than a -1 return.
+     * @return true if content channel woken for read
      */
-    public void earlyEOF()
+    public boolean earlyEOF()
     {
-        synchronized (lock())
-        {
-            if (!isEOF())
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("{} early EOF", this);
-                _eofState = EARLY_EOF;
-                if (_listener == null)
-                    return;
-            }
-        }
-        _channelState.onReadPossible();
-    }
-
-
-    public boolean isEarlyEOF()
-    {
-        synchronized (lock())
-        {
-            return _contentState==EARLY_EOF;
-        }
+        return addContent(EARLY_EOF_CONTENT);
     }
 
     /**
      * This method should be called to signal that all the expected
      * content arrived.
+     * @return true if content channel woken for read
      */
-    public void messageComplete()
+    public boolean eof()
     {
-        synchronized (lock())
-        {
-            if (!isEOF())
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("{} EOF", this);
-                _eofState = EOF;
-                if (_listener == null)
-                    return;
-            }
-        }
-        _channelState.onReadPossible();
+       return addContent(EOF_CONTENT);
     }
 
     public boolean consumeAll()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            // Don't bother reading if we already know there was an error.
-            if (_onError != null)
-                return false;
-
             try
             {
                 while (!isFinished())
                 {
-                    T item = getNextContent();
+                    Content item = nextContent();
                     if (item == null)
-                        _contentState.waitForContent(this);
-                    else
-                        consume(item, remaining(item));
+                        break; // Let's not bother blocking
+
+                    skip(item, remaining(item));
                 }
-                return true;
+                return isFinished() && !isError();
             }
             catch (IOException e)
             {
@@ -306,31 +464,28 @@
         }
     }
 
-    public boolean isAsync()
+    public boolean isError()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            return _contentState==ASYNC;
+            return _state instanceof ErrorState;
         }
     }
 
-    /**
-     * @return whether an EOF has been detected, even though there may be content to consume.
-     */
-    public boolean isEOF()
+    public boolean isAsync()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            return _eofState != null && _eofState.isEOF();
+            return _state==ASYNC;
         }
     }
 
     @Override
     public boolean isFinished()
     {
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            return _contentState.isEOF();
+            return _state instanceof EOFState;
         }
     }
 
@@ -338,155 +493,272 @@
     @Override
     public boolean isReady()
     {
-        boolean finished;
-        synchronized (lock())
+        try
         {
-            if (_contentState.isEOF())
-                return true;
-            if (_listener == null )
-                return true;
-            if (available() > 0)
-                return true;
-            if (_notReady)
-                return false;
-            _notReady = true;
-            finished = isFinished();
-        }
-        if (finished)
-            _channelState.onReadPossible();
-        else
-            unready();
-        return false;
-    }
+            synchronized (_inputQ)
+            {
+                if (_listener == null )
+                    return true;
+                if (_state instanceof EOFState)
+                    return true;
+                if (nextReadable()!=null)
+                    return true;
 
-    protected void unready()
-    {
+                _channelState.onReadUnready();
+            }
+            return false;
+        }
+        catch(IOException e)
+        {
+            LOG.ignore(e);
+            return true;
+        }
     }
 
     @Override
     public void setReadListener(ReadListener readListener)
     {
+        readListener = Objects.requireNonNull(readListener);
+        boolean woken=false;
         try
         {
-            readListener = Objects.requireNonNull(readListener);
-            boolean content;
-            synchronized (lock())
+            synchronized (_inputQ)
             {
-                if (_contentState != STREAM)
-                    throw new IllegalStateException("state=" + _contentState);
-                _contentState = ASYNC;
+                if (_listener != null)
+                    throw new IllegalStateException("ReadListener already set");
+                if (_state != STREAM)
+                    throw new IllegalStateException("State "+STREAM+" != " + _state);
+
+                _state = ASYNC;
                 _listener = readListener;
-                _notReady = true;
+                boolean content=nextContent()!=null;
 
-                content = getNextContent()!=null || isEOF();
-
+                if (content)
+                    woken = _channelState.onReadReady();
+                else
+                    _channelState.onReadUnready();
             }
-            if (content)
-                _channelState.onReadPossible();
-            else
-                unready();
         }
         catch(IOException e)
         {
             throw new RuntimeIOException(e);
         }
+
+        if (woken)
+            wake();
     }
 
-    public void failed(Throwable x)
+    public boolean failed(Throwable x)
     {
-        synchronized (lock())
+        boolean woken=false;
+        synchronized (_inputQ)
         {
-            if (_onError != null)
+            if (_state instanceof ErrorState)
                 LOG.warn(x);
             else
-                _onError = x;
+                _state = new ErrorState(x);
+
+            if (_listener==null)
+                _inputQ.notify();
+            else
+                woken=_channelState.onReadPossible();
         }
+
+        return woken;
     }
 
+    /* ------------------------------------------------------------ */
+    /*
+     * <p>
+     * While this class is-a Runnable, it should never be dispatched in it's own thread. It is a
+     * runnable only so that the calling thread can use {@link ContextHandler#handle(Runnable)}
+     * to setup classloaders etc.
+     * </p>
+     */
     @Override
     public void run()
     {
         final Throwable error;
         final ReadListener listener;
-        boolean available = false;
-        final boolean eof;
+        boolean aeof=false;
 
-        synchronized (lock())
+        synchronized (_inputQ)
         {
-            if (!_notReady || _listener == null)
+            if (_state==EOF)
                 return;
 
-            error = _onError;
+            if (_state==AEOF)
+            {
+                _state=EOF;
+                aeof=true;
+            }
+
             listener = _listener;
-
-            try
-            {
-                T item = getNextContent();
-                available = item != null && remaining(item) > 0;
-            }
-            catch (Exception e)
-            {
-                failed(e);
-            }
-
-            eof = !available && isFinished();
-            _notReady = !available && !eof;
+            error = _state instanceof ErrorState?((ErrorState)_state).getError():null;
         }
 
         try
         {
-            if (error != null)
+            if (error!=null)
+            {
+                _channelState.getHttpChannel().getResponse().getHttpFields().add(HttpConnection.CONNECTION_CLOSE);
                 listener.onError(error);
-            else if (available)
-                listener.onDataAvailable();
-            else if (eof)
+            }
+            else if (aeof)
+            {
                 listener.onAllDataRead();
+            }
             else
-                unready();
+            {
+                listener.onDataAvailable();
+            }
         }
         catch (Throwable e)
         {
             LOG.warn(e.toString());
             LOG.debug(e);
-            listener.onError(e);
+            try
+            {
+                if (aeof || error==null)
+                {
+                    _channelState.getHttpChannel().getResponse().getHttpFields().add(HttpConnection.CONNECTION_CLOSE);
+                    listener.onError(e);
+                }
+            }
+            catch (Throwable e2)
+            {
+                LOG.warn(e2.toString());
+                LOG.debug(e2);
+                throw new RuntimeIOException(e2);
+            }
         }
     }
 
     @Override
     public String toString()
     {
-        return String.format("%s@%x[r=%d,s=%s,e=%s,f=%s]",
+        return String.format("%s@%x[c=%d,s=%s]",
                 getClass().getSimpleName(),
                 hashCode(),
-                _contentRead,
-                _contentState,
-                _eofState,
-                _onError);
+                _contentConsumed,
+                _state);
     }
 
+    public static class PoisonPillContent extends Content
+    {
+        private final String _name;
+        public PoisonPillContent(String name)
+        {
+            super(BufferUtil.EMPTY_BUFFER);
+            _name=name;
+        }
+
+        @Override
+        public String toString()
+        {
+            return _name;
+        }
+    }
+
+    public static class EofContent extends PoisonPillContent
+    {
+        EofContent(String name)
+        {
+            super(name);
+        }
+    }
+
+    public static class Content implements Callback
+    {
+        private final ByteBuffer _content;
+
+        public Content(ByteBuffer content)
+        {
+            _content=content;
+        }
+
+        @Override
+        public boolean isNonBlocking()
+        {
+            return true;
+        }
+
+
+        public ByteBuffer getContent()
+        {
+            return _content;
+        }
+
+        public boolean hasContent()
+        {
+            return _content.hasRemaining();
+        }
+
+        public int remaining()
+        {
+            return _content.remaining();
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("Content@%x{%s}",hashCode(),BufferUtil.toDetailString(_content));
+        }
+    }
+
+
     protected static abstract class State
     {
-        public void waitForContent(HttpInput<?> in) throws IOException
+        public boolean blockForContent(HttpInput in) throws IOException
         {
+            return false;
         }
 
         public int noContent() throws IOException
         {
             return -1;
         }
+    }
 
-        public boolean isEOF()
+    protected static class EOFState extends State
+    {
+    }
+
+    protected class ErrorState extends EOFState
+    {
+        final Throwable _error;
+        ErrorState(Throwable error)
         {
-            return false;
+            _error=error;
+        }
+
+        public Throwable getError()
+        {
+            return _error;
+        }
+
+        @Override
+        public int noContent() throws IOException
+        {
+            if (_error instanceof IOException)
+                throw (IOException)_error;
+            throw new IOException(_error);
+        }
+
+        @Override
+        public String toString()
+        {
+            return "ERROR:"+_error;
         }
     }
 
     protected static final State STREAM = new State()
     {
         @Override
-        public void waitForContent(HttpInput<?> input) throws IOException
+        public boolean blockForContent(HttpInput input) throws IOException
         {
             input.blockForContent();
+            return true;
         }
 
         @Override
@@ -511,7 +783,7 @@
         }
     };
 
-    protected static final State EARLY_EOF = new State()
+    protected static final State EARLY_EOF = new EOFState()
     {
         @Override
         public int noContent() throws IOException
@@ -520,30 +792,28 @@
         }
 
         @Override
-        public boolean isEOF()
-        {
-            return true;
-        }
-
-        @Override
         public String toString()
         {
             return "EARLY_EOF";
         }
     };
 
-    protected static final State EOF = new State()
+    protected static final State EOF = new EOFState()
     {
         @Override
-        public boolean isEOF()
-        {
-            return true;
-        }
-
-        @Override
         public String toString()
         {
             return "EOF";
         }
     };
+
+    protected static final State AEOF = new EOFState()
+    {
+        @Override
+        public String toString()
+        {
+            return "AEOF";
+        }
+    };
+
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java
index f91becc..de3afa4 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInputOverHTTP.java
@@ -19,128 +19,31 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.SharedBlockingCallback;
-import org.eclipse.jetty.util.SharedBlockingCallback.Blocker;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class HttpInputOverHTTP extends HttpInput<ByteBuffer> implements Callback
+public class HttpInputOverHTTP extends HttpInput
 {
-    private static final Logger LOG = Log.getLogger(HttpInputOverHTTP.class);
-    private final SharedBlockingCallback _readBlocker = new SharedBlockingCallback();
-    private final HttpConnection _httpConnection;
-    private ByteBuffer _content;
-
-    /**
-     * @param httpConnection
-     */
-    public HttpInputOverHTTP(HttpConnection httpConnection)
+    public HttpInputOverHTTP(HttpChannelState state)
     {
-        _httpConnection = httpConnection;
+        super(state);
     }
 
     @Override
-    public void recycle()
+    protected void produceContent() throws IOException
     {
-        synchronized (lock())
-        {
-            super.recycle();
-            _content=null;
-        }
+        ((HttpConnection)getHttpChannelState().getHttpChannel().getEndPoint().getConnection()).fillAndParseForContent();
     }
 
     @Override
     protected void blockForContent() throws IOException
     {
-        while(true)
+        ((HttpConnection)getHttpChannelState().getHttpChannel().getEndPoint().getConnection()).blockingReadFillInterested();
+        try
         {
-            try (Blocker blocker=_readBlocker.acquire())
-            {            
-                _httpConnection.fillInterested(blocker);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("{} block readable on {}",this,blocker);
-                blocker.block();
-            }
-
-            Object content=getNextContent();
-            if (content!=null || isFinished())
-                break;
+            super.blockForContent();
         }
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s@%x",getClass().getSimpleName(),hashCode());
-    }
-
-    @Override
-    protected ByteBuffer nextContent() throws IOException
-    {
-        // If we have some content available, return it
-        if (BufferUtil.hasContent(_content))
-            return _content;
-
-        // No - then we are going to need to parse some more content
-        _content=null;
-        _httpConnection.parseContent();
-        
-        // If we have some content available, return it
-        if (BufferUtil.hasContent(_content))
-            return _content;
-
-        return null;
-
-    }
-
-    @Override
-    protected int remaining(ByteBuffer item)
-    {
-        return item.remaining();
-    }
-
-    @Override
-    protected int get(ByteBuffer item, byte[] buffer, int offset, int length)
-    {
-        int l = Math.min(item.remaining(), length);
-        item.get(buffer, offset, l);
-        return l;
-    }
-
-    @Override
-    protected void consume(ByteBuffer item, int length)
-    {
-        item.position(item.position()+length);
-    }
-
-    @Override
-    public void content(ByteBuffer item)
-    {
-        if (BufferUtil.hasContent(_content))
-            throw new IllegalStateException();
-        _content=item;
-    }
-
-    @Override
-    protected void unready()
-    {
-        _httpConnection.fillInterested(this);
-    }
-
-    @Override
-    public void succeeded()
-    {
-        _httpConnection.getHttpChannel().getState().onReadPossible();
-    }
-
-    @Override
-    public void failed(Throwable x)
-    {
-        super.failed(x);
-        _httpConnection.getHttpChannel().getState().onReadPossible();
+        catch(Throwable e)
+        {
+            ((HttpConnection)getHttpChannelState().getHttpChannel().getEndPoint().getConnection()).blockingReadException(e);
+        }
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java
index 47346cb..ae64acf 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java
@@ -18,12 +18,14 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritePendingException;
 import java.util.concurrent.atomic.AtomicReference;
+
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.ServletRequest;
@@ -53,40 +55,57 @@
  */
 public class HttpOutput extends ServletOutputStream implements Runnable
 {
-    private static Logger LOG = Log.getLogger(HttpOutput.class);
-    private final HttpChannel<?> _channel;
-    private final SharedBlockingCallback _writeblock=new SharedBlockingCallback()
+    public interface Interceptor
     {
-        @Override
-        protected long getIdleTimeout()
-        {
-            return _channel.getIdleTimeout();
-        }
-    };
+        void write(ByteBuffer content, boolean complete, Callback callback);
+        Interceptor getNextInterceptor();
+        boolean isOptimizedForDirectBuffers();
+    }
+    
+    private static Logger LOG = Log.getLogger(HttpOutput.class);
+
+    private final HttpChannel _channel;
+    private final SharedBlockingCallback _writeBlock;
+    private Interceptor _interceptor;
+    
+    /** Bytes written via the write API (excludes bytes written via sendContent). Used to autocommit once content length is written. */
     private long _written;
+    
     private ByteBuffer _aggregate;
     private int _bufferSize;
     private int _commitSize;
     private WriteListener _writeListener;
     private volatile Throwable _onError;
-
     /*
     ACTION             OPEN       ASYNC      READY      PENDING       UNREADY       CLOSED
-    -----------------------------------------------------------------------------------------------------
+    -------------------------------------------------------------------------------------------
     setWriteListener() READY->owp ise        ise        ise           ise           ise
     write()            OPEN       ise        PENDING    wpe           wpe           eof
     flush()            OPEN       ise        PENDING    wpe           wpe           eof
     close()            CLOSED     CLOSED     CLOSED     CLOSED        wpe           CLOSED
     isReady()          OPEN:true  READY:true READY:true UNREADY:false UNREADY:false CLOSED:true
     write completed    -          -          -          ASYNC         READY->owp    -
-    
     */
-    enum OutputState { OPEN, ASYNC, READY, PENDING, UNREADY, ERROR, CLOSED }
+    private enum OutputState { OPEN, ASYNC, READY, PENDING, UNREADY, ERROR, CLOSED }
     private final AtomicReference<OutputState> _state=new AtomicReference<>(OutputState.OPEN);
 
-    public HttpOutput(HttpChannel<?> channel)
+    public HttpOutput(HttpChannel channel)
     {
         _channel = channel;
+        _interceptor = channel;
+        _writeBlock = new SharedBlockingCallback()
+        {
+            @Override
+            protected long getIdleTimeout()
+            {
+                long bto = getHttpChannel().getHttpConfiguration().getBlockingTimeout();
+                if (bto>0)
+                    return bto;
+                if (bto<0)
+                    return -1;
+                return _channel.getIdleTimeout();
+            }
+        };
         HttpConfiguration config = channel.getHttpConfiguration();
         _bufferSize = config.getOutputBufferSize();
         _commitSize = config.getOutputAggregationSize();
@@ -97,10 +116,20 @@
         }
     }
     
-    public HttpChannel<?> getHttpChannel()
+    public HttpChannel getHttpChannel()
     {
         return _channel;
     }
+
+    public Interceptor getInterceptor()
+    {
+        return _interceptor;
+    }
+
+    public void setInterceptor(Interceptor filter)
+    {
+        _interceptor=filter;
+    }
     
     public boolean isWritten()
     {
@@ -112,12 +141,6 @@
         return _written;
     }
 
-    public void reset()
-    {
-        _written = 0;
-        reopen();
-    }
-
     public void reopen()
     {
         _state.set(OutputState.OPEN);
@@ -130,89 +153,121 @@
 
     protected Blocker acquireWriteBlockingCallback() throws IOException
     {
-        return _writeblock.acquire();
+        return _writeBlock.acquire();
     }
     
-    protected void write(ByteBuffer content, boolean complete) throws IOException
+    private void write(ByteBuffer content, boolean complete) throws IOException
     {
-        try (Blocker blocker=_writeblock.acquire())
+        try (Blocker blocker = _writeBlock.acquire())
         {        
-            write(content,complete,blocker);
+            write(content, complete, blocker);
             blocker.block();
         }
+        catch (Throwable failure)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(failure);
+            abort(failure);
+            throw failure;
+        }
     }
-    
+
     protected void write(ByteBuffer content, boolean complete, Callback callback)
     {
-        _channel.write(content,complete,callback);
+        _interceptor.write(content, complete, callback);
     }
-    
+
+    private void abort(Throwable failure)
+    {
+        closed();
+        _channel.abort(failure);
+    }
+
     @Override
     public void close()
     {
-        loop: while(true)
+        while(true)
         {
             OutputState state=_state.get();
             switch (state)
             {
                 case CLOSED:
-                    break loop;
-                    
+                {
+                    return;
+                }
                 case UNREADY:
+                {
                     if (_state.compareAndSet(state,OutputState.ERROR))
                         _writeListener.onError(_onError==null?new EofException("Async close"):_onError);
-                    continue;
-                    
+                    break;
+                }
                 default:
-                    if (_state.compareAndSet(state,OutputState.CLOSED))
+                {
+                    if (!_state.compareAndSet(state,OutputState.CLOSED))
+                        break;
+
+                    try
                     {
-                        try
-                        {
-                            write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER,!_channel.getResponse().isIncluding());
-                        }
-                        catch(IOException e)
-                        {
-                            LOG.debug(e);
-                            _channel.abort();
-                        }
-                        releaseBuffer();
-                        return;
+                        write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding());
                     }
+                    catch (IOException x)
+                    {
+                        // Ignore it, it's been already logged in write().
+                    }
+                    finally
+                    {
+                        releaseBuffer();
+                    }
+                    // Return even if an exception is thrown by write().
+                    return;
+                }
             }
         }
     }
 
-    /* Called to indicated that the output is already closed (write with last==true performed) and the state needs to be updated to match */
+    /**
+     * Called to indicate that the last write has been performed.
+     * It updates the state and performs cleanup operations.
+     */
     void closed()
     {
-        loop: while(true)
+        while(true)
         {
             OutputState state=_state.get();
             switch (state)
             {
                 case CLOSED:
-                    break loop;
-                    
+                {
+                    return;
+                }
                 case UNREADY:
+                {
                     if (_state.compareAndSet(state,OutputState.ERROR))
                         _writeListener.onError(_onError==null?new EofException("Async closed"):_onError);
-                    continue;
-                    
+                    break;
+                }
                 default:
-                    if (_state.compareAndSet(state,OutputState.CLOSED))
+                {
+                    if (!_state.compareAndSet(state, OutputState.CLOSED))
+                        break;
+
+                    try
                     {
-                        try
-                        {
-                            _channel.getResponse().closeOutput();
-                        }
-                        catch(IOException e)
-                        {
-                            LOG.debug(e);
-                            _channel.abort();
-                        }
-                        releaseBuffer();
-                        return;
+                        _channel.getResponse().closeOutput();
                     }
+                    catch (Throwable x)
+                    {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug(x);
+                        abort(x);
+                    }
+                    finally
+                    {
+                        releaseBuffer();
+                    }
+                    // Return even if an exception is thrown by closeOutput().
+                    return;
+                }
             }
         }
     }
@@ -260,12 +315,13 @@
                     
                 case CLOSED:
                     return;
+
+                default:
+                    throw new IllegalStateException();
             }
-            break;
         }
     }
 
-
     @Override
     public void write(byte[] b, int off, int len) throws IOException
     {
@@ -292,7 +348,7 @@
                     if (!complete && len<=_commitSize)
                     {
                         if (_aggregate == null)
-                            _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
+                            _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
 
                         // YES - fill the aggregate with content from the buffer
                         int filled = BufferUtil.fill(_aggregate, b, off, len);
@@ -323,11 +379,13 @@
                     
                 case CLOSED:
                     throw new EofException("Closed");
+
+                default:
+                    throw new IllegalStateException();
             }
             break;
         }
 
-
         // handle blocking write
 
         // Should we aggregate?
@@ -335,7 +393,7 @@
         if (!complete && len<=_commitSize)
         {
             if (_aggregate == null)
-                _aggregate = _channel.getByteBufferPool().acquire(capacity, false);
+                _aggregate = _channel.getByteBufferPool().acquire(capacity, _interceptor.isOptimizedForDirectBuffers());
 
             // YES - fill the aggregate with content from the buffer
             int filled = BufferUtil.fill(_aggregate, b, off, len);
@@ -383,11 +441,12 @@
             write(view,complete);
         }
         else if (complete)
-            write(BufferUtil.EMPTY_BUFFER,complete);
+        {
+            write(BufferUtil.EMPTY_BUFFER,true);
+        }
 
         if (complete)
             closed();
-
     }
 
     public void write(ByteBuffer buffer) throws IOException
@@ -424,6 +483,9 @@
                     
                 case CLOSED:
                     throw new EofException("Closed");
+
+                default:
+                    throw new IllegalStateException();
             }
             break;
         }
@@ -440,7 +502,7 @@
         if (len>0)
             write(buffer, complete);
         else if (complete)
-            write(BufferUtil.EMPTY_BUFFER,complete);
+            write(BufferUtil.EMPTY_BUFFER, true);
 
         if (complete)
             closed();
@@ -459,17 +521,13 @@
             {
                 case OPEN:
                     if (_aggregate == null)
-                        _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
+                        _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
                     BufferUtil.append(_aggregate, (byte)b);
 
                     // Check if all written or full
                     if (complete || BufferUtil.isFull(_aggregate))
                     {
-                        try(Blocker blocker=_writeblock.acquire())
-                        {
-                            write(_aggregate, complete, blocker);
-                            blocker.block();
-                        }
+                        write(_aggregate, complete);
                         if (complete)
                             closed();
                     }
@@ -483,7 +541,7 @@
                         continue;
 
                     if (_aggregate == null)
-                        _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), false);
+                        _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
                     BufferUtil.append(_aggregate, (byte)b);
 
                     // Check if all written or full
@@ -507,6 +565,9 @@
                     
                 case CLOSED:
                     throw new EofException("Closed");
+
+                default:
+                    throw new IllegalStateException();
             }
             break;
         }
@@ -521,71 +582,98 @@
         write(s.getBytes(_channel.getResponse().getCharacterEncoding()));
     }
 
-    /* ------------------------------------------------------------ */
-    /** Blocking send of content.
-     * @param content The content to send.
-     * @throws IOException
+    /**
+     * Blocking send of whole content.
+     *
+     * @param content The whole content to send
+     * @throws IOException if the send fails
      */
     public void sendContent(ByteBuffer content) throws IOException
     {
-        try(Blocker blocker=_writeblock.acquire())
-        {
-            write(content,true,blocker);
-            blocker.block();
-        }
+        if (LOG.isDebugEnabled())
+            LOG.debug("sendContent({})",BufferUtil.toDetailString(content));
+        
+        write(content, true);
+        closed();
     }
 
-    /* ------------------------------------------------------------ */
-    /** Blocking send of content.
-     * @param in The content to send
-     * @throws IOException
+    /**
+     * Blocking send of stream content.
+     *
+     * @param in The stream content to send
+     * @throws IOException if the send fails
      */
     public void sendContent(InputStream in) throws IOException
     {
-        try(Blocker blocker=_writeblock.acquire())
+        try(Blocker blocker = _writeBlock.acquire())
         {
-            new InputStreamWritingCB(in,blocker).iterate();
+            new InputStreamWritingCB(in, blocker).iterate();
             blocker.block();
         }
+        catch (Throwable failure)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(failure);
+            abort(failure);
+            throw failure;
+        }
     }
 
-    /* ------------------------------------------------------------ */
-    /** Blocking send of content.
-     * @param in The content to send
-     * @throws IOException
+    /**
+     * Blocking send of channel content.
+     *
+     * @param in The channel content to send
+     * @throws IOException if the send fails
      */
     public void sendContent(ReadableByteChannel in) throws IOException
     {
-        try(Blocker blocker=_writeblock.acquire())
+        try(Blocker blocker = _writeBlock.acquire())
         {
-            new ReadableByteChannelWritingCB(in,blocker).iterate();
+            new ReadableByteChannelWritingCB(in, blocker).iterate();
             blocker.block();
         }
+        catch (Throwable failure)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(failure);
+            abort(failure);
+            throw failure;
+        }
     }
 
-
-    /* ------------------------------------------------------------ */
-    /** Blocking send of content.
-     * @param content The content to send
-     * @throws IOException
+    /**
+     * Blocking send of HTTP content.
+     *
+     * @param content The HTTP content to send
+     * @throws IOException if the send fails
      */
     public void sendContent(HttpContent content) throws IOException
     {
-        try(Blocker blocker=_writeblock.acquire())
+        try(Blocker blocker = _writeBlock.acquire())
         {
-            sendContent(content,blocker);
+            sendContent(content, blocker);
             blocker.block();
         }
+        catch (Throwable failure)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug(failure);
+            abort(failure);
+            throw failure;
+        }
     }
 
-    /* ------------------------------------------------------------ */
-    /** Asynchronous send of content.
-     * @param content The content to send
+    /**
+     * Asynchronous send of whole content.
+     * @param content The whole content to send
      * @param callback The callback to use to notify success or failure
      */
     public void sendContent(ByteBuffer content, final Callback callback)
     {
-        write(content,true,new Callback()
+        if (LOG.isDebugEnabled())
+            LOG.debug("sendContent(buffer={},{})",BufferUtil.toDetailString(content),callback);
+        
+        write(content, true, new Callback()
         {
             @Override
             public void succeeded()
@@ -597,40 +685,53 @@
             @Override
             public void failed(Throwable x)
             {
+                abort(x);
                 callback.failed(x);
             }
         });
     }
 
-    /* ------------------------------------------------------------ */
-    /** Asynchronous send of content.
-     * @param in The content to send as a stream.  The stream will be closed
-     * after reading all content.
+    /**
+     * Asynchronous send of stream content.
+     * The stream will be closed after reading all content.
+     *
+     * @param in The stream content to send
      * @param callback The callback to use to notify success or failure
      */
     public void sendContent(InputStream in, Callback callback)
     {
-        new InputStreamWritingCB(in,callback).iterate();
+        if (LOG.isDebugEnabled())
+            LOG.debug("sendContent(stream={},{})",in,callback);
+        
+        new InputStreamWritingCB(in, callback).iterate();
     }
 
-    /* ------------------------------------------------------------ */
-    /** Asynchronous send of content.
-     * @param in The content to send as a channel.  The channel will be closed
-     * after reading all content.
+    /**
+     * Asynchronous send of channel content.
+     * The channel will be closed after reading all content.
+     *
+     * @param in The channel content to send
      * @param callback The callback to use to notify success or failure
      */
     public void sendContent(ReadableByteChannel in, Callback callback)
     {
-        new ReadableByteChannelWritingCB(in,callback).iterate();
+        if (LOG.isDebugEnabled())
+            LOG.debug("sendContent(channel={},{})",in,callback);
+        
+        new ReadableByteChannelWritingCB(in, callback).iterate();
     }
 
-    /* ------------------------------------------------------------ */
-    /** Asynchronous send of content.
-     * @param httpContent The content to send
+    /**
+     * Asynchronous send of HTTP content.
+     *
+     * @param httpContent The HTTP content to send
      * @param callback The callback to use to notify success or failure
      */
     public void sendContent(HttpContent httpContent, Callback callback)
     {
+        if (LOG.isDebugEnabled())
+            LOG.debug("sendContent(http={},{})",httpContent,callback);
+        
         if (BufferUtil.hasContent(_aggregate))
         {
             callback.failed(new IOException("cannot sendContent() after write()"));
@@ -650,6 +751,7 @@
                     if (!_state.compareAndSet(OutputState.OPEN, OutputState.PENDING))
                         continue;
                     break;
+
                 case ERROR:
                     callback.failed(new EofException(_onError));
                     return;
@@ -657,20 +759,20 @@
                 case CLOSED:
                     callback.failed(new EofException("Closed"));
                     return;
+
                 default:
                     throw new IllegalStateException();
             }
             break;
         }
-        ByteBuffer buffer= _channel.useDirectBuffers()?httpContent.getDirectBuffer():null;
+        
+
+        ByteBuffer buffer = _channel.useDirectBuffers() ? httpContent.getDirectBuffer() : null;
         if (buffer == null)
             buffer = httpContent.getIndirectBuffer();
 
         if (buffer!=null)
         {
-            if (LOG.isDebugEnabled())
-                LOG.debug("sendContent({}=={},{},direct={})",httpContent,BufferUtil.toDetailString(buffer),callback,_channel.useDirectBuffers());
-            
             sendContent(buffer,callback);
             return;
         }
@@ -680,29 +782,25 @@
             ReadableByteChannel rbc=httpContent.getReadableByteChannel();
             if (rbc!=null)
             {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("sendContent({}=={},{},direct={})",httpContent,rbc,callback,_channel.useDirectBuffers());
                 // Close of the rbc is done by the async sendContent
                 sendContent(rbc,callback);
                 return;
             }
 
             InputStream in = httpContent.getInputStream();
-            if ( in!=null )
+            if (in!=null)
             {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("sendContent({}=={},{},direct={})",httpContent,in,callback,_channel.useDirectBuffers());
                 sendContent(in,callback);
                 return;
             }
+
+            throw new IllegalArgumentException("unknown content for "+httpContent);
         }
         catch(Throwable th)
         {
+            abort(th);
             callback.failed(th);
-            return;
         }
-
-        callback.failed(new IllegalArgumentException("unknown content for "+httpContent));
     }
 
     public int getBufferSize()
@@ -716,10 +814,18 @@
         _commitSize = size;
     }
 
+    public void recycle()
+    {
+        resetBuffer();
+        _interceptor=_channel;
+    }
+    
     public void resetBuffer()
     {
+        _written = 0;
         if (BufferUtil.hasContent(_aggregate))
             BufferUtil.clear(_aggregate);
+        reopen();
     }
 
     @Override
@@ -731,7 +837,8 @@
         if (_state.compareAndSet(OutputState.OPEN, OutputState.READY))
         {
             _writeListener = writeListener;
-            _channel.getState().onWritePossible();
+            if (_channel.getState().onWritePossible())
+                _channel.execute(_channel);
         }
         else
             throw new IllegalStateException();
@@ -749,16 +856,20 @@
             {
                 case OPEN:
                     return true;
+
                 case ASYNC:
                     if (!_state.compareAndSet(OutputState.ASYNC, OutputState.READY))
                         continue;
                     return true;
+
                 case READY:
                     return true;
+
                 case PENDING:
                     if (!_state.compareAndSet(OutputState.PENDING, OutputState.UNREADY))
                         continue;
                     return false;
+
                 case UNREADY:
                     return false;
 
@@ -767,6 +878,9 @@
                     
                 case CLOSED:
                     return true;
+
+                default:
+                    throw new IllegalStateException();
             }
         }
     }
@@ -784,10 +898,12 @@
                 {
                     case CLOSED:
                     case ERROR:
+                    {
                         _onError=null;
                         break loop;
-
+                    }
                     default:
+                    {
                         if (_state.compareAndSet(state, OutputState.ERROR))
                         {
                             Throwable th=_onError;
@@ -796,10 +912,9 @@
                                 LOG.debug("onError",th);
                             _writeListener.onError(th);
                             close();
-
                             break loop;
                         }
-
+                    }
                 }
                 continue;
             }
@@ -807,10 +922,12 @@
             switch(_state.get())
             {
                 case CLOSED:
-                    // even though a write is not possible, because a close has 
+                    // Even though a write is not possible, because a close has
                     // occurred, we need to call onWritePossible to tell async
                     // producer that the last write completed.
-                    // so fall through
+                    // So fall through
+                case PENDING:
+                case UNREADY:
                 case READY:
                     try
                     {
@@ -819,7 +936,7 @@
                     }
                     catch (Throwable e)
                     {
-                        _onError=e;
+                        _onError = e;
                     }
                     break;
                     
@@ -828,13 +945,25 @@
             }
         }
     }
-    
+
+    private void close(Closeable resource)
+    {
+        try
+        {
+            resource.close();
+        }
+        catch (Throwable x)
+        {
+            LOG.ignore(x);
+        }
+    }
+
     @Override
     public String toString()
     {
         return String.format("%s@%x{%s}",this.getClass().getSimpleName(),hashCode(),_state.get());
     }
-    
+
     private abstract class AsyncICB extends IteratingCallback
     {
         @Override
@@ -853,7 +982,8 @@
                     case UNREADY:
                         if (!_state.compareAndSet(OutputState.UNREADY, OutputState.READY))
                             continue;
-                        _channel.getState().onWritePossible();
+                        if (_channel.getState().onWritePossible())
+                            _channel.execute(_channel);
                         break;
 
                     case CLOSED:
@@ -870,11 +1000,11 @@
         public void onCompleteFailure(Throwable e)
         {
             _onError=e==null?new IOException():e;
-            _channel.getState().onWritePossible();
+            if (_channel.getState().onWritePossible())
+                _channel.execute(_channel);
         }
     }
-    
-    
+
     private class AsyncFlush extends AsyncICB
     {
         protected volatile boolean _flushed;
@@ -904,8 +1034,6 @@
         }
     }
 
-
-
     private class AsyncWrite extends AsyncICB
     {
         private final ByteBuffer _buffer;
@@ -928,7 +1056,13 @@
             _buffer=buffer;
             _len=buffer.remaining();
             // Use a slice buffer for large indirect to avoid JVM pooling large direct buffers
-            _slice=_buffer.isDirect()||_len<getBufferSize()?null:_buffer.duplicate();
+            if (_buffer.isDirect()||_len<getBufferSize())
+                _slice=null;
+            else
+            {
+                _slice=_buffer.duplicate();
+                _buffer.position(_buffer.limit());
+            }                
             _complete=complete;
         }
 
@@ -980,10 +1114,12 @@
             if (_complete && !_completed)
             {
                 _completed=true;
-                write(BufferUtil.EMPTY_BUFFER, _complete, this);
+                write(BufferUtil.EMPTY_BUFFER, true, this);
                 return Action.SCHEDULED;
             }
 
+            if (LOG.isDebugEnabled() && _completed)
+                LOG.debug("EOF of {}",this);
             return Action.SUCCEEDED;
         }
 
@@ -994,13 +1130,10 @@
             if (_complete)
                 closed();
         }
-        
-        
     }
 
-
-    /* ------------------------------------------------------------ */
-    /** An iterating callback that will take content from an
+    /**
+     * An iterating callback that will take content from an
      * InputStream and write it to the associated {@link HttpChannel}.
      * A non direct buffer of size {@link HttpOutput#getBufferSize()} is used.
      * This callback is passed to the {@link HttpChannel#write(ByteBuffer, boolean, Callback)} to
@@ -1027,6 +1160,8 @@
             // a write done with EOF=true
             if (_eof)
             {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("EOF of {}",this);
                 // Handle EOF
                 _in.close();
                 closed();
@@ -1055,18 +1190,11 @@
         @Override
         public void onCompleteFailure(Throwable x)
         {
-            super.onCompleteFailure(x);
+            abort(x);
             _channel.getByteBufferPool().release(_buffer);
-            try
-            {
-                _in.close();
-            }
-            catch (IOException e)
-            {
-                LOG.ignore(e);
-            }
+            HttpOutput.this.close(_in);
+            super.onCompleteFailure(x);
         }
-
     }
 
     /* ------------------------------------------------------------ */
@@ -1090,7 +1218,7 @@
             _in=in;
             _buffer = _channel.getByteBufferPool().acquire(getBufferSize(), _channel.useDirectBuffers());
         }
-
+        
         @Override
         protected Action process() throws Exception
         {
@@ -1098,6 +1226,8 @@
             // a write done with EOF=true
             if (_eof)
             {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("EOF of {}",this);
                 _in.close();
                 closed();
                 _channel.getByteBufferPool().release(_buffer);
@@ -1112,23 +1242,17 @@
             // write what we have
             _buffer.flip();
             write(_buffer,_eof,this);
-
+            
             return Action.SCHEDULED;
         }
 
         @Override
         public void onCompleteFailure(Throwable x)
         {
-            super.onCompleteFailure(x);
+            abort(x);
             _channel.getByteBufferPool().release(_buffer);
-            try
-            {
-                _in.close();
-            }
-            catch (IOException e)
-            {
-                LOG.ignore(e);
-            }
+            HttpOutput.this.close(_in);
+            super.onCompleteFailure(x);
         }
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java
index d392246..af09e6e 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java
@@ -20,21 +20,41 @@
 
 import java.nio.ByteBuffer;
 
-import org.eclipse.jetty.http.HttpGenerator;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.util.Callback;
 
+
+/* ------------------------------------------------------------ */
+/** Abstraction of the outbound HTTP transport.
+ */
 public interface HttpTransport
 {    
-    void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback);
+    void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback);
 
-    void send(ByteBuffer content, boolean lastContent, Callback callback);
+    boolean isPushSupported();
     
-    void completed();
+    void push(MetaData.Request request);
     
-    /* ------------------------------------------------------------ */
-    /** Abort transport.
-     * This is called when an error response needs to be sent, but the response is already committed.
-     * Abort to should terminate the transport in a way that can indicate abnormal response to the client. 
+    void onCompleted();
+    
+    /**
+     * Aborts this transport.
+     * <p>
+     * This method should terminate the transport in a way that
+     * can indicate an abnormal response to the client, for example
+     * by abruptly close the connection.
+     * <p>
+     * This method is called when an error response needs to be sent,
+     * but the response is already committed, or when a write failure
+     * is detected.
+     *
+     * @param failure the failure that caused the abort.
      */
-    void abort();
+    void abort(Throwable failure);
+
+    /* ------------------------------------------------------------ */
+    /** Is the underlying transport optimized for DirectBuffer usage
+     * @return True if direct buffers can be used optimally.
+     */
+    boolean isOptimizedForDirectBuffers();
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
index b41891c..5251235 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java
@@ -161,7 +161,7 @@
         if (!isStarted())
             throw new IllegalStateException("!STARTED");
         LocalEndPoint endp = new LocalEndPoint();
-        endp.setInput(rawRequest);
+        endp.addInput(rawRequest);
         _connects.add(endp);
         return endp;
     }
@@ -187,16 +187,13 @@
 
         public LocalEndPoint()
         {
-            super(getScheduler(), LocalConnector.this.getIdleTimeout());
+            super(LocalConnector.this.getScheduler(), LocalConnector.this.getIdleTimeout());
             setGrowOutput(true);
         }
-
-        public void addInput(String s)
+        
+        protected void execute(Runnable task)
         {
-            // TODO this is a busy wait
-            while(getIn()==null || BufferUtil.hasContent(getIn()))
-                Thread.yield();
-            setInput(BufferUtil.toBuffer(s, StandardCharsets.UTF_8));
+            getExecutor().execute(task);
         }
 
         @Override
@@ -206,7 +203,6 @@
             super.close();
             if (wasOpen)
             {
-//                connectionClosed(getConnection());
                 getConnection().onClose();
                 onClose();
             }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LowResourceMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LowResourceMonitor.java
index 4c37991..bb6cc09 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/LowResourceMonitor.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LowResourceMonitor.java
@@ -37,11 +37,14 @@
 import org.eclipse.jetty.util.thread.ThreadPool;
 
 
-/* ------------------------------------------------------------ */
-/** A monitor for low resources
- * <p>An instance of this class will monitor all the connectors of a server (or a set of connectors
+/** 
+ * A monitor for low resources
+ * <p>
+ * An instance of this class will monitor all the connectors of a server (or a set of connectors
  * configured with {@link #setMonitoredConnectors(Collection)}) for a low resources state.
- * Low resources can be detected by:<ul>
+ * <p>
+ * Low resources can be detected by:
+ * <ul>
  * <li>{@link ThreadPool#isLowOnThreads()} if {@link Connector#getExecutor()} is
  * an instance of {@link ThreadPool} and {@link #setMonitorThreads(boolean)} is true.<li>
  * <li>If {@link #setMaxMemory(long)} is non zero then low resources is detected if the JVMs
@@ -50,14 +53,13 @@
  * <li>If {@link #setMaxConnections(int)} is non zero then low resources is dected if the total number
  * of connections exceeds {@link #getMaxConnections()}</li>
  * </ul>
- * </p>
- * <p>Once low resources state is detected, the cause is logged and all existing connections returned
+ * <p>
+ * Once low resources state is detected, the cause is logged and all existing connections returned
  * by {@link Connector#getConnectedEndPoints()} have {@link EndPoint#setIdleTimeout(long)} set
  * to {@link #getLowResourcesIdleTimeout()}.  New connections are not affected, however if the low
  * resources state persists for more than {@link #getMaxLowResourcesTime()}, then the
  * {@link #getLowResourcesIdleTimeout()} to all connections again.  Once the low resources state is
  * cleared, the idle timeout is reset to the connector default given by {@link Connector#getIdleTimeout()}.
- * </p>
  */
 @ManagedObject ("Monitor for low resource conditions and activate a low resource mode if detected")
 public class LowResourceMonitor extends AbstractLifeCycle
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java
new file mode 100644
index 0000000..9ca8465
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server;
+
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.MultiException;
+import org.eclipse.jetty.util.MultiPartInputStreamParser;
+
+public class MultiPartCleanerListener implements ServletRequestListener
+{
+    public final static MultiPartCleanerListener INSTANCE = new MultiPartCleanerListener();
+    
+    protected MultiPartCleanerListener()
+    {
+    }
+    
+    @Override
+    public void requestDestroyed(ServletRequestEvent sre)
+    {
+        //Clean up any tmp files created by MultiPartInputStream
+        MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM);
+        if (mpis != null)
+        {
+            ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT);
+
+            //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files
+            if (context == sre.getServletContext())
+            {
+                try
+                {
+                    mpis.deleteParts();
+                }
+                catch (MultiException e)
+                {
+                    sre.getServletContext().log("Errors deleting multipart tmp files", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void requestInitialized(ServletRequestEvent sre)
+    {
+        //nothing to do, multipart config set up by ServletHolder.handle()
+    }
+    
+}
\ No newline at end of file
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java
index 0aa5aad..aa9fe9f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NCSARequestLog.java
@@ -38,7 +38,7 @@
  * formats.
  */
 @ManagedObject("NCSA standard format request log")
-public class NCSARequestLog extends AbstractNCSARequestLog implements RequestLog
+public class NCSARequestLog extends AbstractNCSARequestLog
 {
     private String _filename;
     private boolean _append;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnection.java
index be4149d..3ad9f9a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnection.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.util.List;
 
 import javax.net.ssl.SSLEngine;
@@ -36,6 +35,11 @@
 {
     private static final Logger LOG = Log.getLogger(NegotiatingServerConnection.class);
 
+    public interface CipherDiscriminator
+    {
+        boolean isAcceptable(String protocol, String tlsProtocol, String tlsCipher);
+    }
+    
     private final Connector connector;
     private final SSLEngine engine;
     private final List<String> protocols;
@@ -61,6 +65,11 @@
         return defaultProtocol;
     }
 
+    protected Connector getConnector()
+    {
+        return connector;
+    }
+    
     protected SSLEngine getSSLEngine()
     {
         return engine;
@@ -111,9 +120,8 @@
                 ConnectionFactory connectionFactory = connector.getConnectionFactory(protocol);
                 if (connectionFactory == null)
                 {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured",
-                            this, protocol, ConnectionFactory.class.getName());
+                    LOG.info("{} application selected protocol '{}', but no correspondent {} has been configured",
+                             this, protocol, ConnectionFactory.class.getName());
                     close();
                 }
                 else
@@ -128,7 +136,7 @@
         {
             // Something went bad, we need to close.
             if (LOG.isDebugEnabled())
-                LOG.debug("{} closing on client close", this);
+                LOG.debug("{} detected close on client side", this);
             close();
         }
         else
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java
index 10547c2..22c780c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java
@@ -18,27 +18,57 @@
 
 package org.eclipse.jetty.server;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.ssl.SslConnection;
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.Connector;
 
 public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory
 {
-    private final List<String> protocols;
+    public static void checkProtocolNegotiationAvailable()
+    {
+        if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN"))
+            throw new IllegalStateException("No ALPN classes available");
+    }
+
+    private static boolean isAvailableInBootClassPath(String className)
+    {
+        try
+        {
+            Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className);
+            if (klass.getClassLoader() != null)
+                throw new IllegalStateException(className + " must be on JVM boot classpath");
+            return true;
+        }
+        catch (ClassNotFoundException x)
+        {
+            return false;
+        }
+    }
+
+    private final List<String> negotiatedProtocols;
     private String defaultProtocol;
 
-    public NegotiatingServerConnectionFactory(String protocol, String... protocols)
+    public NegotiatingServerConnectionFactory(String protocol, String... negotiatedProtocols)
     {
         super(protocol);
-        this.protocols = Arrays.asList(protocols);
+        this.negotiatedProtocols = new ArrayList<>();
+        if (negotiatedProtocols != null)
+        {
+            // Trim the values, as they may come from XML configuration.
+            for (String p : negotiatedProtocols)
+            {
+                p = p.trim();
+                if (!p.isEmpty())
+                    this.negotiatedProtocols.add(p.trim());
+            }
+        }
     }
 
     public String getDefaultProtocol()
@@ -48,36 +78,42 @@
 
     public void setDefaultProtocol(String defaultProtocol)
     {
-        this.defaultProtocol = defaultProtocol;
+        // Trim the value, as it may come from XML configuration.
+        String dft = defaultProtocol == null ? "" : defaultProtocol.trim();
+        this.defaultProtocol = dft.isEmpty() ? null : dft;
     }
 
-    public List<String> getProtocols()
+    public List<String> getNegotiatedProtocols()
     {
-        return protocols;
+        return negotiatedProtocols;
     }
-
+    
     @Override
     public Connection newConnection(Connector connector, EndPoint endPoint)
     {
-        List<String> protocols = this.protocols;
-        if (protocols.isEmpty())
+        List<String> negotiated = this.negotiatedProtocols;
+        if (negotiated.isEmpty())
         {
-            protocols = connector.getProtocols();
-            Iterator<String> i = protocols.iterator();
-            while (i.hasNext())
+            // Generate list of protocols that we can negotiate
+            negotiated = new ArrayList<>(connector.getProtocols());
+            for (Iterator<String> i = negotiated.iterator();i.hasNext();)
             {
                 String protocol = i.next();
-                String prefix = "ssl-";
-                if (protocol.regionMatches(true, 0, prefix, 0, prefix.length()) || protocol.equalsIgnoreCase("alpn"))
+                // exclude SSL and negotiating protocols
+                ConnectionFactory f = connector.getConnectionFactory(protocol);
+               
+                if ((f instanceof SslConnectionFactory) ||
+                    (f instanceof NegotiatingServerConnectionFactory))
                 {
                     i.remove();
                 }
             }
         }
 
+        // if default protocol is not set, then it is the first protocol given
         String dft = defaultProtocol;
-        if (dft == null && !protocols.isEmpty())
-            dft = protocols.get(0);
+        if (dft == null && !negotiated.isEmpty())
+            dft = negotiated.get(0);
 
         SSLEngine engine = null;
         EndPoint ep = endPoint;
@@ -90,7 +126,7 @@
                 ep = null;
         }
 
-        return configure(newServerConnection(connector, endPoint, engine, protocols, dft), connector, endPoint);
+        return configure(newServerConnection(connector, endPoint, engine, negotiated, dft), connector, endPoint);
     }
 
     protected abstract AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol);
@@ -98,6 +134,6 @@
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s,%s,%s}", getClass().getSimpleName(), hashCode(), getProtocol(), getDefaultProtocol(), getProtocols());
+        return String.format("%s@%x{%s,%s,%s}", getClass().getSimpleName(), hashCode(), getProtocols(), getDefaultProtocol(), getNegotiatedProtocols());
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java
index 9bf0dee..974e454 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NetworkTrafficServerConnector.java
@@ -26,10 +26,10 @@
 import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.NetworkTrafficListener;
 import org.eclipse.jetty.io.NetworkTrafficSelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.io.SelectorManager;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.Scheduler;
 
@@ -84,7 +84,7 @@
     }
 
     @Override
-    protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectorManager.ManagedSelector selectSet, SelectionKey key) throws IOException
+    protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
     {
         NetworkTrafficSelectChannelEndPoint endPoint = new NetworkTrafficSelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout(), listeners);
         return endPoint;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java
new file mode 100644
index 0000000..9752434
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java
@@ -0,0 +1,343 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadPendingException;
+import java.nio.channels.WritePendingException;
+import java.util.Iterator;
+
+import org.eclipse.jetty.io.AbstractConnection;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * ConnectionFactory for the PROXY Protocol.
+ * <p>This factory can be placed in front of any other connection factory
+ * to process the proxy line before the normal protocol handling</p>
+ *
+ * @see <a href="http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt">http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt</a>
+ */
+public class ProxyConnectionFactory extends AbstractConnectionFactory
+{
+    private static final Logger LOG = Log.getLogger(ProxyConnectionFactory.class);
+    private final String _next;
+
+    /* ------------------------------------------------------------ */
+    /** Proxy Connection Factory that uses the next ConnectionFactory
+     * on the connector as the next protocol
+     */
+    public ProxyConnectionFactory()
+    {
+        super("proxy");
+        _next=null;
+    }
+
+    public ProxyConnectionFactory(String nextProtocol)
+    {
+        super("proxy");
+        _next=nextProtocol;
+    }
+
+    @Override
+    public Connection newConnection(Connector connector, EndPoint endp)
+    {
+        String next=_next;
+        if (next==null)
+        {
+            for (Iterator<String> i = connector.getProtocols().iterator();i.hasNext();)
+            {
+                String p=i.next();
+                if (getProtocol().equalsIgnoreCase(p))
+                {
+                    next=i.next();
+                    break;
+                }
+            }
+        }
+
+        return new ProxyConnection(endp,connector,next);
+    }
+
+    public static class ProxyConnection extends AbstractConnection
+    {
+        // 0     1 2       3       4 5 6
+        // 98765432109876543210987654321
+        // PROXY P R.R.R.R L.L.L.L R Lrn
+
+        private final int[] __size = {29,23,21,13,5,3,1};
+        private final Connector _connector;
+        private final String _next;
+        private final StringBuilder _builder=new StringBuilder();
+        private final String[] _field=new String[6];
+        private int _fields;
+        private int _length;
+
+        protected ProxyConnection(EndPoint endp, Connector connector, String next)
+        {
+            super(endp,connector.getExecutor());
+            _connector=connector;
+            _next=next;
+        }
+
+        @Override
+        public void onOpen()
+        {
+            super.onOpen();
+            fillInterested();
+        }
+
+        @Override
+        public void onFillable()
+        {
+            try
+            {
+                ByteBuffer buffer=null;
+                loop: while(true)
+                {
+                    // Create a buffer that will not read too much data
+                    int size=Math.max(1,__size[_fields]-_builder.length());
+                    if (buffer==null || buffer.capacity()!=size)
+                        buffer=BufferUtil.allocate(size);
+                    else
+                        BufferUtil.clear(buffer);
+
+                    // Read data
+                    int fill=getEndPoint().fill(buffer);
+                    if (fill<0)
+                    {
+                        getEndPoint().shutdownOutput();
+                        return;
+                    }
+                    if (fill==0)
+                    {
+                        fillInterested();
+                        return;
+                    }
+
+                    _length+=fill;
+                    if (_length>=108)
+                    {
+                        LOG.warn("PROXY line too long {} for {}",_length,getEndPoint());
+                        close();
+                        return;
+                    }
+
+                    // parse fields
+                    while (buffer.hasRemaining())
+                    {
+                        byte b = buffer.get();
+                        if (_fields<6)
+                        {
+                            if (b==' ' || b=='\r' && _fields==5)
+                            {
+                                _field[_fields++]=_builder.toString();
+                                _builder.setLength(0);
+                            }
+                            else if (b<' ')
+                            {
+                                LOG.warn("Bad character {} for {}",b&0xFF,getEndPoint());
+                                close();
+                                return;
+                            }
+                            else
+                            {
+                                _builder.append((char)b);
+                            }
+                        }
+                        else
+                        {
+                            if (b=='\n')
+                                break loop;
+
+                            LOG.warn("Bad CRLF for {}",getEndPoint());
+                            close();
+                            return;
+                        }
+                    }
+                }
+
+                // Check proxy
+                if (!"PROXY".equals(_field[0]))
+                {
+                    LOG.warn("Not PROXY protocol for {}",getEndPoint());
+                    close();
+                    return;
+                }
+
+                // Extract Addresses
+                InetSocketAddress remote=new InetSocketAddress(_field[2],Integer.parseInt(_field[4]));
+                InetSocketAddress local =new InetSocketAddress(_field[3],Integer.parseInt(_field[5]));
+
+                // Create the next protocol
+                ConnectionFactory connectionFactory = _connector.getConnectionFactory(_next);
+                if (connectionFactory == null)
+                {
+                    LOG.info("Next protocol '{}' for {}",_next,getEndPoint());
+                    close();
+                    return;
+                }
+
+                EndPoint endPoint = new ProxyEndPoint(getEndPoint(),remote,local);
+                Connection newConnection = connectionFactory.newConnection(_connector, endPoint);
+                endPoint.upgrade(newConnection);
+            }
+            catch (Throwable x)
+            {
+                LOG.warn("PROXY error for "+getEndPoint(),x);
+                close();
+            }
+        }
+    }
+
+    public static class ProxyEndPoint implements EndPoint
+    {
+        private final EndPoint _endp;
+        private final InetSocketAddress _remote;
+        private final InetSocketAddress _local;
+
+        public ProxyEndPoint(EndPoint endp, InetSocketAddress remote, InetSocketAddress local)
+        {
+            _endp=endp;
+            _remote=remote;
+            _local=local;
+        }
+
+        @Override
+        public boolean isOptimizedForDirectBuffers()
+        {
+            return _endp.isOptimizedForDirectBuffers();
+        }
+
+        public InetSocketAddress getLocalAddress()
+        {
+            return _local;
+        }
+
+        public InetSocketAddress getRemoteAddress()
+        {
+            return _remote;
+        }
+
+        public boolean isOpen()
+        {
+            return _endp.isOpen();
+        }
+
+        public long getCreatedTimeStamp()
+        {
+            return _endp.getCreatedTimeStamp();
+        }
+
+        public void shutdownOutput()
+        {
+            _endp.shutdownOutput();
+        }
+
+        public boolean isOutputShutdown()
+        {
+            return _endp.isOutputShutdown();
+        }
+
+        public boolean isInputShutdown()
+        {
+            return _endp.isInputShutdown();
+        }
+
+        public void close()
+        {
+            _endp.close();
+        }
+
+        public int fill(ByteBuffer buffer) throws IOException
+        {
+            return _endp.fill(buffer);
+        }
+
+        public boolean flush(ByteBuffer... buffer) throws IOException
+        {
+            return _endp.flush(buffer);
+        }
+
+        public Object getTransport()
+        {
+            return _endp.getTransport();
+        }
+
+        public long getIdleTimeout()
+        {
+            return _endp.getIdleTimeout();
+        }
+
+        public void setIdleTimeout(long idleTimeout)
+        {
+            _endp.setIdleTimeout(idleTimeout);
+        }
+
+        public void fillInterested(Callback callback) throws ReadPendingException
+        {
+            _endp.fillInterested(callback);
+        }
+
+        @Override
+        public boolean isFillInterested()
+        {
+            return _endp.isFillInterested();
+        }
+
+        public void write(Callback callback, ByteBuffer... buffers) throws WritePendingException
+        {
+            _endp.write(callback,buffers);
+        }
+
+        public Connection getConnection()
+        {
+            return _endp.getConnection();
+        }
+
+        public void setConnection(Connection connection)
+        {
+            _endp.setConnection(connection);
+        }
+
+        public void onOpen()
+        {
+            _endp.onOpen();
+        }
+
+        public void onClose()
+        {
+            _endp.onClose();
+        }
+
+        @Override
+        public void upgrade(Connection newConnection)
+        {
+            _endp.upgrade(newConnection);
+        }
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilder.java b/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilder.java
new file mode 100644
index 0000000..803d6a0
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilder.java
@@ -0,0 +1,185 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.util.Set;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/** Build a request to be pushed.
+ * <p>
+ * A PushBuilder is obtained by calling {@link Request#getPushBuilder()}
+ * which creates an initializes the builder as follows:
+ * <ul>
+ * <li> Each call to getPushBuilder() will return a new instance of a 
+ * PushBuilder based off the Request.  Any mutations to the
+ * returned PushBuilder are not reflected on future returns.</li>
+ * <li>The method is initialized to "GET"</li>
+ * <li>The requests headers are added to the Builder, except for:<ul>
+ *   <li>Conditional headers (eg. If-Modified-Since)
+ *   <li>Range headers
+ *   <li>Expect headers
+ *   <li>Authorization headers
+ *   <li>Referrer headers
+ * </ul></li>
+ * <li>If the request was Authenticated, an Authorization header will 
+ * be set with a container generated token that will result in equivalent
+ * Authorization for the pushed request</li>
+ * <li>The query string from {@link HttpServletRequest#getQueryString()}
+ * <li>The {@link HttpServletRequest#getRequestedSessionId()} value, unless at the time
+ * of the call {@link HttpServletRequest#getSession(boolean)}
+ * has previously been called to create a new {@link HttpSession}, in 
+ * which case the new session ID will be used as the PushBuilders 
+ * requested session ID. The source of the requested session id will be the 
+ * same as for the request</li>
+ * <li>The Referer header will be set to {@link HttpServletRequest#getRequestURL()} 
+ * plus any {@link HttpServletRequest#getQueryString()} </li>
+ * <li>If {@link HttpServletResponse#addCookie(Cookie)} has been called
+ * on the associated response, then a corresponding Cookie header will be added
+ * to the PushBuilder, unless the {@link Cookie#getMaxAge()} is &lt;=0, in which
+ * case the Cookie will be removed from the builder.</li>
+ * <li>If this request has has the conditional headers If-Modified-Since or
+ * If-None-Match then the {@link #isConditional()} header is set to true.</li> 
+ * </ul>
+ * <p>A PushBuilder can be customized by chained calls to mutator methods before the 
+ * {@link #push()} method is called to initiate a push request with the current state
+ * of the builder.  After the call to {@link #push()}, the builder may be reused for
+ * another push, however the {@link #path(String)}, {@link #etag(String)} and
+ * {@link #lastModified(String)} values will have been nulled.  All other 
+ * values are retained over calls to {@link #push()}. 
+ */
+public interface PushBuilder
+{
+    /** Set the method to be used for the push.  
+     * Defaults to GET.
+     * @param method the method to be used for the push.  
+     * @return this builder.
+     */
+    public abstract PushBuilder method(String method);
+    
+    /** Set the query string to be used for the push.  
+     * Defaults to the requests query string.
+     * Will be appended to any query String included in a call to {@link #path(String)}.  This 
+     * method should be used instead of a query in {@link #path(String)} when multiple
+     * {@link #push()} calls are to be made with the same query string, or to remove a 
+     * query string obtained from the associated request.
+     * @param  queryString the query string to be used for the push. 
+     * @return this builder.
+     */
+    public abstract PushBuilder queryString(String queryString);
+    
+    /** Set the SessionID to be used for the push.
+     * The session ID will be set in the same way it was on the associated request (ie
+     * as a cookie if the associated request used a cookie, or as a url parameter if
+     * the associated request used a url parameter).
+     * Defaults to the requested session ID or any newly assigned session id from
+     * a newly created session.
+     * @param sessionId the SessionID to be used for the push.
+     * @return this builder.
+     */
+    public abstract PushBuilder sessionId(String sessionId);
+    
+    /** Set if the request is to be conditional.
+     * If the request is conditional, any available values from {@link #etag(String)} or 
+     * {@link #lastModified(String)} will be set in the appropriate headers. If the request
+     * is not conditional, then etag and lastModified values are ignored.  
+     * Defaults to true if the associated request was conditional.
+     * @param  conditional true if the push request is conditional
+     * @return this builder.
+     */
+    public abstract PushBuilder conditional(boolean conditional);
+    
+    /** Set a header to be used for the push.  
+     * @param name The header name to set
+     * @param value The header value to set
+     * @return this builder.
+     */
+    public abstract PushBuilder setHeader(String name, String value);
+    
+    /** Add a header to be used for the push.  
+     * @param name The header name to add
+     * @param value The header value to add
+     * @return this builder.
+     */
+    public abstract PushBuilder addHeader(String name, String value);
+    
+    /** Set the URI path to be used for the push.  
+     * The path may start with "/" in which case it is treated as an
+     * absolute path, otherwise it is relative to the context path of
+     * the associated request.
+     * There is no path default and {@link #path(String)} must be called
+     * before every call to {@link #push()}
+     * @param path the URI path to be used for the push, which may include a
+     * query string.
+     * @return this builder.
+     */
+    public abstract PushBuilder path(String path);
+    
+    /** Set the etag to be used for conditional pushes.  
+     * The etag will be used only if {@link #isConditional()} is true.
+     * Defaults to no etag.  The value is nulled after every call to 
+     * {@link #push()}
+     * @param etag the etag to be used for the push.
+     * @return this builder.
+     */
+    public abstract PushBuilder etag(String etag);
+
+    /** Set the last modified date to be used for conditional pushes.  
+     * The last modified date will be used only if {@link #isConditional()} is true.
+     * Defaults to no date.  The value is nulled after every call to 
+     * {@link #push()}
+     * @param lastModified the last modified date to be used for the push.
+     * @return this builder.
+     * */
+    public abstract PushBuilder lastModified(String lastModified);
+
+
+    /** Push a resource.
+     * Push a resource based on the current state of the PushBuilder.  If {@link #isConditional()}
+     * is true and an etag or lastModified value is provided, then an appropriate conditional header
+     * will be generated. If both an etag and lastModified value are provided only an If-None-Match header
+     * will be generated. If the builder has a session ID, then the pushed request
+     * will include the session ID either as a Cookie or as a URI parameter as appropriate. The builders
+     * query string is merged with any passed query string.
+     * After initiating the push, the builder has its path, etag and lastModified fields nulled. All 
+     * other fields are left as is for possible reuse in another push.
+     * @throws IllegalArgumentException if the method set expects a request body (eg POST)
+     */
+    public abstract void push();
+    
+    
+    
+    
+    
+    public abstract String getMethod();
+    public abstract String getQueryString();
+    public abstract String getSessionId();
+    public abstract boolean isConditional();
+    public abstract Set<String> getHeaderNames();
+    public abstract String getHeader(String name);
+    public abstract String getPath();
+    public abstract String getEtag();
+    public abstract String getLastModified();
+
+
+
+}
\ No newline at end of file
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilderImpl.java b/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilderImpl.java
new file mode 100644
index 0000000..d884a3d
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/PushBuilderImpl.java
@@ -0,0 +1,311 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.util.Set;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** 
+ */
+public class PushBuilderImpl implements PushBuilder
+{    
+    private static final Logger LOG = Log.getLogger(PushBuilderImpl.class);
+
+    private final static HttpField JettyPush = new HttpField("x-http2-push","PushBuilder");
+    
+    private final Request _request;
+    private final HttpFields _fields;
+    private String _method;
+    private String _queryString;
+    private String _sessionId;
+    private boolean _conditional;
+    private String _path;
+    private String _etag;
+    private String _lastModified;
+    
+    public PushBuilderImpl(Request request, HttpFields fields, String method, String queryString, String sessionId, boolean conditional)
+    {
+        super();
+        _request = request;
+        _fields = fields;
+        _method = method;
+        _queryString = queryString;
+        _sessionId = sessionId;
+        _conditional = conditional;
+        _fields.add(JettyPush);
+        if (LOG.isDebugEnabled())
+            LOG.debug("PushBuilder({} {}?{} s={} c={})",_method,_request.getRequestURI(),_queryString,_sessionId,_conditional);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getMethod()
+     */
+    @Override
+    public String getMethod()
+    {
+        return _method;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#method(java.lang.String)
+     */
+    @Override
+    public PushBuilder method(String method)
+    {
+        _method = method;
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getQueryString()
+     */
+    @Override
+    public String getQueryString()
+    {
+        return _queryString;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#queryString(java.lang.String)
+     */
+    @Override
+    public PushBuilder queryString(String queryString)
+    {
+        _queryString = queryString;
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getSessionId()
+     */
+    @Override
+    public String getSessionId()
+    {
+        return _sessionId;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#sessionId(java.lang.String)
+     */
+    @Override
+    public PushBuilder sessionId(String sessionId)
+    {
+        _sessionId = sessionId;
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#isConditional()
+     */
+    @Override
+    public boolean isConditional()
+    {
+        return _conditional;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#conditional(boolean)
+     */
+    @Override
+    public PushBuilder conditional(boolean conditional)
+    {
+        _conditional = conditional;
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getHeaderNames()
+     */
+    @Override
+    public Set<String> getHeaderNames()
+    {
+        return _fields.getFieldNamesCollection();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getHeader(java.lang.String)
+     */
+    @Override
+    public String getHeader(String name)
+    {
+        return _fields.get(name);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#setHeader(java.lang.String, java.lang.String)
+     */
+    @Override
+    public PushBuilder setHeader(String name,String value)
+    {
+        _fields.put(name,value);
+        return this;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#addHeader(java.lang.String, java.lang.String)
+     */
+    @Override
+    public PushBuilder addHeader(String name,String value)
+    {
+        _fields.add(name,value);
+        return this;
+    }
+
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getPath()
+     */
+    @Override
+    public String getPath()
+    {
+        return _path;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#path(java.lang.String)
+     */
+    @Override
+    public PushBuilder path(String path)
+    {
+        _path = path;
+        return this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getEtag()
+     */
+    @Override
+    public String getEtag()
+    {
+        return _etag;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#etag(java.lang.String)
+     */
+    @Override
+    public PushBuilder etag(String etag)
+    {
+        _etag = etag;
+        return this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#getLastModified()
+     */
+    @Override
+    public String getLastModified()
+    {
+        return _lastModified;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#lastModified(java.lang.String)
+     */
+    @Override
+    public PushBuilder lastModified(String lastModified)
+    {
+        _lastModified = lastModified;
+        return this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.PushBuilder#push()
+     */
+    @Override
+    public void push()
+    {
+        if (HttpMethod.POST.is(_method) || HttpMethod.PUT.is(_method))
+            throw new IllegalStateException("Bad Method "+_method);
+        
+        if (_path==null || _path.length()==0)
+            throw new IllegalStateException("Bad Path "+_path);
+        
+        String path=_path;
+        String query=_queryString;
+        int q=path.indexOf('?');
+        if (q>=0)
+        {
+            query=(query!=null && query.length()>0)?(_path.substring(q+1)+'&'+query):_path.substring(q+1);
+            path=_path.substring(0,q);
+        }
+        
+        if (!path.startsWith("/"))
+            path=URIUtil.addPaths(_request.getContextPath(),path);
+        
+        String param=null;
+        if (_sessionId!=null)
+        {
+            if (_request.isRequestedSessionIdFromURL())
+                param="jsessionid="+_sessionId;
+            // TODO else 
+            //      _fields.add("Cookie","JSESSIONID="+_sessionId);
+        }
+        
+        if (_conditional)
+        {
+            if (_etag!=null)
+                _fields.add(HttpHeader.IF_NONE_MATCH,_etag);
+            else if (_lastModified!=null)
+                _fields.add(HttpHeader.IF_MODIFIED_SINCE,_lastModified);
+        }
+        
+        HttpURI uri = HttpURI.createHttpURI(_request.getScheme(),_request.getServerName(),_request.getServerPort(),_path,param,query,null);
+        MetaData.Request push = new MetaData.Request(_method,uri,_request.getHttpVersion(),_fields);
+        
+        if (LOG.isDebugEnabled())
+            LOG.debug("Push {} {} inm={} ims={}",_method,uri,_fields.get(HttpHeader.IF_NONE_MATCH),_fields.get(HttpHeader.IF_MODIFIED_SINCE));
+        
+        _request.getHttpChannel().getHttpTransport().push(push);
+        _path=null;
+        _etag=null;
+        _lastModified=null;
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java
deleted file mode 100644
index e088897..0000000
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/QueuedHttpInput.java
+++ /dev/null
@@ -1,146 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-
-import org.eclipse.jetty.util.ArrayQueue;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * {@link QueuedHttpInput} holds a queue of items passed to it by calls to {@link #content(Object)}.
- * <p/>
- * {@link QueuedHttpInput} stores the items directly; if the items contain byte buffers, it does not copy them
- * but simply holds references to the item, thus the caller must organize for those buffers to valid while
- * held by this class.
- * <p/>
- * To assist the caller, subclasses may override methods {@link #onAsyncRead()}, {@link #onContentConsumed(Object)}
- * that can be implemented so that the caller will know when buffers are queued and consumed.
- */
-public abstract class QueuedHttpInput<T> extends HttpInput<T>
-{
-    private final static Logger LOG = Log.getLogger(QueuedHttpInput.class);
-
-    private final ArrayQueue<T> _inputQ = new ArrayQueue<>(lock());
-
-    public QueuedHttpInput()
-    {
-    }
-
-    public void content(T item)
-    {
-        // The buffer is not copied here.  This relies on the caller not recycling the buffer
-        // until the it is consumed.  The onContentConsumed and onAllContentConsumed() callbacks are
-        // the signals to the caller that the buffers can be recycled.
-
-        synchronized (lock())
-        {
-            boolean wasEmpty = _inputQ.isEmpty();
-            _inputQ.add(item);
-            if (LOG.isDebugEnabled())
-                LOG.debug("{} queued {}", this, item);
-            if (wasEmpty)
-            {
-                if (!onAsyncRead())
-                    lock().notify();
-            }
-        }
-    }
-
-    public void recycle()
-    {
-        synchronized (lock())
-        {
-            T item = _inputQ.pollUnsafe();
-            while (item != null)
-            {
-                onContentConsumed(item);
-                item = _inputQ.pollUnsafe();
-            }
-            super.recycle();
-        }
-    }
-
-    @Override
-    protected T nextContent()
-    {
-        synchronized (lock())
-        {
-            // Items are removed only when they are fully consumed.
-            T item = _inputQ.peekUnsafe();
-            // Skip consumed items at the head of the queue.
-            while (item != null && remaining(item) == 0)
-            {
-                _inputQ.pollUnsafe();
-                onContentConsumed(item);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("{} consumed {}", this, item);
-                item = _inputQ.peekUnsafe();
-            }
-            return item;
-        }
-    }
-
-    protected void blockForContent() throws IOException
-    {
-        synchronized (lock())
-        {
-            while (_inputQ.isEmpty() && !isFinished() && !isEOF())
-            {
-                try
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("{} waiting for content", this);
-                    lock().wait();
-                }
-                catch (InterruptedException e)
-                {
-                    throw (IOException)new InterruptedIOException().initCause(e);
-                }
-            }
-        }
-    }
-
-    /**
-     * Callback that signals that the given content has been consumed.
-     *
-     * @param item the consumed content
-     */
-    protected abstract void onContentConsumed(T item);
-
-    public void earlyEOF()
-    {
-        synchronized (lock())
-        {
-            super.earlyEOF();
-            lock().notify();
-        }
-    }
-
-    public void messageComplete()
-    {
-        synchronized (lock())
-        {
-            super.messageComplete();
-            lock().notify();
-        }
-    }
-}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index a39a139..a7cb18c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -52,8 +52,7 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequestAttributeEvent;
 import javax.servlet.ServletRequestAttributeListener;
-import javax.servlet.ServletRequestEvent;
-import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletRequestWrapper;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
@@ -62,13 +61,18 @@
 import javax.servlet.http.HttpUpgradeHandler;
 import javax.servlet.http.Part;
 
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HostPortHttpField;
 import org.eclipse.jetty.http.HttpCookie;
+import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ContextHandler.Context;
@@ -76,7 +80,6 @@
 import org.eclipse.jetty.util.Attributes;
 import org.eclipse.jetty.util.AttributesMap;
 import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.MultiException;
 import org.eclipse.jetty.util.MultiMap;
 import org.eclipse.jetty.util.MultiPartInputStreamParser;
 import org.eclipse.jetty.util.StringUtil;
@@ -85,7 +88,6 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* ------------------------------------------------------------ */
 /**
  * Jetty Request.
  * <p>
@@ -114,8 +116,6 @@
  * {@link ContextHandler#getMaxFormContentSize()} or if there is no context then the "org.eclipse.jetty.server.Request.maxFormContentSize" {@link Server}
  * attribute. The number of parameters keys is limited by {@link ContextHandler#getMaxFormKeys()} or if there is no context then the
  * "org.eclipse.jetty.server.Request.maxFormKeys" {@link Server} attribute.
- *
- *
  */
 public class Request implements HttpServletRequest
 {
@@ -127,46 +127,44 @@
     private static final Collection<Locale> __defaultLocale = Collections.singleton(Locale.getDefault());
     private static final int __NONE = 0, _STREAM = 1, __READER = 2;
 
-    private final HttpChannel<?> _channel;
-    private final HttpFields _fields=new HttpFields();
-    private final List<ServletRequestAttributeListener>  _requestAttributeListeners=new ArrayList<>();
-    private final HttpInput<?> _input;
+    private static final MultiMap<String> NO_PARAMS = new MultiMap<>();
 
-    public static class MultiPartCleanerListener implements ServletRequestListener
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Obtain the base {@link Request} instance of a {@link ServletRequest}, by
+     * coercion, unwrapping or special attribute.
+     * @param request The request
+     * @return the base {@link Request} instance of a {@link ServletRequest}.
+     */
+    public static Request getBaseRequest(ServletRequest request)
     {
-        @Override
-        public void requestDestroyed(ServletRequestEvent sre)
-        {
-            //Clean up any tmp files created by MultiPartInputStream
-            MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM);
-            if (mpis != null)
-            {
-                ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__MULTIPART_CONTEXT);
+        if (request instanceof Request)
+            return (Request)request;
 
-                //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files
-                if (context == sre.getServletContext())
-                {
-                    try
-                    {
-                        mpis.deleteParts();
-                    }
-                    catch (MultiException e)
-                    {
-                        sre.getServletContext().log("Errors deleting multipart tmp files", e);
-                    }
-                }
-            }
-        }
+        Object channel = request.getAttribute(HttpChannel.class.getName());
+        if (channel instanceof HttpChannel)
+            return ((HttpChannel)channel).getRequest();
 
-        @Override
-        public void requestInitialized(ServletRequestEvent sre)
-        {
-            //nothing to do, multipart config set up by ServletHolder.handle()
-        }
+        while (request instanceof ServletRequestWrapper)
+            request=((ServletRequestWrapper)request).getRequest();
 
+        if (request instanceof Request)
+            return (Request)request;
+
+        return null;
     }
 
 
+    private final HttpChannel _channel;
+    private final List<ServletRequestAttributeListener>  _requestAttributeListeners=new ArrayList<>();
+    private final HttpInput _input;
+
+    private MetaData.Request _metadata;
+
+    private String _contextPath;
+    private String _servletPath;
+    private String _pathInfo;
 
     private boolean _secure;
     private boolean _asyncSupported = true;
@@ -175,43 +173,31 @@
     private boolean _handled = false;
     private boolean _paramsExtracted;
     private boolean _requestedSessionIdFromCookie = false;
-    private volatile Attributes _attributes;
+    private Attributes _attributes;
     private Authentication _authentication;
     private String _characterEncoding;
     private ContextHandler.Context _context;
-    private String _contextPath;
     private CookieCutter _cookies;
     private DispatcherType _dispatcherType;
     private int _inputState = __NONE;
-    private HttpMethod _httpMethod;
-    private String _httpMethodString;
     private MultiMap<String> _queryParameters;
     private MultiMap<String> _contentParameters;
     private MultiMap<String> _parameters;
-    private String _pathInfo;
-    private int _port;
-    private HttpVersion _httpVersion = HttpVersion.HTTP_1_1;
     private String _queryEncoding;
-    private String _queryString;
     private BufferedReader _reader;
     private String _readerEncoding;
     private InetSocketAddress _remote;
     private String _requestedSessionId;
-    private String _requestURI;
     private Map<Object, HttpSession> _savedNewSessions;
-    private String _scheme = URIUtil.HTTP;
     private UserIdentity.Scope _scope;
-    private String _serverName;
-    private String _servletPath;
     private HttpSession _session;
     private SessionManager _sessionManager;
     private long _timeStamp;
-    private HttpURI _uri;
     private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime
     private AsyncContextState _async;
 
     /* ------------------------------------------------------------ */
-    public Request(HttpChannel<?> channel, HttpInput<?> input)
+    public Request(HttpChannel channel, HttpInput input)
     {
         _channel = channel;
         _input = input;
@@ -220,16 +206,135 @@
     /* ------------------------------------------------------------ */
     public HttpFields getHttpFields()
     {
-        return _fields;
+        return _metadata.getFields();
     }
 
     /* ------------------------------------------------------------ */
-    public HttpInput<?> getHttpInput()
+    public HttpInput getHttpInput()
     {
         return _input;
     }
 
     /* ------------------------------------------------------------ */
+    public boolean isPush()
+    {
+        return Boolean.TRUE.equals(getAttribute("org.eclipse.jetty.pushed"));
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isPushSupported()
+    {
+        return getHttpChannel().getHttpTransport().isPushSupported();
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get a PushBuilder associated with this request initialized as follows:<ul>
+     * <li>The method is initialized to "GET"</li>
+     * <li>The headers from this request are copied to the Builder, except for:<ul>
+     *   <li>Conditional headers (eg. If-Modified-Since)
+     *   <li>Range headers
+     *   <li>Expect headers
+     *   <li>Authorization headers
+     *   <li>Referrer headers
+     * </ul></li>
+     * <li>If the request was Authenticated, an Authorization header will
+     * be set with a container generated token that will result in equivalent
+     * Authorization</li>
+     * <li>The query string from {@link #getQueryString()}
+     * <li>The {@link #getRequestedSessionId()} value, unless at the time
+     * of the call {@link #getSession(boolean)}
+     * has previously been called to create a new {@link HttpSession}, in
+     * which case the new session ID will be used as the PushBuilders
+     * requested session ID.</li>
+     * <li>The source of the requested session id will be the same as for
+     * this request</li>
+     * <li>The builders Referer header will be set to {@link #getRequestURL()}
+     * plus any {@link #getQueryString()} </li>
+     * <li>If {@link HttpServletResponse#addCookie(Cookie)} has been called
+     * on the associated response, then a corresponding Cookie header will be added
+     * to the PushBuilder, unless the {@link Cookie#getMaxAge()} is &lt;=0, in which
+     * case the Cookie will be removed from the builder.</li>
+     * <li>If this request has has the conditional headers If-Modified-Since or
+     * If-None-Match then the {@link PushBuilderImpl#isConditional()} header is set
+     * to true.
+     * </ul>
+     *
+     * <p>Each call to getPushBuilder() will return a new instance
+     * of a PushBuilder based off this Request.  Any mutations to the
+     * returned PushBuilder are not reflected on future returns.
+     * @return A new PushBuilder or null if push is not supported
+     */
+    public PushBuilder getPushBuilder()
+    {
+        if (!isPushSupported())
+            throw new IllegalStateException();
+
+        HttpFields fields = new HttpFields(getHttpFields().size()+5);
+        boolean conditional=false;
+        UserIdentity user_identity=null;
+        Authentication authentication=null;
+
+        for (HttpField field : getHttpFields())
+        {
+            HttpHeader header = field.getHeader();
+            if (header==null)
+                fields.add(field);
+            else
+            {
+                switch(header)
+                {
+                    case IF_MATCH:
+                    case IF_RANGE:
+                    case IF_UNMODIFIED_SINCE:
+                    case RANGE:
+                    case EXPECT:
+                    case REFERER:
+                    case COOKIE:
+                        continue;
+
+                    case AUTHORIZATION:
+                        user_identity=getUserIdentity();
+                        authentication=_authentication;
+                        continue;
+
+                    case IF_NONE_MATCH:
+                    case IF_MODIFIED_SINCE:
+                        conditional=true;
+                        continue;
+
+                    default:
+                        fields.add(field);
+                }
+            }
+        }
+
+        String id=null;
+        try
+        {
+            HttpSession session = getSession();
+            if (session!=null)
+            {
+                session.getLastAccessedTime(); // checks if session is valid
+                id=session.getId();
+            }
+            else
+                id=getRequestedSessionId();
+        }
+        catch(IllegalStateException e)
+        {
+            id=getRequestedSessionId();
+        }
+
+        PushBuilder builder = new PushBuilderImpl(this,fields,getMethod(),getQueryString(),id,conditional);
+        builder.addHeader("referer",getRequestURL().toString());
+
+        // TODO process any set cookies
+        // TODO process any user_identity
+
+        return builder;
+    }
+
+    /* ------------------------------------------------------------ */
     public void addEventListener(final EventListener listener)
     {
         if (listener instanceof ServletRequestAttributeListener)
@@ -238,6 +343,7 @@
             throw new IllegalArgumentException(listener.getClass().toString());
     }
 
+    /* ------------------------------------------------------------ */
     public void extractParameters()
     {
         if (_paramsExtracted)
@@ -248,31 +354,32 @@
         // Extract query string parameters; these may be replaced by a forward()
         // and may have already been extracted by mergeQueryParameters().
         if (_queryParameters == null)
-            _queryParameters = extractQueryParameters();
+            extractQueryParameters();
 
         // Extract content parameters; these cannot be replaced by a forward()
         // once extracted and may have already been extracted by getParts() or
         // by a processing happening after a form-based authentication.
         if (_contentParameters == null)
-            _contentParameters = extractContentParameters();
+            extractContentParameters();
 
-        _parameters = restoreParameters();
+        restoreParameters();
     }
 
-    private MultiMap<String> extractQueryParameters()
+    /* ------------------------------------------------------------ */
+    private void extractQueryParameters()
     {
-        MultiMap<String> result = new MultiMap<>();
-        if (_uri != null && _uri.hasQuery())
+        if (_metadata.getURI() == null || !_metadata.getURI().hasQuery())
+            _queryParameters=NO_PARAMS;
+        else
         {
+            _queryParameters = new MultiMap<>();
             if (_queryEncoding == null)
-            {
-                _uri.decodeQueryTo(result);
-            }
+                _metadata.getURI().decodeQueryTo(_queryParameters);
             else
             {
                 try
                 {
-                    _uri.decodeQueryTo(result, _queryEncoding);
+                    _metadata.getURI().decodeQueryTo(_queryParameters, _queryEncoding);
                 }
                 catch (UnsupportedEncodingException e)
                 {
@@ -283,37 +390,38 @@
                 }
             }
         }
-        return result;
     }
 
-    private MultiMap<String> extractContentParameters()
+    /* ------------------------------------------------------------ */
+    private void extractContentParameters()
     {
-        MultiMap<String> result = new MultiMap<>();
-
         String contentType = getContentType();
-        if (contentType != null && !contentType.isEmpty())
+        if (contentType == null || contentType.isEmpty())
+            _contentParameters=NO_PARAMS;
+        else
         {
+            _contentParameters=new MultiMap<>();
             contentType = HttpFields.valueParameters(contentType, null);
             int contentLength = getContentLength();
             if (contentLength != 0)
             {
                 if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE &&
-                        (HttpMethod.POST.is(getMethod()) || HttpMethod.PUT.is(getMethod())))
+                    _channel.getHttpConfiguration().isFormEncodedMethod(getMethod()))
                 {
-                    extractFormParameters(result);
+                    extractFormParameters(_contentParameters);
                 }
                 else if (contentType.startsWith("multipart/form-data") &&
                         getAttribute(__MULTIPART_CONFIG_ELEMENT) != null &&
                         _multiPartInputStream == null)
                 {
-                    extractMultipartParameters(result);
+                    extractMultipartParameters(_contentParameters);
                 }
             }
         }
 
-        return result;
     }
 
+    /* ------------------------------------------------------------ */
     public void extractFormParameters(MultiMap<String> params)
     {
         try
@@ -379,6 +487,7 @@
         }
     }
 
+    /* ------------------------------------------------------------ */
     private void extractMultipartParameters(MultiMap<String> result)
     {
         try
@@ -412,7 +521,8 @@
     /* ------------------------------------------------------------ */
     /**
      * Get Request Attribute.
-     * <p>Also supports jetty specific attributes to gain access to Jetty APIs:
+     * <p>
+     * Also supports jetty specific attributes to gain access to Jetty APIs:
      * <dl>
      * <dt>org.eclipse.jetty.server.Server</dt><dd>The Jetty Server instance</dd>
      * <dt>org.eclipse.jetty.server.HttpChannel</dt><dd>The HttpChannel for this request</dd>
@@ -420,7 +530,6 @@
      * </dl>
      * While these attributes may look like security problems, they are exposing nothing that is not already
      * available via reflection from a Request instance.
-     * </p>
      * @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
      */
     @Override
@@ -428,11 +537,11 @@
     {
         if (name.startsWith("org.eclipse.jetty"))
         {
-            if ("org.eclipse.jetty.server.Server".equals(name))
+            if (Server.class.getName().equals(name))
                 return _channel.getServer();
-            if ("org.eclipse.jetty.server.HttpChannel".equals(name))
+            if (HttpChannel.class.getName().equals(name))
                 return _channel;
-            if ("org.eclipse.jetty.server.HttpConnection".equals(name) &&
+            if (HttpConnection.class.getName().equals(name) &&
                 _channel.getHttpTransport() instanceof HttpConnection)
                 return _channel.getHttpTransport();
         }
@@ -495,6 +604,8 @@
     @Override
     public String getCharacterEncoding()
     {
+        if (_characterEncoding==null)
+            getContentType();
         return _characterEncoding;
     }
 
@@ -502,7 +613,7 @@
     /**
      * @return Returns the connection.
      */
-    public HttpChannel<?> getHttpChannel()
+    public HttpChannel getHttpChannel()
     {
         return _channel;
     }
@@ -514,7 +625,9 @@
     @Override
     public int getContentLength()
     {
-        return (int)_fields.getLongField(HttpHeader.CONTENT_LENGTH.toString());
+        if (_metadata.getContentLength()!=Long.MIN_VALUE)
+            return (int)_metadata.getContentLength();
+        return (int)_metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString());
     }
 
     /* ------------------------------------------------------------ */
@@ -524,13 +637,15 @@
     @Override
     public long getContentLengthLong()
     {
-        return _fields.getLongField(HttpHeader.CONTENT_LENGTH.toString());
+        if (_metadata.getContentLength()!=Long.MIN_VALUE)
+            return _metadata.getContentLength();
+        return _metadata.getFields().getLongField(HttpHeader.CONTENT_LENGTH.toString());
     }
 
     /* ------------------------------------------------------------ */
     public long getContentRead()
     {
-        return _input.getContentRead();
+        return _input.getContentConsumed();
     }
 
     /* ------------------------------------------------------------ */
@@ -540,7 +655,15 @@
     @Override
     public String getContentType()
     {
-        return _fields.getStringField(HttpHeader.CONTENT_TYPE);
+        String content_type = _metadata.getFields().get(HttpHeader.CONTENT_TYPE);
+        if (_characterEncoding==null && content_type!=null)
+        {
+            MimeTypes.Type mime = MimeTypes.CACHE.get(content_type);
+            String charset = (mime == null || mime.getCharset() == null) ? MimeTypes.getCharsetFromContentType(content_type) : mime.getCharset().toString();
+            if (charset != null)
+                _characterEncoding=charset;
+        }
+        return content_type;
     }
 
     /* ------------------------------------------------------------ */
@@ -569,7 +692,7 @@
     @Override
     public Cookie[] getCookies()
     {
-        if (_cookiesExtracted)
+        if (_metadata==null || _cookiesExtracted)
         {
             if (_cookies == null || _cookies.getCookies().length == 0)
                 return null;
@@ -579,7 +702,7 @@
 
         _cookiesExtracted = true;
 
-        Enumeration<?> enm = _fields.getValues(HttpHeader.COOKIE.toString());
+        Enumeration<?> enm = _metadata.getFields().getValues(HttpHeader.COOKIE.toString());
 
         // Handle no cookies
         if (enm != null)
@@ -608,7 +731,7 @@
     @Override
     public long getDateHeader(String name)
     {
-        return _fields.getDateField(name);
+        return _metadata==null?-1:_metadata.getFields().getDateField(name);
     }
 
     /* ------------------------------------------------------------ */
@@ -625,7 +748,7 @@
     @Override
     public String getHeader(String name)
     {
-        return _fields.getStringField(name);
+        return _metadata==null?null:_metadata.getFields().get(name);
     }
 
     /* ------------------------------------------------------------ */
@@ -635,7 +758,9 @@
     @Override
     public Enumeration<String> getHeaderNames()
     {
-        return _fields.getFieldNames();
+        if (_metadata==null)
+            return Collections.emptyEnumeration();
+        return _metadata.getFields().getFieldNames();
     }
 
     /* ------------------------------------------------------------ */
@@ -645,7 +770,9 @@
     @Override
     public Enumeration<String> getHeaders(String name)
     {
-        Enumeration<String> e = _fields.getValues(name);
+        if (_metadata==null)
+            return Collections.emptyEnumeration();
+        Enumeration<String> e = _metadata.getFields().getValues(name);
         if (e == null)
             return Collections.enumeration(Collections.<String>emptyList());
         return e;
@@ -684,7 +811,7 @@
     @Override
     public int getIntHeader(String name)
     {
-        return (int)_fields.getLongField(name);
+        return _metadata==null?-1:(int)_metadata.getFields().getLongField(name);
     }
 
 
@@ -695,7 +822,10 @@
     @Override
     public Locale getLocale()
     {
-        Enumeration<String> enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
+        if (_metadata==null)
+            return Locale.getDefault();
+
+        Enumeration<String> enm = _metadata.getFields().getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
 
         // handle no locale
         if (enm == null || !enm.hasMoreElements())
@@ -732,8 +862,10 @@
     @Override
     public Enumeration<Locale> getLocales()
     {
+        if (_metadata==null)
+            return Collections.enumeration(__defaultLocale);
 
-        Enumeration<String> enm = _fields.getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
+        Enumeration<String> enm = _metadata.getFields().getValues(HttpHeader.ACCEPT_LANGUAGE.toString(),HttpFields.__separators);
 
         // handle no locale
         if (enm == null || !enm.hasMoreElements())
@@ -774,6 +906,21 @@
     @Override
     public String getLocalAddr()
     {
+        if (_channel==null)
+        {
+            try
+            {
+                String name =InetAddress.getLocalHost().getHostAddress();
+                if (StringUtil.ALL_INTERFACES.equals(name))
+                    return null;
+                return name;
+            }
+            catch (java.net.UnknownHostException e)
+            {
+                LOG.ignore(e);
+            }
+        }
+
         InetSocketAddress local=_channel.getLocalAddress();
         if (local==null)
             return "";
@@ -790,6 +937,20 @@
     @Override
     public String getLocalName()
     {
+        if (_channel==null)
+        {
+            try
+            {
+                String name =InetAddress.getLocalHost().getHostName();
+                if (StringUtil.ALL_INTERFACES.equals(name))
+                    return null;
+                return name;
+            }
+            catch (java.net.UnknownHostException e)
+            {
+                LOG.ignore(e);
+            }
+        }
         InetSocketAddress local=_channel.getLocalAddress();
         return local.getHostString();
     }
@@ -801,6 +962,8 @@
     @Override
     public int getLocalPort()
     {
+        if (_channel==null)
+            return 0;
         InetSocketAddress local=_channel.getLocalAddress();
         return local.getPort();
     }
@@ -812,7 +975,7 @@
     @Override
     public String getMethod()
     {
-        return _httpMethodString;
+        return _metadata==null?null:_metadata.getMethod();
     }
 
     /* ------------------------------------------------------------ */
@@ -825,7 +988,7 @@
         if (!_paramsExtracted)
             extractParameters();
         if (_parameters == null)
-            _parameters = restoreParameters();
+            restoreParameters();
         return _parameters.getValue(name,0);
     }
 
@@ -839,7 +1002,7 @@
         if (!_paramsExtracted)
             extractParameters();
         if (_parameters == null)
-            _parameters = restoreParameters();
+            restoreParameters();
         return Collections.unmodifiableMap(_parameters.toStringArrayMap());
     }
 
@@ -853,7 +1016,7 @@
         if (!_paramsExtracted)
             extractParameters();
         if (_parameters == null)
-            _parameters = restoreParameters();
+            restoreParameters();
         return Collections.enumeration(_parameters.keySet());
     }
 
@@ -867,38 +1030,50 @@
         if (!_paramsExtracted)
             extractParameters();
         if (_parameters == null)
-            _parameters = restoreParameters();
+            restoreParameters();
         List<String> vals = _parameters.getValues(name);
         if (vals == null)
             return null;
         return vals.toArray(new String[vals.size()]);
     }
 
-    private MultiMap<String> restoreParameters()
+    /* ------------------------------------------------------------ */
+    private void restoreParameters()
     {
-        MultiMap<String> result = new MultiMap<>();
         if (_queryParameters == null)
-            _queryParameters = extractQueryParameters();
-        result.addAllValues(_queryParameters);
-        result.addAllValues(_contentParameters);
-        return result;
+            extractQueryParameters();
+
+        if (_queryParameters==NO_PARAMS || _queryParameters.size()==0)
+            _parameters=_contentParameters;
+        else if (_contentParameters==NO_PARAMS || _contentParameters.size()==0)
+            _parameters=_queryParameters;
+        else
+        {
+            _parameters = new MultiMap<>();
+            _parameters.addAllValues(_queryParameters);
+            _parameters.addAllValues(_contentParameters);
+        }
     }
 
+    /* ------------------------------------------------------------ */
     public MultiMap<String> getQueryParameters()
     {
         return _queryParameters;
     }
 
+    /* ------------------------------------------------------------ */
     public void setQueryParameters(MultiMap<String> queryParameters)
     {
         _queryParameters = queryParameters;
     }
 
+    /* ------------------------------------------------------------ */
     public void setContentParameters(MultiMap<String> contentParameters)
     {
         _contentParameters = contentParameters;
     }
 
+    /* ------------------------------------------------------------ */
     public void resetParameters()
     {
         _parameters = null;
@@ -933,7 +1108,12 @@
     @Override
     public String getProtocol()
     {
-        return _httpVersion.toString();
+        if (_metadata==null)
+            return null;
+        HttpVersion version = _metadata.getVersion();
+        if (version==null)
+            return null;
+        return version.toString();
     }
 
     /* ------------------------------------------------------------ */
@@ -942,7 +1122,7 @@
      */
     public HttpVersion getHttpVersion()
     {
-        return _httpVersion;
+        return _metadata==null?null:_metadata.getVersion();
     }
 
     /* ------------------------------------------------------------ */
@@ -958,14 +1138,7 @@
     @Override
     public String getQueryString()
     {
-        if (_queryString == null && _uri != null)
-        {
-            if (_queryEncoding == null)
-                _queryString = _uri.getQuery();
-            else
-                _queryString = _uri.getQuery(_queryEncoding);
-        }
-        return _queryString;
+        return _metadata.getURI().getQuery();
     }
 
     /* ------------------------------------------------------------ */
@@ -1132,9 +1305,8 @@
     @Override
     public String getRequestURI()
     {
-        if (_requestURI == null && _uri != null)
-            _requestURI = _uri.getPathAndParam();
-        return _requestURI;
+        MetaData metadata = _metadata;
+        return (metadata==null)?null:_metadata.getURI().getPath();
     }
 
     /* ------------------------------------------------------------ */
@@ -1181,7 +1353,8 @@
     @Override
     public String getScheme()
     {
-        return _scheme;
+        String scheme=_metadata==null?null:_metadata.getURI().getScheme();
+        return scheme==null?HttpScheme.HTTP.asString():scheme;
     }
 
     /* ------------------------------------------------------------ */
@@ -1191,90 +1364,45 @@
     @Override
     public String getServerName()
     {
+        String name = _metadata.getURI().getHost();
+
         // Return already determined host
-        if (_serverName != null)
-            return _serverName;
+        if (name != null)
+            return name;
 
-        if (_uri == null)
-            throw new IllegalStateException("No uri");
+        return findServerName();
+    }
 
-        // Return host from absolute URI
-        _serverName = _uri.getHost();
-        if (_serverName != null)
-        {
-            _port = _uri.getPort();
-            return _serverName;
-        }
-
+    /* ------------------------------------------------------------ */
+    private String findServerName()
+    {
         // Return host from header field
-        String hostPort = _fields.getStringField(HttpHeader.HOST);
-
-        _port=0;
-        if (hostPort != null)
+        HttpField host = _metadata.getFields().getField(HttpHeader.HOST);
+        if (host!=null)
         {
-            int len=hostPort.length();
-            loop: for (int i = len; i-- > 0;)
-            {
-                char c2 = (char)(0xff & hostPort.charAt(i));
-                switch (c2)
-                {
-                    case ']':
-                        break loop;
-
-                    case ':':
-                        try
-                        {
-                            len=i;
-                            _port = StringUtil.toInt(hostPort.substring(i+1));
-                        }
-                        catch (NumberFormatException e)
-                        {
-                            LOG.warn(e);
-                            _serverName=hostPort;
-                            _port=0;
-                            return _serverName;
-                        }
-                        break loop;
-                }
-            }
-            if (hostPort.charAt(0)=='[')
-            {
-                if (hostPort.charAt(len-1)!=']')
-                {
-                    LOG.warn("Bad IPv6 "+hostPort);
-                    _serverName=hostPort;
-                    _port=0;
-                    return _serverName;
-                }
-                _serverName = hostPort.substring(0,len);
-            }
-            else if (len==hostPort.length())
-                _serverName=hostPort;
-            else
-                _serverName = hostPort.substring(0,len);
-
-            return _serverName;
+            // TODO is this needed now?
+            HostPortHttpField authority = (host instanceof HostPortHttpField)
+                ?((HostPortHttpField)host)
+                :new HostPortHttpField(host.getValue());
+            _metadata.getURI().setAuthority(authority.getHost(),authority.getPort());
+            return authority.getHost();
         }
 
         // Return host from connection
-        if (_channel != null)
-        {
-            _serverName = getLocalName();
-            _port = getLocalPort();
-            if (_serverName != null && !StringUtil.ALL_INTERFACES.equals(_serverName))
-                return _serverName;
-        }
+        String name=getLocalName();
+        if (name != null)
+            return name;
 
         // Return the local host
         try
         {
-            _serverName = InetAddress.getLocalHost().getHostAddress();
+            return InetAddress.getLocalHost().getHostAddress();
         }
         catch (java.net.UnknownHostException e)
         {
             LOG.ignore(e);
         }
-        return _serverName;
+        return null;
     }
 
     /* ------------------------------------------------------------ */
@@ -1284,30 +1412,41 @@
     @Override
     public int getServerPort()
     {
-        if (_port <= 0)
-        {
-            if (_serverName == null)
-                getServerName();
+        HttpURI uri = _metadata.getURI();
+        int port = (uri.getHost()==null)?findServerPort():uri.getPort();
 
-            if (_port <= 0)
-            {
-                if (_serverName != null && _uri != null)
-                    _port = _uri.getPort();
-                else
-                {
-                    InetSocketAddress local = _channel.getLocalAddress();
-                    _port = local == null?0:local.getPort();
-                }
-            }
-        }
-
-        if (_port <= 0)
+        // If no port specified, return the default port for the scheme
+        if (port <= 0)
         {
             if (getScheme().equalsIgnoreCase(URIUtil.HTTPS))
                 return 443;
             return 80;
         }
-        return _port;
+
+        // return a specific port
+        return port;
+    }
+
+    /* ------------------------------------------------------------ */
+    private int findServerPort()
+    {
+        // Return host from header field
+        HttpField host = _metadata.getFields().getField(HttpHeader.HOST);
+        if (host!=null)
+        {
+            // TODO is this needed now?
+            HostPortHttpField authority = (host instanceof HostPortHttpField)
+                ?((HostPortHttpField)host)
+                :new HostPortHttpField(host.getValue());
+            _metadata.getURI().setAuthority(authority.getHost(),authority.getPort());
+            return authority.getPort();
+        }
+
+        // Return host from connection
+        if (_channel != null)
+            return getLocalPort();
+
+        return -1;
     }
 
     /* ------------------------------------------------------------ */
@@ -1360,7 +1499,7 @@
             AbstractSession abstractSession =  ((AbstractSession)session);
             abstractSession.renewId(this);
             if (getRemoteUser() != null)
-                abstractSession.setAttribute(AbstractSession.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
+                abstractSession.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
             if (abstractSession.isIdChanged())
                 _channel.getResponse().addCookie(_sessionManager.getSessionCookie(abstractSession, getContextPath(), isSecure()));
         }
@@ -1434,9 +1573,18 @@
     /**
      * @return Returns the uri.
      */
-    public HttpURI getUri()
+    public HttpURI getHttpURI()
     {
-        return _uri;
+        return _metadata==null?null:_metadata.getURI();
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param uri the URI to set
+     */
+    public void setHttpURI(HttpURI uri)
+    {
+        _metadata.setURI(uri);
     }
 
     /* ------------------------------------------------------------ */
@@ -1591,9 +1739,71 @@
         return _savedNewSessions.get(key);
     }
 
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param request the Request metadata
+     */
+    public void setMetaData(org.eclipse.jetty.http.MetaData.Request request)
+    {
+        _metadata=request;
+        setMethod(request.getMethod());
+        HttpURI uri = request.getURI();
+
+        String path = uri.getDecodedPath();
+        String info;
+        if (path==null || path.length()==0)
+        {
+            if (uri.isAbsolute())
+            {
+                path="/";
+                uri.setPath(path);
+            }
+            else
+            {
+                setPathInfo("");
+                throw new BadMessageException(400,"Bad URI");
+            }
+            info=path;
+        }
+        else if (!path.startsWith("/"))
+        {
+            if (!"*".equals(path) && !HttpMethod.CONNECT.is(getMethod()))
+            {
+                setPathInfo(path);
+                throw new BadMessageException(400,"Bad URI");
+            }
+            info=path;
+        }
+        else
+            info = URIUtil.canonicalPath(path);// TODO should this be done prior to decoding???
+
+        if (info == null)
+        {
+            setPathInfo(path);
+            throw new BadMessageException(400,"Bad URI");
+        }
+
+        setPathInfo(info);
+    }
+
+    /* ------------------------------------------------------------ */
+    public org.eclipse.jetty.http.MetaData.Request getMetaData()
+    {
+        return _metadata;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean hasMetaData()
+    {
+        return _metadata!=null;
+    }
+
     /* ------------------------------------------------------------ */
     protected void recycle()
     {
+        _metadata=null;
+
         if (_context != null)
             throw new IllegalStateException("Request in context!");
 
@@ -1629,25 +1839,16 @@
         _cookiesExtracted = false;
         _context = null;
         _newContext=false;
-        _serverName = null;
-        _httpMethod=null;
-        _httpMethodString = null;
         _pathInfo = null;
-        _port = 0;
-        _httpVersion = HttpVersion.HTTP_1_1;
         _queryEncoding = null;
-        _queryString = null;
         _requestedSessionId = null;
         _requestedSessionIdFromCookie = false;
         _secure=false;
         _session = null;
         _sessionManager = null;
-        _requestURI = null;
         _scope = null;
-        _scheme = URIUtil.HTTP;
         _servletPath = null;
         _timeStamp = 0;
-        _uri = null;
         _queryParameters = null;
         _contentParameters = null;
         _parameters = null;
@@ -1659,7 +1860,6 @@
         _savedNewSessions=null;
         _multiPartInputStream = null;
         _remote=null;
-        _fields.clear();
         _input.recycle();
     }
 
@@ -1802,8 +2002,7 @@
      */
     public void setContentType(String contentType)
     {
-        _fields.put(HttpHeader.CONTENT_TYPE,contentType);
-
+        _metadata.getFields().put(HttpHeader.CONTENT_TYPE,contentType);
     }
 
     /* ------------------------------------------------------------ */
@@ -1834,7 +2033,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Sets the "context path" for this request
-     *
+     * @param contextPath the context path for this request
      * @see HttpServletRequest#getContextPath()
      */
     public void setContextPath(String contextPath)
@@ -1871,16 +2070,15 @@
      * @param method
      *            The method to set.
      */
-    public void setMethod(HttpMethod httpMethod, String method)
+    public void setMethod(String method)
     {
-        _httpMethod=httpMethod;
-        _httpMethodString = method;
+        _metadata.setMethod(method);
     }
 
     /* ------------------------------------------------------------ */
     public boolean isHead()
     {
-        return HttpMethod.HEAD==_httpMethod;
+        return _metadata!=null && HttpMethod.HEAD.is(_metadata.getMethod());
     }
 
     /* ------------------------------------------------------------ */
@@ -1895,27 +2093,16 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param version
-     *            The protocol to set.
-     */
-    public void setHttpVersion(HttpVersion version)
-    {
-        _httpVersion = version;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
      * Set the character encoding used for the query string. This call will effect the return of getQueryString and getParamaters. It must be called before any
      * getParameter methods.
      *
      * The request attribute "org.eclipse.jetty.server.server.Request.queryEncoding" may be set as an alternate method of calling setQueryEncoding.
      *
-     * @param queryEncoding
+     * @param queryEncoding the URI query character encoding
      */
     public void setQueryEncoding(String queryEncoding)
     {
         _queryEncoding = queryEncoding;
-        _queryString = null;
     }
 
     /* ------------------------------------------------------------ */
@@ -1925,7 +2112,7 @@
      */
     public void setQueryString(String queryString)
     {
-        _queryString = queryString;
+        _metadata.getURI().setQuery(queryString);
         _queryEncoding = null; //assume utf-8
     }
 
@@ -1960,13 +2147,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param requestURI
-     *            The requestURI to set.
-     */
-    public void setRequestURI(String requestURI)
+    public void setURIPathQuery(String requestURI)
     {
-        _requestURI = requestURI;
+        _metadata.getURI().setPathQuery(requestURI);
     }
 
     /* ------------------------------------------------------------ */
@@ -1976,27 +2159,19 @@
      */
     public void setScheme(String scheme)
     {
-        _scheme = scheme;
+        _metadata.getURI().setScheme(scheme);
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @param host
      *            The host to set.
-     */
-    public void setServerName(String host)
-    {
-        _serverName = host;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
      * @param port
-     *            The port to set.
+     *            the port to set
      */
-    public void setServerPort(int port)
+    public void setAuthority(String host,int port)
     {
-        _port = port;
+        _metadata.getURI().setAuthority(host,port);
     }
 
     /* ------------------------------------------------------------ */
@@ -2036,16 +2211,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param uri
-     *            The uri to set.
-     */
-    public void setUri(HttpURI uri)
-    {
-        _uri = uri;
-    }
-
-    /* ------------------------------------------------------------ */
     public void setUserIdentityScope(UserIdentity.Scope scope)
     {
         _scope = scope;
@@ -2089,7 +2254,7 @@
                 getClass().getSimpleName(),
                 _handled ? "[" : "(",
                 getMethod(),
-                _uri,
+                getHttpURI(),
                 _handled ? "]" : ")",
                 hashCode());
     }
@@ -2162,7 +2327,7 @@
                         IO.copy(is, os);
                         String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset));
                         if (_contentParameters == null)
-                            _contentParameters = params == null ? new MultiMap<String>() : params;
+                            _contentParameters = params == null ? new MultiMap<>() : params;
                         _contentParameters.add(mp.getName(), content);
                     }
                     os.reset();
@@ -2198,24 +2363,35 @@
         _authentication=Authentication.UNAUTHENTICATED;
     }
 
-    public void mergeQueryParameters(String newQuery, boolean updateQueryString)
+    /* ------------------------------------------------------------ */
+    public void mergeQueryParameters(String oldQuery,String newQuery, boolean updateQueryString)
     {
-        MultiMap<String> newQueryParams = new MultiMap<>();
-        // Have to assume ENCODING because we can't know otherwise.
-        UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING, -1);
+        // TODO  This is seriously ugly
 
-        MultiMap<String> oldQueryParams = _queryParameters;
-        if (oldQueryParams == null && _queryString != null)
+        MultiMap<String> newQueryParams = null;
+        // Have to assume ENCODING because we can't know otherwise.
+        if (newQuery!=null)
         {
-            oldQueryParams = new MultiMap<>();
-            UrlEncoded.decodeTo(_queryString, oldQueryParams, getQueryEncoding(), -1);
+            newQueryParams = new MultiMap<>();
+            UrlEncoded.decodeTo(newQuery, newQueryParams, UrlEncoded.ENCODING);
         }
 
-        MultiMap<String> mergedQueryParams = newQueryParams;
-        if (oldQueryParams != null)
+        MultiMap<String> oldQueryParams = _queryParameters;
+        if (oldQueryParams == null && oldQuery != null)
+        {
+            oldQueryParams = new MultiMap<>();
+            UrlEncoded.decodeTo(oldQuery, oldQueryParams, getQueryEncoding());
+        }
+
+        MultiMap<String> mergedQueryParams;
+        if (newQueryParams==null || newQueryParams.size()==0)
+            mergedQueryParams=oldQueryParams==null?NO_PARAMS:oldQueryParams;
+        else if (oldQueryParams==null || oldQueryParams.size()==0)
+            mergedQueryParams=newQueryParams==null?NO_PARAMS:newQueryParams;
+        else
         {
             // Parameters values are accumulated.
-            mergedQueryParams = new MultiMap<>(newQueryParams);
+            mergedQueryParams=new MultiMap<>(newQueryParams);
             mergedQueryParams.addAllValues(oldQueryParams);
         }
 
@@ -2224,18 +2400,32 @@
 
         if (updateQueryString)
         {
-            // Build the new merged query string, parameters in the
-            // new query string hide parameters in the old query string.
-            StringBuilder mergedQuery = new StringBuilder(newQuery);
-            for (Map.Entry<String, List<String>> entry : mergedQueryParams.entrySet())
+            if (newQuery==null)
+                setQueryString(oldQuery);
+            else if (oldQuery==null)
+                setQueryString(newQuery);
+            else
             {
-                if (newQueryParams.containsKey(entry.getKey()))
-                    continue;
-                for (String value : entry.getValue())
-                    mergedQuery.append("&").append(entry.getKey()).append("=").append(value);
+                // Build the new merged query string, parameters in the
+                // new query string hide parameters in the old query string.
+                StringBuilder mergedQuery = new StringBuilder();
+                if (newQuery!=null)
+                    mergedQuery.append(newQuery);
+                for (Map.Entry<String, List<String>> entry : mergedQueryParams.entrySet())
+                {
+                    if (newQueryParams!=null && newQueryParams.containsKey(entry.getKey()))
+                        continue;
+                    for (String value : entry.getValue())
+                    {
+                        if (mergedQuery.length()>0)
+                            mergedQuery.append("&");
+                        URIUtil.encodePath(mergedQuery,entry.getKey());
+                        mergedQuery.append('=');
+                        URIUtil.encodePath(mergedQuery,value);
+                    }
+                }
+                setQueryString(mergedQuery.toString());
             }
-
-            setQueryString(mergedQuery.toString());
         }
     }
 
@@ -2245,23 +2435,6 @@
     @Override
     public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException
     {
-        if (getContext() == null)
-            throw new ServletException ("Unable to instantiate "+handlerClass);
-
-        try
-        {
-            //Instantiate an instance and inject it
-            T h = getContext().createInstance(handlerClass);
-
-            //TODO handle the rest of the upgrade process
-
-            return h;
-        }
-        catch (Exception e)
-        {
-            if (e instanceof ServletException)
-                throw (ServletException)e;
-            throw new ServletException(e);
-        }
+        throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty");
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java
index 4391e27..e9284b6 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLog.java
@@ -18,13 +18,24 @@
 
 package org.eclipse.jetty.server; 
 
-import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
 
 /** 
  * A <code>RequestLog</code> can be attached to a {@link org.eclipse.jetty.server.handler.RequestLogHandler} to enable 
  * logging of requests/responses.
+ * @see RequestLogHandler#setRequestLog(RequestLog)
+ * @see Server#setRequestLog(RequestLog)
  */
-public interface RequestLog extends LifeCycle
+public interface RequestLog
 {
+    /* ------------------------------------------------------------ */
+    /**
+     * @param request The request to log.
+     * @param response The response to log.  Note that for some requests
+     * the response instance may not have been fully populated (Eg 400 bad request
+     * responses are sent without a servlet response object).  Thus for basic
+     * log information it is best to consult {@link Response#getCommittedMetaData()}
+     * and {@link Response#getHttpChannel()} directly.
+     */
     public void log(Request request, Response response);
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogCollection.java
new file mode 100644
index 0000000..45e27d7
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/RequestLogCollection.java
@@ -0,0 +1,46 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.util.ArrayList;
+
+import static java.util.Arrays.asList;
+
+class RequestLogCollection
+    implements RequestLog
+{
+    private final ArrayList<RequestLog> delegates;
+
+    public RequestLogCollection(RequestLog... requestLogs)
+    {
+        delegates = new ArrayList<>(asList(requestLogs));
+    }
+
+    public void add(RequestLog requestLog)
+    {
+        delegates.add(requestLog);
+    }
+
+    @Override
+    public void log(Request request, Response response)
+    {
+        for (RequestLog delegate:delegates)
+            delegate.log(request, response);
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java
index 187f89f..7dab43d 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
 import java.nio.channels.ReadableByteChannel;
 import java.util.Comparator;
 import java.util.SortedSet;
@@ -32,30 +33,33 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.http.DateGenerator;
+import org.eclipse.jetty.http.GzipHttpContent;
 import org.eclipse.jetty.http.HttpContent;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.MimeTypes.Type;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.http.ResourceHttpContent;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceFactory;
 
-
-/* ------------------------------------------------------------ */
-/** 
- * 
- */
-public class ResourceCache
+// TODO rename to ContentCache
+public class ResourceCache implements HttpContent.Factory
 {
     private static final Logger LOG = Log.getLogger(ResourceCache.class);
 
-    private final ConcurrentMap<String,Content> _cache;
+    private final ConcurrentMap<String,CachedHttpContent> _cache;
     private final AtomicInteger _cachedSize;
     private final AtomicInteger _cachedFiles;
     private final ResourceFactory _factory;
     private final ResourceCache _parent;
     private final MimeTypes _mimeTypes;
-    private final boolean _etagSupported;
+    private final boolean _etags;
+    private final boolean _gzip;
     private final boolean  _useFileMappedBuffer;
     
     private int _maxCachedFileSize =128*1024*1024;
@@ -64,18 +68,24 @@
     
     /* ------------------------------------------------------------ */
     /** Constructor.
+     * @param parent the parent resource cache
+     * @param factory the resource factory
      * @param mimeTypes Mimetype to use for meta data
+     * @param useFileMappedBuffer true to file memory mapped buffers
+     * @param etags true to support etags 
+     * @param gzip true to support gzip 
      */
-    public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags)
+    public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags,boolean gzip)
     {
         _factory = factory;
-        _cache=new ConcurrentHashMap<String,Content>();
+        _cache=new ConcurrentHashMap<String,CachedHttpContent>();
         _cachedSize=new AtomicInteger();
         _cachedFiles=new AtomicInteger();
         _mimeTypes=mimeTypes;
         _parent=parent;
         _useFileMappedBuffer=useFileMappedBuffer;
-        _etagSupported=etags;
+        _etags=etags;
+        _gzip=gzip;
     }
 
     /* ------------------------------------------------------------ */
@@ -150,7 +160,7 @@
             {
                 for (String path : _cache.keySet())
                 {
-                    Content content = _cache.remove(path);
+                    CachedHttpContent content = _cache.remove(path);
                     if (content!=null)
                         content.invalidate();
                 }
@@ -159,34 +169,45 @@
     }
 
     /* ------------------------------------------------------------ */
+    @Deprecated
+    public HttpContent lookup(String pathInContext)
+        throws IOException
+    {
+        return getContent(pathInContext,_maxCachedFileSize);
+    }
+
+    /* ------------------------------------------------------------ */
     /** Get a Entry from the cache.
      * Get either a valid entry object or create a new one if possible.
      *
      * @param pathInContext The key into the cache
+     * @param maxBufferSize The maximum buffer to allocated for this request.  For cached content, a larger buffer may have
+     * previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls.
      * @return The entry matching <code>pathInContext</code>, or a new entry 
      * if no matching entry was found. If the content exists but is not cachable, 
-     * then a {@link ResourceAsHttpContent} instance is return. If 
+     * then a {@link ResourceHttpContent} instance is return. If 
      * the resource does not exist, then null is returned.
      * @throws IOException Problem loading the resource
      */
-    public HttpContent lookup(String pathInContext)
+    @Override
+    public HttpContent getContent(String pathInContext,int maxBufferSize)
         throws IOException
     {
         // Is the content in this cache?
-        Content content =_cache.get(pathInContext);
+        CachedHttpContent content =_cache.get(pathInContext);
         if (content!=null && (content).isValid())
             return content;
        
         // try loading the content from our factory.
         Resource resource=_factory.getResource(pathInContext);
-        HttpContent loaded = load(pathInContext,resource);
+        HttpContent loaded = load(pathInContext,resource,maxBufferSize);
         if (loaded!=null)
             return loaded;
         
         // Is the content in the parent cache?
         if (_parent!=null)
         {
-            HttpContent httpContent=_parent.lookup(pathInContext);
+            HttpContent httpContent=_parent.getContent(pathInContext,maxBufferSize);
             if (httpContent!=null)
                 return httpContent;
         }
@@ -196,48 +217,89 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param resource
+     * @param resource the resource to test
      * @return True if the resource is cacheable. The default implementation tests the cache sizes.
      */
     protected boolean isCacheable(Resource resource)
     {
+        if (_maxCachedFiles<=0)
+            return false;
+        
         long len = resource.length();
 
         // Will it fit in the cache?
-        return  (len>0 && len<_maxCachedFileSize && len<_maxCacheSize);
+        return  (len>0 && (_useFileMappedBuffer || (len<_maxCachedFileSize && len<_maxCacheSize)));
     }
     
     /* ------------------------------------------------------------ */
-    private HttpContent load(String pathInContext, Resource resource)
+    private HttpContent load(String pathInContext, Resource resource, int maxBufferSize)
         throws IOException
     {
-        Content content=null;
-        
         if (resource==null || !resource.exists())
             return null;
         
+        if (resource.isDirectory())
+            return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize());
+        
         // Will it fit in the cache?
-        if (!resource.isDirectory() && isCacheable(resource))
+        if (isCacheable(resource))
         {   
-            // Create the Content (to increment the cache sizes before adding the content 
-            content = new Content(pathInContext,resource);
-
-            // reduce the cache to an acceptable size.
-            shrinkCache();
+            CachedHttpContent content=null;
+            
+            // Look for a gzip resource
+            if (_gzip)
+            {
+                String pathInContextGz=pathInContext+".gz";
+                CachedHttpContent contentGz = _cache.get(pathInContextGz);
+                if (contentGz==null || !contentGz.isValid())
+                {
+                    contentGz=null;
+                    Resource resourceGz=_factory.getResource(pathInContextGz);
+                    if (resourceGz.exists() && resourceGz.lastModified()>=resource.lastModified() && resourceGz.length()<resource.length())
+                    {
+                        contentGz = new CachedHttpContent(pathInContextGz,resourceGz,null);
+                        CachedHttpContent added = _cache.putIfAbsent(pathInContextGz,contentGz);
+                        if (added!=null)
+                        {
+                            contentGz.invalidate();
+                            contentGz=added;
+                        }
+                    }
+                }
+                content = new CachedHttpContent(pathInContext,resource,contentGz);
+            }
+            else 
+                content = new CachedHttpContent(pathInContext,resource,null);
 
             // Add it to the cache.
-            Content added = _cache.putIfAbsent(pathInContext,content);
+            CachedHttpContent added = _cache.putIfAbsent(pathInContext,content);
             if (added!=null)
             {
                 content.invalidate();
                 content=added;
             }
-
+            
             return content;
         }
         
-        return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etagSupported);
+        // Look for non Cacheable gzip resource or content
+        String mt = _mimeTypes.getMimeByExtension(pathInContext);
+        if (_gzip)
+        {
+            // Is the gzip content cached?
+            String pathInContextGz=pathInContext+".gz";
+            CachedHttpContent contentGz = _cache.get(pathInContextGz);
+            if (contentGz!=null && contentGz.isValid() && contentGz.getResource().lastModified()>=resource.lastModified())
+                return new ResourceHttpContent(resource,mt,maxBufferSize,contentGz);
+            
+            // Is there a gzip resource?
+            Resource resourceGz=_factory.getResource(pathInContextGz);
+            if (resourceGz.exists() && resourceGz.lastModified()>=resource.lastModified() && resourceGz.length()<resource.length())
+                return new ResourceHttpContent(resource,mt,maxBufferSize,
+                       new ResourceHttpContent(resourceGz,_mimeTypes.getMimeByExtension(pathInContextGz),maxBufferSize));
+        }
         
+        return new ResourceHttpContent(resource,mt,maxBufferSize);
     }
     
     /* ------------------------------------------------------------ */
@@ -247,10 +309,10 @@
         while (_cache.size()>0 && (_cachedFiles.get()>_maxCachedFiles || _cachedSize.get()>_maxCacheSize))
         {
             // Scan the entire cache and generate an ordered list by last accessed time.
-            SortedSet<Content> sorted= new TreeSet<Content>(
-                    new Comparator<Content>()
+            SortedSet<CachedHttpContent> sorted= new TreeSet<CachedHttpContent>(
+                    new Comparator<CachedHttpContent>()
                     {
-                        public int compare(Content c1, Content c2)
+                        public int compare(CachedHttpContent c1, CachedHttpContent c2)
                         {
                             if (c1._lastAccessed<c2._lastAccessed)
                                 return -1;
@@ -258,17 +320,17 @@
                             if (c1._lastAccessed>c2._lastAccessed)
                                 return 1;
 
-                            if (c1._length<c2._length)
+                            if (c1._contentLengthValue<c2._contentLengthValue)
                                 return -1;
                             
                             return c1._key.compareTo(c2._key);
                         }
                     });
-            for (Content content : _cache.values())
+            for (CachedHttpContent content : _cache.values())
                 sorted.add(content);
             
             // Invalidate least recently used first
-            for (Content content : sorted)
+            for (CachedHttpContent content : sorted)
             {
                 if (_cachedFiles.get()<=_maxCachedFiles && _cachedSize.get()<=_maxCacheSize)
                     break;
@@ -295,6 +357,8 @@
     /* ------------------------------------------------------------ */
     protected ByteBuffer getDirectBuffer(Resource resource)
     {
+        // Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for
+        // a non shared resource.  Also ignore max buffer size
         try
         {
             if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE) 
@@ -320,40 +384,53 @@
     /* ------------------------------------------------------------ */
     /** MetaData associated with a context Resource.
      */
-    public class Content implements HttpContent
+    public class CachedHttpContent implements HttpContent
     {
-        final Resource _resource;
-        final int _length;
         final String _key;
-        final long _lastModified;
-        final ByteBuffer _lastModifiedBytes;
-        final ByteBuffer _contentType;
-        final String _etag;
+        final Resource _resource;
+        final int _contentLengthValue;
+        final HttpField _contentType;
+        final String _characterEncoding;
+        final MimeTypes.Type _mimeType;
+        final HttpField _contentLength;
+        final HttpField _lastModified;
+        final long _lastModifiedValue;
+        final HttpField _etag;
+        final CachedGzipHttpContent _gzipped;
         
         volatile long _lastAccessed;
         AtomicReference<ByteBuffer> _indirectBuffer=new AtomicReference<ByteBuffer>();
         AtomicReference<ByteBuffer> _directBuffer=new AtomicReference<ByteBuffer>();
 
         /* ------------------------------------------------------------ */
-        Content(String pathInContext,Resource resource)
+        CachedHttpContent(String pathInContext,Resource resource,CachedHttpContent gzipped)
         {
             _key=pathInContext;
             _resource=resource;
 
-            String mimeType = _mimeTypes.getMimeByExtension(_resource.toString());
-            _contentType=(mimeType==null?null:BufferUtil.toBuffer(mimeType));
-            boolean exists=resource.exists();
-            _lastModified=exists?resource.lastModified():-1;
-            _lastModifiedBytes=_lastModified<0?null:BufferUtil.toBuffer(DateGenerator.formatDate(_lastModified));
+            String contentType = _mimeTypes.getMimeByExtension(_resource.toString());
+            _contentType=contentType==null?null:new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,contentType);
+            _characterEncoding = _contentType==null?null:MimeTypes.getCharsetFromContentType(contentType);
+            _mimeType = _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(contentType));
             
-            _length=exists?(int)resource.length():0;
-            _cachedSize.addAndGet(_length);
-            _cachedFiles.incrementAndGet();
+            boolean exists=resource.exists();
+            _lastModifiedValue=exists?resource.lastModified():-1L;
+            _lastModified=_lastModifiedValue==-1?null
+                :new PreEncodedHttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(_lastModifiedValue));
+            
+            _contentLengthValue=exists?(int)resource.length():0;
+            _contentLength=new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH,Long.toString(_contentLengthValue));
+            
+            if (_cachedFiles.incrementAndGet()>_maxCachedFiles)
+                shrinkCache();
+            
             _lastAccessed=System.currentTimeMillis();
             
-            _etag=ResourceCache.this._etagSupported?resource.getWeakETag():null;
+            _etag=ResourceCache.this._etags?new PreEncodedHttpField(HttpHeader.ETAG,resource.getWeakETag()):null;
+            
+            _gzipped=gzipped==null?null:new CachedGzipHttpContent(this,gzipped);        
         }
-
+        
 
         /* ------------------------------------------------------------ */
         public String getKey()
@@ -382,15 +459,22 @@
 
         /* ------------------------------------------------------------ */
         @Override
-        public String getETag()
+        public HttpField getETag()
         {
             return _etag;
         }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getETagValue()
+        {
+            return _etag.getValue();
+        }
         
         /* ------------------------------------------------------------ */
         boolean isValid()
         {
-            if (_lastModified==_resource.lastModified() && _length==_resource.length())
+            if (_lastModifiedValue==_resource.lastModified() && _contentLengthValue==_resource.length())
             {
                 _lastAccessed=System.currentTimeMillis();
                 return true;
@@ -404,31 +488,79 @@
         /* ------------------------------------------------------------ */
         protected void invalidate()
         {
-            // Invalidate it
-            _cachedSize.addAndGet(-_length);
+            ByteBuffer indirect=_indirectBuffer.get();
+            if (indirect!=null && _indirectBuffer.compareAndSet(indirect,null))
+                _cachedSize.addAndGet(-BufferUtil.length(indirect));
+            
+            ByteBuffer direct=_directBuffer.get();
+            if (direct!=null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct,null))
+                _cachedSize.addAndGet(-BufferUtil.length(direct));
+
             _cachedFiles.decrementAndGet();
-            _resource.close(); 
+            _resource.close();
         }
 
         /* ------------------------------------------------------------ */
         @Override
-        public String getLastModified()
+        public HttpField getLastModified()
         {
-            return BufferUtil.toString(_lastModifiedBytes);
+            return _lastModified;
+        }
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getLastModifiedValue()
+        {
+            return _lastModified==null?null:_lastModified.getValue();
         }
 
         /* ------------------------------------------------------------ */
         @Override
-        public String getContentType()
+        public HttpField getContentType()
         {
-            return BufferUtil.toString(_contentType);
+            return _contentType;
         }
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getContentTypeValue()
+        {
+            return _contentType==null?null:_contentType.getValue();
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public HttpField getContentEncoding()
+        {
+            return null;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getContentEncodingValue()
+        {
+            return null;
+        }   
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getCharacterEncoding()
+        {
+            return _characterEncoding;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public Type getMimeType()
+        {
+            return _mimeType;
+        }
+
 
         /* ------------------------------------------------------------ */
         @Override
         public void release()
         {
-            // don't release while cached. Release when invalidated.
         }
 
         /* ------------------------------------------------------------ */
@@ -443,7 +575,11 @@
                 if (buffer2==null)
                     LOG.warn("Could not load "+this);
                 else if (_indirectBuffer.compareAndSet(null,buffer2))
+                {
                     buffer=buffer2;
+                    if (_cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
+                        shrinkCache();
+                }
                 else
                     buffer=_indirectBuffer.get();
             }
@@ -452,7 +588,6 @@
             return buffer.slice();
         }
         
-
         /* ------------------------------------------------------------ */
         @Override
         public ByteBuffer getDirectBuffer()
@@ -465,7 +600,12 @@
                 if (buffer2==null)
                     LOG.warn("Could not load "+this);
                 else if (_directBuffer.compareAndSet(null,buffer2))
+                {
                     buffer=buffer2;
+
+                    if (!BufferUtil.isMappedBuffer(buffer) && _cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
+                        shrinkCache(); 
+                }
                 else
                     buffer=_directBuffer.get();
             }
@@ -473,12 +613,19 @@
                 return null;
             return buffer.asReadOnlyBuffer();
         }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public HttpField getContentLength()
+        {
+            return _contentLength;
+        }
         
         /* ------------------------------------------------------------ */
         @Override
-        public long getContentLength()
+        public long getContentLengthValue()
         {
-            return _length;
+            return _contentLengthValue;
         }
 
         /* ------------------------------------------------------------ */
@@ -499,12 +646,65 @@
             return _resource.getReadableByteChannel();
         }
 
-
         /* ------------------------------------------------------------ */
         @Override
         public String toString()
         {
-            return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s}",hashCode(),_resource,_resource.exists(),BufferUtil.toString(_lastModifiedBytes),_contentType);
-        }   
+            return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s,gz=%b}",hashCode(),_resource,_resource.exists(),_lastModified,_contentType,_gzipped!=null);
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public HttpContent getGzipContent()
+        {
+            return (_gzipped!=null && _gzipped.isValid())?_gzipped:null;
+        }
     }
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    public class CachedGzipHttpContent extends GzipHttpContent
+    {
+        private final CachedHttpContent _content; 
+        private final CachedHttpContent _contentGz;
+        private final HttpField _etag;
+        
+        CachedGzipHttpContent(CachedHttpContent content, CachedHttpContent contentGz)
+        {
+            super(content,contentGz);
+            _content=content;
+            _contentGz=contentGz;
+            
+            _etag=(ResourceCache.this._etags)?new PreEncodedHttpField(HttpHeader.ETAG,_content.getResource().getWeakETag("--gzip")):null;
+        }
+
+        public boolean isValid()
+        {
+            return _contentGz.isValid() && _content.isValid() && _content.getResource().lastModified() <= _contentGz.getResource().lastModified();
+        }
+
+        @Override
+        public HttpField getETag()
+        {
+            if (_etag!=null)
+                return _etag;
+            return super.getETag();
+        }
+
+        @Override
+        public String getETagValue()
+        {
+            if (_etag!=null)
+                return _etag.getValue();
+            return super.getETagValue();
+        }
+        
+        @Override
+        public String toString()
+        {
+            return "Cached"+super.toString();
+        }
+    }
+
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java
new file mode 100644
index 0000000..6e70778
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java
@@ -0,0 +1,96 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+
+import org.eclipse.jetty.http.HttpContent;
+import org.eclipse.jetty.http.HttpContent.Factory;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.ResourceHttpContent;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.resource.ResourceFactory;
+
+
+/**
+ * A HttpContent.Factory for transient content.  The HttpContent's created by 
+ * this factory are not intended to be cached, so memory limits for individual
+ * HttpOutput streams are enforced.
+ */
+public class ResourceContentFactory implements Factory
+{
+    private final ResourceFactory _factory;
+    private final MimeTypes _mimeTypes;
+    private final boolean _gzip;
+    
+    /* ------------------------------------------------------------ */
+    public ResourceContentFactory(ResourceFactory factory, MimeTypes mimeTypes, boolean gzip)
+    {
+        _factory=factory;
+        _mimeTypes=mimeTypes;
+        _gzip=gzip;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public HttpContent getContent(String pathInContext,int maxBufferSize)
+        throws IOException
+    {
+        // try loading the content from our factory.
+        Resource resource=_factory.getResource(pathInContext);
+        HttpContent loaded = load(pathInContext,resource,maxBufferSize);
+        return loaded;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    private HttpContent load(String pathInContext, Resource resource, int maxBufferSize)
+        throws IOException
+    {   
+        if (resource==null || !resource.exists())
+            return null;
+        
+        if (resource.isDirectory())
+            return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),maxBufferSize);
+        
+        // Look for a gzip resource or content
+        String mt = _mimeTypes.getMimeByExtension(pathInContext);
+        if (_gzip)
+        {
+            // Is there a gzip resource? 
+            String pathInContextGz=pathInContext+".gz";
+            Resource resourceGz=_factory.getResource(pathInContextGz);
+            if (resourceGz.exists() && resourceGz.lastModified()>=resource.lastModified() && resourceGz.length()<resource.length())
+                return new ResourceHttpContent(resource,mt,maxBufferSize,
+                       new ResourceHttpContent(resourceGz,_mimeTypes.getMimeByExtension(pathInContextGz),maxBufferSize));
+        }
+        
+        return new ResourceHttpContent(resource,mt,maxBufferSize);
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return "ResourceContentFactory["+_factory+"]@"+hashCode();
+    }
+    
+
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
index 3f5ca27..0ece821 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.server;
 
-import static org.eclipse.jetty.util.QuotedStringTokenizer.isQuoted;
-
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.channels.IllegalSelectorException;
@@ -43,17 +41,19 @@
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpHeaderValue;
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.PreEncodedHttpField;
 import org.eclipse.jetty.io.RuntimeIOException;
 import org.eclipse.jetty.server.handler.ErrorHandler;
 import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.Jetty;
 import org.eclipse.jetty.util.QuotedStringTokenizer;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.URIUtil;
@@ -69,6 +69,7 @@
     private static final String __COOKIE_DELIM="\",;\\ \t";
     private final static String __01Jan1970_COOKIE = DateGenerator.formatCookieDate(0).trim();
     private final static int __MIN_BUFFER_SIZE = 1;
+    private final static HttpField __EXPIRES_01JAN1970 = new PreEncodedHttpField(HttpHeader.EXPIRES,DateGenerator.__01Jan1970);
     
 
     // Cookie building buffer. Reduce garbage for cookie using applications
@@ -80,15 +81,6 @@
           return new StringBuilder(128);
        }
     };
-
-    /* ------------------------------------------------------------ */
-    public static Response getResponse(HttpServletResponse response)
-    {
-        if (response instanceof Response)
-            return (Response)response;
-        return HttpChannel.getCurrentHttpChannel().getResponse();
-    }
-    
     
     public enum OutputType
     {
@@ -108,10 +100,10 @@
      */
     public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__";
 
-    private final HttpChannel<?> _channel;
+    private final HttpChannel _channel;
     private final HttpFields _fields = new HttpFields();
     private final AtomicInteger _include = new AtomicInteger();
-    private HttpOutput _out;
+    private final HttpOutput _out;
     private int _status = HttpStatus.OK_200;
     private String _reason;
     private Locale _locale;
@@ -124,13 +116,13 @@
     private long _contentLength = -1;
     
 
-    public Response(HttpChannel<?> channel, HttpOutput out)
+    public Response(HttpChannel channel, HttpOutput out)
     {
         _channel = channel;
         _out = out;
     }
 
-    protected HttpChannel<?> getHttpChannel()
+    public HttpChannel getHttpChannel()
     {
         return _channel;
     }
@@ -145,45 +137,15 @@
         _contentType = null;
         _outputType = OutputType.NONE;
         _contentLength = -1;
-        _out.reset();
+        _out.recycle();
         _fields.clear();
         _explicitEncoding=false;
     }
-
-    public void setHeaders(HttpContent httpContent)
-    {
-        Response response = _channel.getResponse();
-        String contentType = httpContent.getContentType();
-        if (contentType != null && !response.getHttpFields().containsKey(HttpHeader.CONTENT_TYPE.asString()))
-            setContentType(contentType);
-        
-        if (httpContent.getContentLength() > 0)
-            setLongContentLength(httpContent.getContentLength());
-
-        String lm = httpContent.getLastModified();
-        if (lm != null)
-            response.getHttpFields().put(HttpHeader.LAST_MODIFIED, lm);
-        else if (httpContent.getResource() != null)
-        {
-            long lml = httpContent.getResource().lastModified();
-            if (lml != -1)
-                response.getHttpFields().putDateField(HttpHeader.LAST_MODIFIED, lml);
-        }
-
-        String etag=httpContent.getETag();
-        if (etag!=null)
-            response.getHttpFields().put(HttpHeader.ETAG,etag);
-    }
     
     public HttpOutput getHttpOutput()
     {
         return _out;
     }
-    
-    public void setHttpOutput(HttpOutput out)
-    {
-        _out=out;
-    }
 
     public boolean isIncluding()
     {
@@ -256,7 +218,7 @@
      * @param domain the domain
      * @param path the path
      * @param maxAge the maximum age
-     * @param comment the comment (only present on versions > 0)
+     * @param comment the comment (only present on versions &gt; 0)
      * @param isSecure true if secure cookie
      * @param isHttpOnly true if for http only
      * @param version version of cookie logic to use (0 == default behavior)
@@ -300,7 +262,9 @@
         boolean quote_path = has_path && isQuoteNeededForCookie(path);
         
         // Upgrade the version if we have a comment or we need to quote value/path/domain or if they were already quoted
-        if (version==0 && ( comment!=null || quote_name || quote_value || quote_domain || quote_path || isQuoted(name) || isQuoted(value) || isQuoted(path) || isQuoted(domain)))
+        if (version==0 && ( comment!=null || quote_name || quote_value || quote_domain || quote_path ||
+                QuotedStringTokenizer.isQuoted(name) || QuotedStringTokenizer.isQuoted(value) ||
+                QuotedStringTokenizer.isQuoted(path) || QuotedStringTokenizer.isQuoted(domain)))
             version=1;
 
         // Append version
@@ -377,7 +341,7 @@
         _fields.add(HttpHeader.SET_COOKIE.toString(), buf.toString());
 
         // Expire responses with set-cookie headers so they do not get cached.
-        _fields.put(HttpHeader.EXPIRES.toString(), DateGenerator.__01Jan1970);
+        _fields.put(__EXPIRES_01JAN1970);
     }
 
 
@@ -440,9 +404,13 @@
             int port = uri.getPort();
             if (port < 0)
                 port = HttpScheme.HTTPS.asString().equalsIgnoreCase(uri.getScheme()) ? 443 : 80;
-            if (!request.getServerName().equalsIgnoreCase(uri.getHost()) ||
-                    request.getServerPort() != port ||
-                    !path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts
+            
+            // Is it the same server?
+            if (!request.getServerName().equalsIgnoreCase(uri.getHost()))
+                return url;
+            if (request.getServerPort() != port)
+                return url;
+            if (!path.startsWith(request.getContextPath())) //TODO the root context path is "", with which every non null string starts
                 return url;
         }
 
@@ -550,10 +518,17 @@
         if (isIncluding())
             return;
 
+        if (isCommitted())
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Aborting on sendError on committed response {} {}",code,message);
+            code=-1;
+        }
+        
         switch(code)
         {
             case -1:
-                _channel.abort();
+                _channel.abort(new IOException());
                 return;
             case 102:
                 sendProcessing();
@@ -619,7 +594,9 @@
                     writer.write(". Reason:\n<pre>    ");
                     writer.write(message);
                     writer.write("</pre>");
-                    writer.write("</p>\n<hr /><i><small>Powered by Jetty://</small></i>");
+                    writer.write("</p>\n<hr />");
+
+                    getHttpChannel().getHttpConfiguration().writePoweredBy(writer,null,"<hr/>");
                     writer.write("\n</body>\n</html>\n");
 
                     writer.flush();
@@ -650,6 +627,7 @@
      * request has a Expect header starting with 102, then a 102 response is
      * sent. This indicates that the request still be processed and real response
      * can still be sent.   This method is called by sendError if it is passed 102.
+     * @throws IOException if unable to send the 102 response
      * @see javax.servlet.http.HttpServletResponse#sendError(int)
      */
     public void sendProcessing() throws IOException
@@ -662,9 +640,9 @@
     
     /**
      * Sends a response with one of the 300 series redirection codes.
-     * @param code
-     * @param location
-     * @throws IOException
+     * @param code the redirect status code
+     * @param location the location to send in <code>Location</code> headers
+     * @throws IOException if unable to send the redirect
      */
     public void sendRedirect(int code, String location) throws IOException
     {
@@ -784,7 +762,7 @@
     @Override
     public String getHeader(String name)
     {
-        return _fields.getStringField(name);
+        return _fields.get(name);
     }
 
     @Override
@@ -844,7 +822,7 @@
                 _contentLength = value;
         }
     }
-
+    
     @Override
     public void setStatus(int sc)
     {
@@ -916,7 +894,7 @@
             if (encoding == null)
             {
                 if (_mimeType!=null && _mimeType.isCharsetAssumed())
-                    encoding=_mimeType.getCharset().toString();
+                    encoding=_mimeType.getCharsetString();
                 else
                 {
                     encoding = MimeTypes.inferCharsetFromContentType(_contentType);
@@ -926,16 +904,18 @@
                 }
             }
             
-            if (_writer != null && _writer.isFor(encoding))
+            Locale locale = getLocale();
+            
+            if (_writer != null && _writer.isFor(locale,encoding))
                 _writer.reopen();
             else
             {
                 if (StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
-                    _writer = new ResponseWriter(new Iso88591HttpWriter(_out),encoding);
+                    _writer = new ResponseWriter(new Iso88591HttpWriter(_out),locale,encoding);
                 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
-                    _writer = new ResponseWriter(new Utf8HttpWriter(_out),encoding);
+                    _writer = new ResponseWriter(new Utf8HttpWriter(_out),locale,encoding);
                 else
-                    _writer = new ResponseWriter(new EncodingHttpWriter(_out, encoding),encoding);
+                    _writer = new ResponseWriter(new EncodingHttpWriter(_out, encoding),locale,encoding);
             }
             
             // Set the output type at the end, because setCharacterEncoding() checks for it
@@ -1075,7 +1055,7 @@
                 _characterEncoding = HttpGenerator.__STRICT?encoding:StringUtil.normalizeCharset(encoding);
                 if (_mimeType!=null)
                 {
-                    _contentType=_mimeType.getBaseType().asString()+ "; charset=" + _characterEncoding;
+                    _contentType=_mimeType.getBaseType().asString()+ ";charset=" + _characterEncoding;
                     _mimeType = MimeTypes.CACHE.get(_contentType);
                     if (_mimeType==null || HttpGenerator.__STRICT)
                         _fields.put(HttpHeader.CONTENT_TYPE, _contentType);
@@ -1084,13 +1064,13 @@
                 }
                 else if (_contentType != null)
                 {
-                    _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + "; charset=" + _characterEncoding;
+                    _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType) + ";charset=" + _characterEncoding;
                     _fields.put(HttpHeader.CONTENT_TYPE, _contentType);
                 }
             }
         }
     }
-
+    
     @Override
     public void setContentType(String contentType)
     {
@@ -1115,7 +1095,7 @@
             
             String charset;
             if (_mimeType!=null && _mimeType.getCharset()!=null && !_mimeType.isCharsetAssumed())
-                charset=_mimeType.getCharset().toString();
+                charset=_mimeType.getCharsetString();
             else
                 charset = MimeTypes.getCharsetFromContentType(contentType);
 
@@ -1123,17 +1103,17 @@
             {
                 if (_characterEncoding != null)
                 {
-                    _contentType = contentType + "; charset=" + _characterEncoding;
+                    _contentType = contentType + ";charset=" + _characterEncoding;
                     _mimeType = null;
                 }
             }
-            else if (isWriting() && !charset.equals(_characterEncoding))
+            else if (isWriting() && !charset.equalsIgnoreCase(_characterEncoding))
             {
                 // too late to change the character encoding;
                 _mimeType = null;
                 _contentType = MimeTypes.getContentTypeWithoutCharset(_contentType);
                 if (_characterEncoding != null)
-                    _contentType = _contentType + "; charset=" + _characterEncoding;
+                    _contentType = _contentType + ";charset=" + _characterEncoding;
             }
             else
             {
@@ -1184,7 +1164,8 @@
         _contentLength = -1;
         _fields.clear();
 
-        String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION);
+        String connection = _channel.getRequest().getHeader(HttpHeader.CONNECTION.asString());
+                
         if (connection != null)
         {
             for (String value: StringUtil.csvSplit(null,connection,0,connection.length()))
@@ -1241,21 +1222,28 @@
         if (isCommitted())
             throw new IllegalStateException("Committed");
 
-        switch (_outputType)
-        {
-            case STREAM:
-            case WRITER:
-                _out.reset();
-                break;
-            default:
-        }
-
         _out.resetBuffer();
     }
 
-    protected ResponseInfo newResponseInfo()
+    protected MetaData.Response newResponseMetaData()
     {
-        return new ResponseInfo(_channel.getRequest().getHttpVersion(), _fields, getLongContentLength(), getStatus(), getReason(), _channel.getRequest().isHead());
+        return new MetaData.Response(_channel.getRequest().getHttpVersion(), getStatus(), getReason(), _fields, getLongContentLength());
+    }
+    
+    /** Get the MetaData.Response committed for this response.
+     * This may differ from the meta data in this response for 
+     * exceptional responses (eg 4xx and 5xx responses generated
+     * by the container) and the committedMetaData should be used 
+     * for logging purposes.
+     * @return The committed MetaData or a {@link #newResponseMetaData()}
+     * if not yet committed.
+     */
+    public MetaData.Response getCommittedMetaData()
+    {
+        MetaData.Response meta = _channel.getCommittedMetaData();
+        if (meta==null)
+            return newResponseMetaData();
+        return meta;
     }
 
     @Override
@@ -1321,27 +1309,73 @@
     }
     
 
-    private static class ResponseWriter extends PrintWriter
+    public void putHeaders(HttpContent content,long contentLength, boolean etag)
     {
-        private final String _encoding;
-        private final HttpWriter _httpWriter;
-        
-        public ResponseWriter(HttpWriter httpWriter,String encoding)
+        HttpField lm = content.getLastModified();
+        if (lm!=null)
+            _fields.put(lm);
+
+        if (contentLength==0)
         {
-            super(httpWriter);
-            _httpWriter=httpWriter;
-            _encoding=encoding;
+            _fields.put(content.getContentLength());
+            _contentLength=content.getContentLengthValue();
+        }
+        else if (contentLength>0)
+        {
+            _fields.putLongField(HttpHeader.CONTENT_LENGTH,contentLength);
+            _contentLength=contentLength;
         }
 
-        public boolean isFor(String encoding)
+        HttpField ct=content.getContentType();
+        if (ct!=null)
         {
-            return _encoding.equalsIgnoreCase(encoding);
+            _fields.put(ct);
+            _contentType=ct.getValue();
+            _characterEncoding=content.getCharacterEncoding();
+            _mimeType=content.getMimeType();
         }
         
-        protected void reopen()
+        HttpField ce=content.getContentEncoding();
+        if (ce!=null)
+            _fields.put(ce);
+        
+        if (etag)
         {
-            super.clearError();
-            out=_httpWriter;
+            HttpField et = content.getETag();
+            if (et!=null)
+                _fields.put(et);
+        }
+    }
+    
+    public static void putHeaders(HttpServletResponse response, HttpContent content, long contentLength, boolean etag)
+    {   
+        long lml=content.getResource().lastModified();
+        if (lml>=0)
+            response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),lml);
+
+        if (contentLength==0)
+            contentLength=content.getContentLengthValue();
+        if (contentLength >=0)
+        {
+            if (contentLength<Integer.MAX_VALUE)
+                response.setContentLength((int)contentLength);
+            else
+                response.setHeader(HttpHeader.CONTENT_LENGTH.asString(),Long.toString(contentLength));
+        }
+
+        String ct=content.getContentTypeValue();
+        if (ct!=null && response.getContentType()==null)
+            response.setContentType(ct);
+
+        String ce=content.getContentEncodingValue();
+        if (ce!=null)
+            response.setHeader(HttpHeader.CONTENT_ENCODING.asString(),ce);
+        
+        if (etag)
+        {
+            String et=content.getETagValue();
+            if (et!=null)
+                response.setHeader(HttpHeader.ETAG.asString(),et);
         }
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java
new file mode 100644
index 0000000..8b131d4
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java
@@ -0,0 +1,481 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.PrintWriter;
+import java.util.Formatter;
+import java.util.Locale;
+
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.io.RuntimeIOException;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** Specialized PrintWriter for servlet Responses
+ * <p>An instance of ResponseWriter is the {@link PrintWriter} subclass returned by {@link Response#getWriter()}.
+ * It differs from the standard {@link PrintWriter} in that:<ul>
+ * <li>It does not support autoflush</li>
+ * <li>The default Locale for {@link #format(String, Object...)} is the locale obtained by {@link ServletResponse#getLocale()}</li>
+ * <li>If a write or print method is called while {@link #checkError()}  returns true, then a {@link RuntimeIOException} is thrown to stop needless iterations.</li>
+ * <li>The writer may be reopen to allow for recycling</li>
+ * </ul>
+ * 
+ */
+public class ResponseWriter extends PrintWriter
+{
+    private static final Logger LOG = Log.getLogger(ResponseWriter.class);
+    private final static String __lineSeparator = System.getProperty("line.separator");
+    private final static String __trueln = "true"+__lineSeparator;
+    private final static String __falseln = "false"+__lineSeparator;
+    
+    private final HttpWriter _httpWriter;
+    private final Locale _locale;
+    private final String _encoding;
+    private IOException _ioException;
+    private boolean _isClosed = false;
+    private Formatter _formatter;
+
+    public ResponseWriter(HttpWriter httpWriter,Locale locale,String encoding)
+    {
+        super(httpWriter,false);
+        _httpWriter=httpWriter;
+        _locale=locale;
+        _encoding=encoding;
+    }
+
+    public boolean isFor(Locale locale, String encoding)
+    {
+        if (_locale==null && locale!=null)
+            return false;
+        if (_encoding==null && encoding!=null)
+            return false;
+        return _encoding.equalsIgnoreCase(encoding) && _locale.equals(locale);
+    }
+
+    protected void reopen()
+    {
+        synchronized (lock)
+        {
+            _isClosed=false;
+            clearError();
+            out=_httpWriter;
+        }
+    }
+
+    @Override
+    protected void clearError()
+    {
+        synchronized (lock)
+        {
+            _ioException=null;
+            super.clearError();
+        }
+    }
+    
+    @Override
+    public boolean checkError()
+    {
+        synchronized (lock)
+        {
+            return _ioException!=null || super.checkError();
+        }
+    }
+    
+    private void setError(Throwable th)
+    {
+        super.setError();
+
+        if (th instanceof IOException)
+            _ioException=(IOException)th;
+        else
+        {
+            _ioException=new IOException(String.valueOf(th));
+            _ioException.initCause(th);
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug(th);
+    }
+
+
+    @Override
+    protected void setError()
+    {
+        setError(new IOException());
+    }
+
+    /** Check to make sure that the stream has not been closed */
+    private void isOpen() throws IOException
+    {       
+        if (_ioException!=null)
+            throw new RuntimeIOException(_ioException); 
+        
+        if (_isClosed)
+            throw new EofException("Stream closed");
+    }
+
+    @Override
+    public void flush()
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.flush();
+            }
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void close()
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                out.close();
+                _isClosed = true;
+            }
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void write(int c)
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(c);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+    
+    @Override
+    public void write(char buf[], int off, int len)
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(buf,off,len);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void write(char buf[])
+    { 
+        this.write(buf,0,buf.length);
+    }
+
+    @Override
+    public void write(String s, int off, int len)
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(s,off,len);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void write(String s)
+    {
+        this.write(s,0,s.length());
+    }
+
+    @Override
+    public void print(boolean b)
+    {
+        this.write(b?"true":"false");
+    }
+    
+    @Override
+    public void print(char c)
+    {
+        this.write(c);
+    }
+
+    @Override
+    public void print(int i)
+    {
+        this.write(String.valueOf(i));
+    }
+
+    @Override
+    public void print(long l)
+    {
+        this.write(String.valueOf(l));
+    }
+
+    @Override
+    public void print(float f)
+    {
+        this.write(String.valueOf(f));
+    }
+
+    @Override
+    public void print(double d)
+    {
+        this.write(String.valueOf(d));
+    }
+
+    @Override
+    public void print(char s[])
+    {
+        this.write(s);
+    }
+
+    @Override
+    public void print(String s)
+    {
+        if (s == null)
+            s = "null";
+        this.write(s);
+    }
+
+    @Override
+    public void print(Object obj)
+    {
+        this.write(String.valueOf(obj));
+    }
+
+    @Override
+    public void println()
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(__lineSeparator);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void println(boolean b)
+    {
+        println(b?__trueln:__falseln);
+    }
+
+    @Override
+    public void println(char c)
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(c);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void println(int x)
+    {
+        this.println(String.valueOf(x));
+    }
+
+    @Override
+    public void println(long x)
+    {
+        this.println(String.valueOf(x));
+    }
+    
+    @Override
+    public void println(float x)
+    {
+        this.println(String.valueOf(x));
+    }
+
+    @Override
+    public void println(double x)
+    {
+        this.println(String.valueOf(x));
+    }
+
+    @Override
+    public void println(char s[])
+    {
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(s,0,s.length);
+                out.write(__lineSeparator);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void println(String s)
+    {
+        if (s == null)
+            s = "null";
+        
+        try
+        {
+            synchronized (lock)
+            {
+                isOpen();
+                out.write(s,0,s.length());
+                out.write(__lineSeparator);
+            }
+        }
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+    }
+
+    @Override
+    public void println(Object x)
+    {
+        this.println(String.valueOf(x));
+    }
+
+    @Override
+    public PrintWriter printf(String format, Object... args)
+    {
+        return format(_locale,format,args);
+    }
+
+    @Override
+    public PrintWriter printf(Locale l, String format, Object... args)
+    {
+        return format(l,format,args);
+    }
+
+    @Override
+    public PrintWriter format(String format, Object... args)
+    {
+        return format(_locale,format,args);
+    }
+
+    @Override
+    public PrintWriter format(Locale l, String format, Object... args)
+    { 
+        try 
+        {
+            synchronized (lock) 
+            {
+                isOpen();
+                if ((_formatter == null) || (_formatter.locale() != l))
+                    _formatter = new Formatter(this, l);
+                _formatter.format(l, format, args);
+            }
+        } 
+        catch (InterruptedIOException ex)
+        {
+            LOG.debug(ex);
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException ex)
+        {
+            setError(ex);
+        }
+        return this;
+    }
+
+    
+    
+}
\ No newline at end of file
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
index dc6cf79..61cf47c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java
@@ -19,75 +19,222 @@
 package org.eclipse.jetty.server;
 
 import java.security.cert.X509Certificate;
+import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLSession;
 import javax.servlet.ServletRequest;
 
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.http.PreEncodedHttpField;
 import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
 import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.annotation.Name;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.ssl.SniX509ExtendedKeyManager;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.ssl.X509;
 
-
-/* ------------------------------------------------------------ */
-/** Customizer that extracts the attribute from an {@link SSLContext}
+/**
+ * <p>Customizer that extracts the attribute from an {@link SSLContext}
  * and sets them on the request with {@link ServletRequest#setAttribute(String, Object)}
- * according to Servlet Specification Requirements.
+ * according to Servlet Specification Requirements.</p>
  */
 public class SecureRequestCustomizer implements HttpConfiguration.Customizer
 {
     private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class);
-    
+
     /**
      * The name of the SSLSession attribute that will contain any cached information.
      */
     public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
 
+    private boolean _sniHostCheck;
+    private long _stsMaxAge=-1;
+    private boolean _stsIncludeSubDomains;
+    private HttpField _stsField;
+
+    public SecureRequestCustomizer()
+    {
+        this(true);
+    }
+
+    public SecureRequestCustomizer(@Name("sniHostCheck")boolean sniHostCheck)
+    {
+        this(sniHostCheck,-1,false);
+    }
+    
+    /**
+     * @param sniHostCheck True if the SNI Host name must match.
+     * @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
+     * @param stsIncludeSubdomains If true, a include subdomain property is sent with any Strict-Transport-Security header
+     */
+    public SecureRequestCustomizer(
+            @Name("sniHostCheck")boolean sniHostCheck,
+            @Name("stsMaxAgeSeconds")long stsMaxAgeSeconds,
+            @Name("stsIncludeSubdomains")boolean stsIncludeSubdomains)
+    {
+        _sniHostCheck=sniHostCheck;
+        _stsMaxAge=stsMaxAgeSeconds;
+        _stsIncludeSubDomains=stsIncludeSubdomains;
+        formatSTS();
+    }
+
+    /**
+     * @return True if the SNI Host name must match.
+     */
+    public boolean isSniHostCheck()
+    {
+        return _sniHostCheck;
+    }
+
+    /**
+     * @param sniHostCheck  True if the SNI Host name must match. 
+     */
+    public void setSniHostCheck(boolean sniHostCheck)
+    {
+        _sniHostCheck = sniHostCheck;
+    }
+
+    /**
+     * @return The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
+     */
+    public long getStsMaxAge()
+    {
+        return _stsMaxAge;
+    }
+
+    /**
+     * Set the Strict-Transport-Security max age.
+     * @param stsMaxAgeSeconds The max age in seconds for a Strict-Transport-Security response header. If set less than zero then no header is sent.
+     */
+    public void setStsMaxAge(long stsMaxAgeSeconds)
+    {
+        _stsMaxAge = stsMaxAgeSeconds;
+        formatSTS();
+    }
+
+    /**
+     * Convenience method to call {@link #setStsMaxAge(long)}
+     * @param period The period in units
+     * @param units The {@link TimeUnit} of the period
+     */
+    public void setStsMaxAge(long period,TimeUnit units)
+    {
+        _stsMaxAge = units.toSeconds(period);
+        formatSTS();
+    }
+
+    /**
+     * @return true if a include subdomain property is sent with any Strict-Transport-Security header
+     */
+    public boolean isStsIncludeSubDomains()
+    {
+        return _stsIncludeSubDomains;
+    }
+
+    /**
+     * @param stsIncludeSubDomains If true, a include subdomain property is sent with any Strict-Transport-Security header
+     */
+    public void setStsIncludeSubDomains(boolean stsIncludeSubDomains)
+    {
+        _stsIncludeSubDomains = stsIncludeSubDomains;
+        formatSTS();
+    }
+
+    private void formatSTS()
+    {
+        if (_stsMaxAge<0)
+            _stsField=null;
+        else
+            _stsField=new PreEncodedHttpField(HttpHeader.STRICT_TRANSPORT_SECURITY,String.format("max-age=%d%s",_stsMaxAge,_stsIncludeSubDomains?"; includeSubDomains":""));
+    }
+
     @Override
     public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
     {
         if (request.getHttpChannel().getEndPoint() instanceof DecryptedEndPoint)
         {
-            request.setScheme(HttpScheme.HTTPS.asString());
-            request.setSecure(true);
+            
+            if (request.getHttpURI().getScheme()==null)
+                request.setScheme(HttpScheme.HTTPS.asString());
+            
             SslConnection.DecryptedEndPoint ssl_endp = (DecryptedEndPoint)request.getHttpChannel().getEndPoint();
             SslConnection sslConnection = ssl_endp.getSslConnection();
             SSLEngine sslEngine=sslConnection.getSSLEngine();
             customize(sslEngine,request);
         }
+
+        if (HttpScheme.HTTPS.is(request.getScheme()))
+            customizeSecure(request);
     }
 
-    /* ------------------------------------------------------------ */
-    /*
-     * Customise the request attributes to be set for SSL requests. <br>
-     * The requirements of the Servlet specs are:
-     * <ul>
-     * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
-     * String (since Servlet Spec 3.0).</li>
-     * <li> an attribute named "javax.servlet.request.cipher_suite" of type
-     * String.</li>
-     * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
-     * <li> an attribute named "javax.servlet.request.X509Certificate" of type
-     * java.security.cert.X509Certificate[]. This is an array of objects of type
-     * X509Certificate, the order of this array is defined as being in ascending
-     * order of trust. The first certificate in the chain is the one set by the
-     * client, the next is the one used to authenticate the first, and so on.
-     * </li>
-     * </ul>
-     *
-     * @param request
-     *                HttpRequest to be customised.
+
+    /**
+     * <p>
+     * Customizes the request attributes for general secure settings.
+     * The default impl calls {@link Request#setSecure(boolean)} with true
+     * and sets a response header if the Strict-Transport-Security options 
+     * are set.
+     * </p>
      */
-    public void customize(SSLEngine sslEngine, Request request)
+    protected void customizeSecure(Request request)
+    {
+        request.setSecure(true);
+        
+        if (_stsField!=null)
+            request.getResponse().getHttpFields().add(_stsField);
+    }
+    
+    
+    /**
+     * <p>
+     * Customizes the request attributes to be set for SSL requests.
+     * </p>
+     * <p>
+     * The requirements of the Servlet specs are:
+     * </p>
+     * <ul>
+     * <li>an attribute named "javax.servlet.request.ssl_session_id" of type String (since Servlet Spec 3.0).</li>
+     * <li>an attribute named "javax.servlet.request.cipher_suite" of type String.</li>
+     * <li>an attribute named "javax.servlet.request.key_size" of type Integer.</li>
+     * <li>an attribute named "javax.servlet.request.X509Certificate" of type java.security.cert.X509Certificate[]. This
+     * is an array of objects of type X509Certificate, the order of this array is defined as being in ascending order of
+     * trust. The first certificate in the chain is the one set by the client, the next is the one used to authenticate
+     * the first, and so on.</li>
+     * </ul>
+     * 
+     * @param sslEngine
+     *            the sslEngine to be customized.
+     * @param request
+     *            HttpRequest to be customized.
+     */
+    protected void customize(SSLEngine sslEngine, Request request)
     {
         request.setScheme(HttpScheme.HTTPS.asString());
         SSLSession sslSession = sslEngine.getSession();
 
+        if (_sniHostCheck)
+        {
+            String name = request.getServerName();
+            X509 x509 = (X509)sslSession.getValue(SniX509ExtendedKeyManager.SNI_X509);
+
+            if (x509!=null && !x509.matches(name))
+            {
+                LOG.warn("Host {} does not match SNI {}",name,x509);
+                throw new BadMessageException(400,"Host does not match SNI");
+            }
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Host {} matched SNI {}",name,x509);
+        }
+
         try
         {
             String cipherSuite=sslSession.getCipherSuite();
@@ -102,9 +249,9 @@
                 certs=cachedInfo.getCerts();
                 idStr=cachedInfo.getIdStr();
             }
-            else 
+            else
             {
-                keySize=new Integer(SslContextFactory.deduceKeyLength(cipherSuite));
+                keySize=SslContextFactory.deduceKeyLength(cipherSuite);
                 certs=SslContextFactory.getCertChain(sslSession);
                 byte[] bytes = sslSession.getId();
                 idStr = TypeUtil.toHexString(bytes);
@@ -130,10 +277,7 @@
     {
         return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
     }
-    
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
+
     /**
      * Simple bundle of information that is cached in the SSLSession. Stores the
      * effective keySize and the client certificate chain.
@@ -166,7 +310,4 @@
             return _idStr;
         }
     }
-
-
-
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
index ba0655e..1d81e6a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java
@@ -44,6 +44,7 @@
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.PreEncodedHttpField;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.handler.StatisticsHandler;
@@ -60,6 +61,7 @@
 import org.eclipse.jetty.util.component.LifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.Locker;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.eclipse.jetty.util.thread.ShutdownThread;
 import org.eclipse.jetty.util.thread.ThreadPool;
@@ -84,9 +86,12 @@
     private boolean _stopAtShutdown;
     private boolean _dumpAfterStart=false;
     private boolean _dumpBeforeStop=false;
-    
+    private RequestLog _requestLog;
+
+    private final Locker _dateLocker = new Locker();
     private volatile DateField _dateField;
-    
+
+
     /* ------------------------------------------------------------ */
     public Server()
     {
@@ -108,8 +113,11 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convenience constructor
+    /**
+     * Convenience constructor
+     * <p>
      * Creates server and a {@link ServerConnector} at the passed address.
+     * @param addr the inet socket address to create the connector from
      */
     public Server(@Name("address")InetSocketAddress addr)
     {
@@ -120,8 +128,6 @@
         setConnectors(new Connector[]{connector});
     }
 
-
-
     /* ------------------------------------------------------------ */
     public Server(@Name("threadpool") ThreadPool pool)
     {
@@ -130,6 +136,18 @@
         setServer(this);
     }
 
+    /* ------------------------------------------------------------ */
+    public RequestLog getRequestLog()
+    {
+        return _requestLog;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setRequestLog(RequestLog requestLog)
+    {
+        updateBean(_requestLog,requestLog);
+        _requestLog = requestLog;
+    }
 
     /* ------------------------------------------------------------ */
     @ManagedAttribute("version of this server")
@@ -143,8 +161,8 @@
     {
         return _stopAtShutdown;
     }
-   
-    
+
+
     /* ------------------------------------------------------------ */
     /**
      * Set a graceful stop time.
@@ -291,15 +309,15 @@
         long now=System.currentTimeMillis();
         long seconds = now/1000;
         DateField df = _dateField;
-        
+
         if (df==null || df._seconds!=seconds)
         {
-            synchronized (this) // Trade some contention for less garbage
+            try(Locker.Lock lock = _dateLocker.lock())
             {
                 df = _dateField;
                 if (df==null || df._seconds!=seconds)
                 {
-                    HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.DATE,DateGenerator.formatDate(now));
+                    HttpField field=new PreEncodedHttpField(HttpHeader.DATE,DateGenerator.formatDate(now));
                     _dateField=new DateField(seconds,field);
                     return field;
                 }
@@ -320,7 +338,7 @@
         //Register the Server with the handler thread for receiving
         //remote stop commands
         ShutdownMonitor.register(this);
-        
+
         //Start a thread waiting to receive "stop" commands.
         ShutdownMonitor.getInstance().start(); // initialize
 
@@ -339,7 +357,7 @@
             {
                 if (connector instanceof AbstractConnector)
                     acceptors+=((AbstractConnector)connector).getAcceptors();
-                    
+
                 if (connector instanceof ServerConnector)
                     selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
             }
@@ -348,7 +366,7 @@
         int needed=1+selectors+acceptors;
         if (max>0 && needed>max)
             throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
-        
+
         try
         {
             super.doStart();
@@ -362,7 +380,7 @@
         for (Connector connector : _connectors)
         {
             try
-            {   
+            {
                 connector.start();
             }
             catch(Throwable e)
@@ -370,7 +388,7 @@
                 mex.add(e);
             }
         }
-        
+
         if (isDumpAfterStart())
             dumpStdErr();
 
@@ -394,6 +412,9 @@
         if (isDumpBeforeStop())
             dumpStdErr();
 
+        if (LOG.isDebugEnabled())
+            LOG.debug("doStop {}",this);
+        
         MultiException mex=new MultiException();
 
         // list if graceful futures
@@ -404,7 +425,6 @@
             futures.add(connector.shutdown());
 
         // Then tell the contexts that we are shutting down
-        
         Handler[] gracefuls = getChildHandlersByClass(Graceful.class);
         for (Handler graceful : gracefuls)
             futures.add(((Graceful)graceful).shutdown());
@@ -462,14 +482,12 @@
 
         if (getStopAtShutdown())
             ShutdownThread.deregister(this);
-        
+
         //Unregister the Server with the handler thread for receiving
         //remote stop commands as we are stopped already
         ShutdownMonitor.deregister(this);
-        
 
         mex.ifExceptionThrow();
-
     }
 
     /* ------------------------------------------------------------ */
@@ -478,14 +496,14 @@
      * or after the entire request has been received (for short requests of known length), or
      * on the dispatch of an async request.
      */
-    public void handle(HttpChannel<?> connection) throws IOException, ServletException
+    public void handle(HttpChannel connection) throws IOException, ServletException
     {
         final String target=connection.getRequest().getPathInfo();
         final Request request=connection.getRequest();
         final Response response=connection.getResponse();
 
         if (LOG.isDebugEnabled())
-            LOG.debug(request.getDispatcherType()+" "+request.getMethod()+" "+target+" on "+connection);
+            LOG.debug("{} on {}{}",request.getDispatcherType(),connection,"\n"+request.getMethod()+" "+request.getHttpURI()+"\n"+request.getHttpFields());
 
         if (HttpMethod.OPTIONS.is(request.getMethod()) || "*".equals(target))
         {
@@ -499,7 +517,7 @@
             handle(target, request, request, response);
 
         if (LOG.isDebugEnabled())
-            LOG.debug("RESPONSE "+target+"  "+connection.getResponse().getStatus()+" handled="+request.isHandled());
+            LOG.debug("RESPONSE for {} h={}{}",target,request.isHandled(),"\n"+response.getStatus()+" "+response.getReason()+"\n"+response.getHttpFields());
     }
 
     /* ------------------------------------------------------------ */
@@ -515,24 +533,24 @@
      * or after the entire request has been received (for short requests of known length), or
      * on the dispatch of an async request.
      */
-    public void handleAsync(HttpChannel<?> connection) throws IOException, ServletException
+    public void handleAsync(HttpChannel connection) throws IOException, ServletException
     {
         final HttpChannelState state = connection.getRequest().getHttpChannelState();
         final AsyncContextEvent event = state.getAsyncContextEvent();
 
         final Request baseRequest=connection.getRequest();
         final String path=event.getPath();
-        
+
         if (path!=null)
         {
             // this is a dispatch with a path
             ServletContext context=event.getServletContext();
-            HttpURI uri = new HttpURI(URIUtil.addPaths(context==null?null:context.getContextPath(), path));            
-            baseRequest.setUri(uri);
-            baseRequest.setRequestURI(null);
+            String query=baseRequest.getQueryString();
+            baseRequest.setURIPathQuery(URIUtil.addPaths(context==null?null:context.getContextPath(), path));
+            HttpURI uri = baseRequest.getHttpURI();
             baseRequest.setPathInfo(uri.getDecodedPath());
             if (uri.getQuery()!=null)
-                baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
+                baseRequest.mergeQueryParameters(query,uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
         }
 
         final String target=baseRequest.getPathInfo();
@@ -708,6 +726,6 @@
             _seconds = seconds;
             _dateField = dateField;
         }
-        
+
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java
index 2766a89..a805ba8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java
@@ -20,10 +20,12 @@
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
 import java.nio.channels.Channel;
 import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.util.concurrent.Executor;
@@ -32,9 +34,10 @@
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectorManager;
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
+import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.Name;
@@ -44,13 +47,12 @@
 /**
  * This {@link Connector} implementation is the primary connector for the
  * Jetty server over TCP/IP.  By the use of various {@link ConnectionFactory} instances it is able
- * to accept connections for HTTP, SPDY and WebSocket, either directly or over SSL.
+ * to accept connections for HTTP, HTTP/2 and WebSocket, either directly or over SSL.
  * <p>
  * The connector is a fully asynchronous NIO based implementation that by default will
  * use all the commons services (eg {@link Executor}, {@link Scheduler})  of the
  * passed {@link Server} instance, but all services may also be constructor injected
  * into the connector so that it may operate with dedicated or otherwise shared services.
- * <p>
  * <h2>Connection Factories</h2>
  * Various convenience constructors are provided to assist with common configurations of
  * ConnectionFactories, whose generic use is described in {@link AbstractConnector}.
@@ -58,7 +60,6 @@
  * default to use a {@link HttpConnectionFactory}.  If an non null {@link SslContextFactory}
  * instance is passed, then this used to instantiate a {@link SslConnectionFactory} which is
  * prepended to the other passed or default factories.
- * <p>
  * <h2>Selectors</h2>
  * The connector will use the {@link Executor} service to execute a number of Selector Tasks,
  * which are implemented to each use a NIO {@link Selector} instance to asynchronously
@@ -104,7 +105,7 @@
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      */
     public ServerConnector(
         @Name("server") Server server,
@@ -122,7 +123,7 @@
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      * @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
      */
     public ServerConnector(
@@ -171,7 +172,7 @@
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      */
     public ServerConnector(
         @Name("server") Server server,
@@ -194,7 +195,7 @@
         @Name("sslContextFactory") SslContextFactory sslContextFactory,
         @Name("factories") ConnectionFactory... factories)
     {
-        this(server,null,null,null,-1,-1,AbstractConnectionFactory.getFactories(sslContextFactory,factories));
+        this(server, null, null, null, -1, -1, AbstractConnectionFactory.getFactories(sslContextFactory, factories));
     }
 
     /** Generic Server Connection.
@@ -211,7 +212,7 @@
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or &lt;=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      * @param factories 
      *          Zero or more {@link ConnectionFactory} instances used to create and configure connections.
      */
@@ -225,9 +226,16 @@
         @Name("factories") ConnectionFactory... factories)
     {
         super(server,executor,scheduler,bufferPool,acceptors,factories);
-        _manager = new ServerConnectorManager(getExecutor(), getScheduler(), 
+        _manager = newSelectorManager(getExecutor(), getScheduler(),
             selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2)));
         addBean(_manager, true);
+        setSelectorPriorityDelta(-1);
+        setAcceptorPriorityDelta(-2);
+    }
+
+    protected SelectorManager newSelectorManager(Executor executor, Scheduler scheduler, int selectors)
+    {
+        return new ServerConnectorManager(executor, scheduler, selectors);
     }
 
     @Override
@@ -249,24 +257,21 @@
         return channel!=null && channel.isOpen();
     }
 
-
-    @ManagedAttribute("The priority delta to apply to selector threads")
+    /**
+     * @return the selector priority delta
+     * @deprecated not implemented
+     */
+    @Deprecated
     public int getSelectorPriorityDelta()
     {
         return _manager.getSelectorPriorityDelta();
     }
 
     /**
-     * Sets the selector thread priority delta to the given amount.
-     * <p>This allows the selector threads to run at a different priority.
-     * Typically this would be used to lower the priority to give preference 
-     * to handling previously accepted connections rather than accepting
-     * new connections.</p>
-     *
-     * @param selectorPriorityDelta the amount to set the thread priority delta to
-     *                              (may be negative)
-     * @see Thread#getPriority()
+     * @param selectorPriorityDelta the selector priority delta
+     * @deprecated not implemented
      */
+    @Deprecated
     public void setSelectorPriorityDelta(int selectorPriorityDelta)
     {
         _manager.setSelectorPriorityDelta(selectorPriorityDelta);
@@ -337,7 +342,7 @@
     @Override
     public Future<Void> shutdown()
     {
-        // TODO shutdown all the connections
+        // shutdown all the connections
         return super.shutdown();
     }
 
@@ -480,9 +485,9 @@
         _reuseAddress = reuseAddress;
     }
 
-    private final class ServerConnectorManager extends SelectorManager
+    protected class ServerConnectorManager extends SelectorManager
     {
-        private ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors)
+        public ServerConnectorManager(Executor executor, Scheduler scheduler, int selectors)
         {
             super(executor, scheduler, selectors);
         }
@@ -518,7 +523,5 @@
             onEndPointClosed(endpoint);
             super.endPointClosed(endpoint);
         }
-        
-        
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java
index 13e6c80..80946c6 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionIdManager.java
@@ -42,7 +42,7 @@
     
     /**
      * Remove session from the list of known sessions for a given ID.
-     * @param session
+     * @param session the session to remove
      */
     public void removeSession(HttpSession session);
     
@@ -53,8 +53,10 @@
     public void invalidateAll(String id);
     
     /**
-     * @param request
-     * @param created
+     * Create a new Session ID.
+     * 
+     * @param request the request with the sesion
+     * @param created the timestamp for when the session was created
      * @return the new session id
      */
     public String newSessionId(HttpServletRequest request,long created);
@@ -67,7 +69,7 @@
     /* ------------------------------------------------------------ */
     /** Get a cluster ID from a node ID.
      * Strip node identifier from a located session ID.
-     * @param nodeId
+     * @param nodeId the node id
      * @return the cluster id
      */
     public String getClusterId(String nodeId);
@@ -84,9 +86,9 @@
     /* ------------------------------------------------------------ */
     /** Change the existing session id.
     * 
-    * @param oldClusterId
-    * @param oldNodeId
-    * @param request
+    * @param oldClusterId the old cluster id
+    * @param oldNodeId the old node id
+    * @param request the request containing the session
     */
     public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request);    
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java
index d7f7f33..d2a10df 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java
@@ -23,6 +23,7 @@
 
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
+import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
@@ -307,10 +308,10 @@
     /* ------------------------------------------------------------ */
     /** Change the existing session id.
     * 
-    * @param oldClusterId
-    * @param oldNodeId
-    * @param newClusterId
-    * @param newNodeId
+    * @param oldClusterId the old cluster id
+    * @param oldNodeId the old node id
+    * @param newClusterId the new cluster id
+    * @param newNodeId the new node id
     */
     public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId);  
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
index d49b288..7fbd20a 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
@@ -259,7 +259,7 @@
          * Stop the registered lifecycles, optionally
          * calling destroy on them.
          * 
-         * @param destroy
+         * @param destroy true if {@link Destroyable}'s should also be destroyed.
          */
         public void stopLifeCycles (boolean destroy)
         {
@@ -448,7 +448,7 @@
     }
 
     /**
-     * @param exitVm
+     * @param exitVm true to exit the VM on shutdown
      */
     public void setExitVm(boolean exitVm)
     {
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java
index 3630f3a..aea0602 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Slf4jRequestLog.java
@@ -27,7 +27,7 @@
  * Implementation of NCSARequestLog where output is sent as a SLF4J INFO Log message on the named logger "org.eclipse.jetty.server.RequestLog"
  */
 @ManagedObject("NCSA standard format request log to slf4j bridge")
-public class Slf4jRequestLog extends AbstractNCSARequestLog implements RequestLog
+public class Slf4jRequestLog extends AbstractNCSARequestLog
 {
     private Slf4jLog logger;
     private String loggerName;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SocketCustomizationListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SocketCustomizationListener.java
new file mode 100644
index 0000000..0ee58e4
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SocketCustomizationListener.java
@@ -0,0 +1,97 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.net.Socket;
+
+import org.eclipse.jetty.io.ChannelEndPoint;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.Connection.Listener;
+import org.eclipse.jetty.io.ssl.SslConnection;
+import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
+import org.eclipse.jetty.io.EndPoint;
+
+
+/* ------------------------------------------------------------ */
+/** 
+ * A Connection Lister for customization of SocketConnections.
+ * <p>
+ * Instances of this listener may be added to a {@link Connector} (or 
+ * {@link ConnectionFactory}) so that they are applied to all connections
+ * for that connector (or protocol) and thus allow additional Socket
+ * configuration to be applied by implementing {@link #customize(Socket, Class, boolean)}
+ */
+public class SocketCustomizationListener implements Listener
+{
+    private final boolean _ssl;
+    
+    /**
+     * Construct with SSL unwrapping on.
+     */
+    public SocketCustomizationListener()
+    {
+        this(true);
+    }
+    
+    /**
+     * @param ssl If True, then a Socket underlying an SSLConnection is unwrapped
+     * and notified.
+     */
+    public SocketCustomizationListener(boolean ssl)
+    {
+        _ssl=ssl;
+    }
+
+    @Override
+    public void onOpened(Connection connection)
+    {
+        EndPoint endp = connection.getEndPoint();
+        boolean ssl=false;
+        
+        if (_ssl && endp instanceof DecryptedEndPoint)
+        {
+            endp = ((DecryptedEndPoint)endp).getSslConnection().getEndPoint();
+            ssl=true;
+        }
+        
+        if (endp instanceof ChannelEndPoint) 
+        {
+            Socket socket = ((ChannelEndPoint)endp).getSocket();
+            customize(socket,connection.getClass(),ssl);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /** This method may be extended to configure a socket on open 
+     * events.
+     * @param socket The Socket to configure
+     * @param connection The class of the connection (The socket may be wrapped
+     * by an {@link SslConnection} prior to this connection).
+     * @param ssl True if the socket is wrapped with an SslConnection
+     */
+    protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+    {
+    }
+
+    @Override
+    public void onClosed(Connection connection)
+    {
+    }
+
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java
index eafa594..680288c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SslConnectionFactory.java
@@ -47,7 +47,7 @@
 
     public SslConnectionFactory(@Name("sslContextFactory") SslContextFactory factory, @Name("next") String nextProtocol)
     {
-        super("SSL-"+nextProtocol);
+        super("SSL");
         _sslContextFactory=factory==null?new SslContextFactory():factory;
         _nextProtocol=nextProtocol;
         addBean(_sslContextFactory);
@@ -97,6 +97,7 @@
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s}",this.getClass().getSimpleName(),hashCode(),getProtocol());
+        return String.format("%s@%x{%s->%s}",this.getClass().getSimpleName(),hashCode(),getProtocol(),_nextProtocol);
     }
+
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java b/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java
index 3b67f2c..b6f6790 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/UserIdentity.java
@@ -23,13 +23,12 @@
 
 import javax.security.auth.Subject;
 
-/* ------------------------------------------------------------ */
-/** User object that encapsulates user identity and operations such as run-as-role actions,
+/** 
+ * User object that encapsulates user identity and operations such as run-as-role actions,
  * checking isUserInRole and getUserPrincipal.
- *
+ * <p>
  * Implementations of UserIdentity should be immutable so that they may be
  * cached by Authenticators and LoginServices.
- *
  */
 public interface UserIdentity
 {
@@ -50,7 +49,7 @@
      * This call is used to satisfy authorization calls from
      * container code which will be using translated role names.
      * @param role A role name.
-     * @param scope
+     * @param scope the scope
      * @return True if the user can act in that role.
      */
     boolean isUserInRole(String role, Scope scope);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java
index 1cb7538..b76db1c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java
@@ -25,6 +25,7 @@
 
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HandlerContainer;
+import org.eclipse.jetty.server.Server;
 
 
 /* ------------------------------------------------------------ */
@@ -117,4 +118,21 @@
         }
         return null;
     }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void setServer(Server server)
+    {
+        if (server==getServer())
+            return;
+        
+        if (isStarted())
+            throw new IllegalStateException(STARTED);
+
+        super.setServer(server);
+        Handler[] handlers=getHandlers();
+        if (handlers!=null)
+            for (Handler h : handlers)
+                h.setServer(server);
+    }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
index 0df51cb..43b8bc1 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
@@ -18,14 +18,13 @@
 
 package org.eclipse.jetty.server.handler;
 
-import java.io.File;
-import java.net.URI;
 import java.nio.file.Files;
 import java.nio.file.Path;
 
 import org.eclipse.jetty.server.handler.ContextHandler.AliasCheck;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.PathResource;
 import org.eclipse.jetty.util.resource.Resource;
 
 
@@ -41,56 +40,79 @@
     private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class);
     
     @Override
-    public boolean check(String path, Resource resource)
+    public boolean check(String uri, Resource resource)
     {
+        // Only support PathResource alias checking
+        if (!(resource instanceof PathResource))
+            return false;
+        
+        PathResource pathResource = (PathResource)resource;
+
         try
         {
-            File file =resource.getFile();
-            if (file==null)
-                return false;
+            Path path = pathResource.getPath();
+            Path alias = pathResource.getAliasPath();
             
-            // If the file exists
-            if (file.exists())
-            {
-                // we can use the real path method to check the symlinks resolve to the alias
-                URI real = file.toPath().toRealPath().toUri();
-                if (real.equals(resource.getAlias()))
+            // is the file itself a symlink?
+            if (Files.isSymbolicLink(path))
+            {        
+                alias = path.getParent().resolve(alias);
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("path ={}",path);
+                    LOG.debug("alias={}",alias);
+                }
+                if (Files.isSameFile(path,alias))
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("Allow symlink {} --> {}",resource,real);
+                        LOG.debug("Allow symlink {} --> {}",resource,pathResource.getAliasPath());
                     return true;
                 }
             }
-            else
+
+            // No, so let's check each element ourselves
+            boolean linked=true;
+            Path target=path;
+            int loops=0;
+            while (linked)
             {
-                // file does not exists, so we have to walk the path and links ourselves.
-                Path p = file.toPath().toAbsolutePath();
-                File d = p.getRoot().toFile();
-                for (Path e:p)
-                {
-                    d=new File(d,e.toString());
-                    
-                    while (d.exists() && Files.isSymbolicLink(d.toPath()))
-                    {
-                        Path link=Files.readSymbolicLink(d.toPath());
-                        if (!link.isAbsolute())
-                            link=link.resolve(d.toPath());
-                        d=link.toFile().getAbsoluteFile().getCanonicalFile();
-                    }
-                }
-                if (resource.getAlias().equals(d.toURI()))
+                if (++loops>100)
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("Allow symlink {} --> {}",resource,d);
-                    return true;
+                        LOG.debug("Too many symlinks {} --> {}",resource,target);
+                    return false;
                 }
+                linked=false;
+                Path d = target.getRoot();
+                for (Path e:target)
+                {
+                    Path r=d.resolve(e);
+                    d=r;
+
+                    while (Files.exists(d) && Files.isSymbolicLink(d))
+                    {
+                        Path link=Files.readSymbolicLink(d);    
+                        if (!link.isAbsolute())
+                            link=d.getParent().resolve(link);
+                        d=link;
+                        linked=true;
+                    }
+                }
+                target=d;
+            }
+            
+            if (pathResource.getAliasPath().equals(target))
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Allow path symlink {} --> {}",resource,target);
+                return true;
             }
         }
         catch(Exception e)
         {
-            e.printStackTrace();
             LOG.ignore(e);
         }
+        
         return false;
     }
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index 928f850..15429f8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -64,8 +64,10 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.ClassLoaderDump;
+import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Dispatcher;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HandlerContainer;
@@ -79,6 +81,7 @@
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.DumpableCollection;
 import org.eclipse.jetty.util.component.Graceful;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -98,8 +101,9 @@
  * and org.eclipse.jetty.server.Request.maxFormContentSize.  These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
  * <p>
  * This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor".
- *
- * @org.apache.xbean.XBean description="Creates a basic HTTP context"
+ * <p>
+ * By default, the context is created with alias checkers for {@link AllowSymLinkAliasChecker} (unix only) and {@link ApproveNonExistentDirectoryAliases}.
+ * If these alias checkers are not required, then {@link #clearAliasChecks()} or {@link #setAliasChecks(List)} should be called.
  */
 @ManagedObject("URI Context")
 public class ContextHandler extends ScopedHandler implements Attributes, Graceful
@@ -107,9 +111,9 @@
     public final static int SERVLET_MAJOR_VERSION=3;
     public final static int SERVLET_MINOR_VERSION=1;
     public static final Class<?>[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class,
-                                                                      ServletContextAttributeListener.class,
-                                                                      ServletRequestListener.class,
-                                                                      ServletRequestAttributeListener.class};
+        ServletContextAttributeListener.class,
+        ServletRequestListener.class,
+        ServletRequestAttributeListener.class};
 
     public static final int DEFAULT_LISTENER_TYPE_INDEX = 1;
     public static final int EXTENDED_LISTENER_TYPE_INDEX = 0;
@@ -121,6 +125,8 @@
 
     private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
 
+    private static String __serverInfo = "jetty/" + Server.getVersion();
+
     /**
      * If a context attribute with this name is set, it is interpreted as a comma separated list of attribute name. Any other context attributes that are set
      * with a name from this list will result in a call to {@link #setManagedAttribute(String, Object)}, which typically initiates the creation of a JMX MBean
@@ -150,6 +156,19 @@
         return null;
     }
 
+    /* ------------------------------------------------------------ */
+    public static String getServerInfo()
+    {
+        return __serverInfo;
+    }
+
+    /* ------------------------------------------------------------ */
+    public static void setServerInfo(String serverInfo)
+    {
+        __serverInfo = serverInfo;
+    }
+
+
 
     protected Context _scontext;
     private final AttributesMap _attributes;
@@ -171,13 +190,15 @@
     private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
     private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
     private boolean _compactPath = false;
+    private boolean _usingSecurityManager = System.getSecurityManager()!=null;
 
     private final List<EventListener> _eventListeners=new CopyOnWriteArrayList<>();
     private final List<EventListener> _programmaticListeners=new CopyOnWriteArrayList<>();
-    private final List<ServletContextListener> _contextListeners=new CopyOnWriteArrayList<>();
-    private final List<ServletContextAttributeListener> _contextAttributeListeners=new CopyOnWriteArrayList<>();
-    private final List<ServletRequestListener> _requestListeners=new CopyOnWriteArrayList<>();
-    private final List<ServletRequestAttributeListener> _requestAttributeListeners=new CopyOnWriteArrayList<>();
+    private final List<ServletContextListener> _servletContextListeners=new CopyOnWriteArrayList<>();
+    private final List<ServletContextAttributeListener> _servletContextAttributeListeners=new CopyOnWriteArrayList<>();
+    private final List<ServletRequestListener> _servletRequestListeners=new CopyOnWriteArrayList<>();
+    private final List<ServletRequestAttributeListener> _servletRequestAttributeListeners=new CopyOnWriteArrayList<>();
+    private final List<ContextScopeListener> _contextListeners = new CopyOnWriteArrayList<>();
     private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>();
     private Map<String, Object> _managedAttributes;
     private String[] _protectedTargets;
@@ -187,35 +208,24 @@
     private volatile Availability _availability;
 
     /* ------------------------------------------------------------ */
-    /**
-     *
-     */
     public ContextHandler()
     {
-        super();
-        _scontext = new Context();
-        _attributes = new AttributesMap();
-        _initParams = new HashMap<String, String>();
-        addAliasCheck(new ApproveNonExistentDirectoryAliases());
+        this((Context)null);
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     *
-     */
     protected ContextHandler(Context context)
     {
         super();
-        _scontext = context;
+        _scontext = context==null?new Context():context;
         _attributes = new AttributesMap();
         _initParams = new HashMap<String, String>();
         addAliasCheck(new ApproveNonExistentDirectoryAliases());
+        if (File.separatorChar=='/')
+            addAliasCheck(new AllowSymLinkAliasChecker());
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     *
-     */
     public ContextHandler(String contextPath)
     {
         this();
@@ -223,9 +233,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     *
-     */
     public ContextHandler(HandlerContainer parent, String contextPath)
     {
         this();
@@ -241,10 +248,11 @@
     public void dump(Appendable out, String indent) throws IOException
     {
         dumpBeans(out,indent,
-            Collections.singletonList(new ClassLoaderDump(getClassLoader())),
-            _initParams.entrySet(),
-            _attributes.getAttributeEntrySet(),
-            _scontext.getAttributeEntrySet());
+                Collections.singletonList(new ClassLoaderDump(getClassLoader())),
+                Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())),
+                Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())),
+                Collections.singletonList(new DumpableCollection("Initparams "+this,getInitParams().entrySet()))
+                );
     }
 
     /* ------------------------------------------------------------ */
@@ -283,6 +291,18 @@
     }
 
     /* ------------------------------------------------------------ */
+    public boolean isUsingSecurityManager()
+    {
+        return _usingSecurityManager;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setUsingSecurityManager(boolean usingSecurityManager)
+    {
+        _usingSecurityManager = usingSecurityManager;
+    }
+
+    /* ------------------------------------------------------------ */
     /**
      * Set the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a
      * virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a
@@ -553,9 +573,10 @@
     public void setEventListeners(EventListener[] eventListeners)
     {
         _contextListeners.clear();
-        _contextAttributeListeners.clear();
-        _requestListeners.clear();
-        _requestAttributeListeners.clear();
+        _servletContextListeners.clear();
+        _servletContextAttributeListeners.clear();
+        _servletRequestListeners.clear();
+        _servletRequestAttributeListeners.clear();
         _eventListeners.clear();
 
         if (eventListeners!=null)
@@ -566,6 +587,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Add a context event listeners.
+     * @param listener the event listener to add
      *
      * @see ServletContextListener
      * @see ServletContextAttributeListener
@@ -579,22 +601,26 @@
         if (!(isStarted() || isStarting()))
             _durableListeners.add(listener);
 
+        if (listener instanceof ContextScopeListener)
+            _contextListeners.add((ContextScopeListener)listener);
+
         if (listener instanceof ServletContextListener)
-            _contextListeners.add((ServletContextListener)listener);
+            _servletContextListeners.add((ServletContextListener)listener);
 
         if (listener instanceof ServletContextAttributeListener)
-            _contextAttributeListeners.add((ServletContextAttributeListener)listener);
+            _servletContextAttributeListeners.add((ServletContextAttributeListener)listener);
 
         if (listener instanceof ServletRequestListener)
-            _requestListeners.add((ServletRequestListener)listener);
+            _servletRequestListeners.add((ServletRequestListener)listener);
 
         if (listener instanceof ServletRequestAttributeListener)
-            _requestAttributeListeners.add((ServletRequestAttributeListener)listener);
+            _servletRequestAttributeListeners.add((ServletRequestAttributeListener)listener);
     }
 
     /* ------------------------------------------------------------ */
     /**
      * Remove a context event listeners.
+     * @param listener the event listener to remove
      *
      * @see ServletContextListener
      * @see ServletContextAttributeListener
@@ -605,24 +631,27 @@
     {
         _eventListeners.remove(listener);
 
-        if (listener instanceof ServletContextListener)
+        if (listener instanceof ContextScopeListener)
             _contextListeners.remove(listener);
 
+        if (listener instanceof ServletContextListener)
+            _servletContextListeners.remove(listener);
+
         if (listener instanceof ServletContextAttributeListener)
-            _contextAttributeListeners.remove(listener);
+            _servletContextAttributeListeners.remove(listener);
 
         if (listener instanceof ServletRequestListener)
-            _requestListeners.remove(listener);
+            _servletRequestListeners.remove(listener);
 
         if (listener instanceof ServletRequestAttributeListener)
-            _requestAttributeListeners.remove(listener);
+            _servletRequestAttributeListeners.remove(listener);
     }
 
     /* ------------------------------------------------------------ */
     /**
      * Apply any necessary restrictions on a programmatic added listener.
      *
-     * @param listener
+     * @param listener the programmatic listener to add
      */
     protected void addProgrammaticListener (EventListener listener)
     {
@@ -678,6 +707,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Set Available status.
+     * @param available true to set as enabled
      */
     public void setAvailable(boolean available)
     {
@@ -714,13 +744,14 @@
         if (_contextPath == null)
             throw new IllegalStateException("Null contextPath");
 
-        _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName());
+        if (_logger==null)
+            _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName());
         ClassLoader old_classloader = null;
         Thread current_thread = null;
         Context old_context = null;
 
         _attributes.setAttribute("org.eclipse.jetty.server.Executor",getServer().getThreadPool());
-        
+
         try
         {
             // Set the classloader
@@ -757,6 +788,7 @@
     /**
      * Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to
      * insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers.
+     * @throws Exception if unable to start the context
      *
      * @see org.eclipse.jetty.server.handler.ContextHandler.Context
      */
@@ -764,34 +796,37 @@
     {
         String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
         if (managedAttributes != null)
-        {
-            _managedAttributes = new HashMap<String, Object>();
-            String[] attributes = managedAttributes.split(",");
-            for (String attribute : attributes)
-            {
-                _managedAttributes.put(attribute.trim(),null);
-            }
-
-            Enumeration<String> e = _scontext.getAttributeNames();
-            while (e.hasMoreElements())
-            {
-                String name = e.nextElement();
-                Object value = _scontext.getAttribute(name);
-                checkManagedAttribute(name,value);
-            }
-        }
+            addEventListener(new ManagedAttributeListener(this,StringUtil.csvSplit(managedAttributes)));
 
         super.doStart();
 
         // Call context listeners
-        if (!_contextListeners.isEmpty())
+        if (!_servletContextListeners.isEmpty())
         {
             ServletContextEvent event = new ServletContextEvent(_scontext);
-            for (ServletContextListener listener:_contextListeners)
+            for (ServletContextListener listener:_servletContextListeners)
                 callContextInitialized(listener, event);
         }
     }
 
+
+    /* ------------------------------------------------------------ */
+    protected void stopContext () throws Exception
+    {
+        //stop all the handler hierarchy
+        super.doStop();
+
+        //Call the context listeners
+        if (!_servletContextListeners.isEmpty())
+        {
+            ServletContextEvent event = new ServletContextEvent(_scontext);
+            for (int i = _servletContextListeners.size(); i-->0;)
+                callContextDestroyed(_servletContextListeners.get(i),event);
+        }
+    }
+
+
+
     /* ------------------------------------------------------------ */
     protected void callContextInitialized (ServletContextListener l, ServletContextEvent e)
     {
@@ -818,6 +853,7 @@
         _availability = Availability.UNAVAILABLE;
 
         ClassLoader old_classloader = null;
+        ClassLoader old_webapploader = null;
         Thread current_thread = null;
 
         Context old_context = __context.get();
@@ -827,20 +863,13 @@
             // Set the classloader
             if (_classLoader != null)
             {
+                old_webapploader = _classLoader;
                 current_thread = Thread.currentThread();
                 old_classloader = current_thread.getContextClassLoader();
                 current_thread.setContextClassLoader(_classLoader);
             }
 
-            super.doStop();
-
-            // Context listeners
-            if (!_contextListeners.isEmpty())
-            {
-                ServletContextEvent event = new ServletContextEvent(_scontext);
-                for (int i = _contextListeners.size(); i-->0;)
-                    callContextDestroyed(_contextListeners.get(i),event);
-            }
+            stopContext();
 
             //retain only durable listeners
             setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()]));
@@ -849,13 +878,6 @@
             if (_errorHandler != null)
                 _errorHandler.stop();
 
-            Enumeration<String> e = _scontext.getAttributeNames();
-            while (e.hasMoreElements())
-            {
-                String name = e.nextElement();
-                checkManagedAttribute(name,null);
-            }
-
             for (EventListener l : _programmaticListeners)
                 removeEventListener(l);
             _programmaticListeners.clear();
@@ -865,13 +887,15 @@
             LOG.info("Stopped {}", this);
             __context.set(old_context);
             // reset the classloader
-            if (_classLoader != null && current_thread!=null)
+            if ((old_classloader == null || (old_classloader != old_webapploader)) && current_thread != null)
                 current_thread.setContextClassLoader(old_classloader);
         }
 
         _scontext.clearAttributes();
     }
 
+
+    /* ------------------------------------------------------------ */
     public boolean checkVirtualHost(final Request baseRequest)
     {
         if (_vhosts != null && _vhosts.length > 0)
@@ -911,7 +935,9 @@
         }
         return true;
     }
-    
+
+
+    /* ------------------------------------------------------------ */
     public boolean checkContextPath(String uri)
     {
         // Are we not the root context?
@@ -925,7 +951,7 @@
         }
         return true;
     }
-    
+
     /* ------------------------------------------------------------ */
     /*
      * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
@@ -940,7 +966,7 @@
 
         if (!checkContextPath(target))
             return false;
-        
+
         // Are we not the root context?
         // redirect null path infos
         if (!_allowNullPathInfo && _contextPath.length() == target.length() && _contextPath.length()>1)
@@ -1051,6 +1077,9 @@
                 baseRequest.setPathInfo(pathInfo);
             }
 
+            if (old_context != _scontext)
+                enterScope(baseRequest,dispatch);
+
             if (LOG.isDebugEnabled())
                 LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this);
 
@@ -1069,6 +1098,8 @@
         {
             if (old_context != _scontext)
             {
+                exitScope(baseRequest);
+
                 // reset the classloader
                 if (_classLoader != null && current_thread!=null)
                 {
@@ -1100,14 +1131,14 @@
             if (new_context)
             {
                 // Handle the REALLY SILLY request events!
-                if (!_requestAttributeListeners.isEmpty())
-                    for (ServletRequestAttributeListener l :_requestAttributeListeners)
+                if (!_servletRequestAttributeListeners.isEmpty())
+                    for (ServletRequestAttributeListener l :_servletRequestAttributeListeners)
                         baseRequest.addEventListener(l);
 
-                if (!_requestListeners.isEmpty())
+                if (!_servletRequestListeners.isEmpty())
                 {
                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
-                    for (ServletRequestListener l : _requestListeners)
+                    for (ServletRequestListener l : _servletRequestListeners)
                         l.requestInitialized(sre);
                 }
             }
@@ -1134,34 +1165,91 @@
             // Handle more REALLY SILLY request events!
             if (new_context)
             {
-                if (!_requestListeners.isEmpty())
+                if (!_servletRequestListeners.isEmpty())
                 {
                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
-                    for (int i=_requestListeners.size();i-->0;)
-                        _requestListeners.get(i).requestDestroyed(sre);
+                    for (int i=_servletRequestListeners.size();i-->0;)
+                        _servletRequestListeners.get(i).requestDestroyed(sre);
                 }
 
-                if (!_requestAttributeListeners.isEmpty())
+                if (!_servletRequestAttributeListeners.isEmpty())
                 {
-                    for (int i=_requestAttributeListeners.size();i-->0;)
-                        baseRequest.removeEventListener(_requestAttributeListeners.get(i));
+                    for (int i=_servletRequestAttributeListeners.size();i-->0;)
+                        baseRequest.removeEventListener(_servletRequestAttributeListeners.get(i));
+                }
+            }
+        }
+    }
+
+
+
+
+    /**
+     * @param request A request that is applicable to the scope, or null
+     * @param reason An object that indicates the reason the scope is being entered.
+     */
+    protected void enterScope(Request request, Object reason)
+    {
+        if (!_contextListeners.isEmpty())
+        {
+            for (ContextScopeListener listener:_contextListeners)
+            {
+                try
+                {
+                    listener.enterScope(_scontext,request,reason);
+                }
+                catch(Throwable e)
+                {
+                    LOG.warn(e);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @param request A request that is applicable to the scope, or null
+     */
+    protected void exitScope(Request request)
+    {
+        if (!_contextListeners.isEmpty())
+        {
+            for (int i = _contextListeners.size(); i-->0;)
+            {
+                try
+                {
+                    _contextListeners.get(i).exitScope(_scontext,request);
+                }
+                catch(Throwable e)
+                {
+                    LOG.warn(e);
                 }
             }
         }
     }
 
     /* ------------------------------------------------------------ */
-    /*
-     * Handle a runnable in this context
+    /**
+     * Handle a runnable in the scope of this context and a particular request
+     * @param request The request to scope the thread to (may be null if no particular request is in scope)
+     * @param runnable The runnable to run.
      */
-    public void handle(Runnable runnable)
+    public void handle(Request request, Runnable runnable)
     {
         ClassLoader old_classloader = null;
         Thread current_thread = null;
-        Context old_context = null;
+        Context old_context = __context.get();
+
+        // Are we already in the scope?
+        if (old_context==_scontext)
+        {
+            runnable.run();
+            return;
+        }
+
+        // Nope, so enter the scope and then exit
         try
         {
-            old_context = __context.get();
             __context.set(_scontext);
 
             // Set the classloader
@@ -1172,12 +1260,15 @@
                 current_thread.setContextClassLoader(_classLoader);
             }
 
+            enterScope(request,runnable);
             runnable.run();
         }
         finally
         {
+            exitScope(request);
+
             __context.set(old_context);
-            if (old_classloader != null && current_thread!=null)
+            if (old_classloader != null)
             {
                 current_thread.setContextClassLoader(old_classloader);
             }
@@ -1185,11 +1276,21 @@
     }
 
     /* ------------------------------------------------------------ */
+    /*
+     * Handle a runnable in the scope of this context
+     */
+    public void handle(Runnable runnable)
+    {
+        handle(null,runnable);
+    }
+
+    /* ------------------------------------------------------------ */
     /**
      * Check the target. Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a target within a context is determined. If
      * the target is protected, 404 is returned.
+     * @param target the target to test
+     * @return true if target is a protected target
      */
-    /* ------------------------------------------------------------ */
     public boolean isProtectedTarget(String target)
     {
         if (target == null || _protectedTargets == null)
@@ -1205,7 +1306,7 @@
             {
                 if (target.length()==t.length())
                     return true;
-                
+
                 // Check that the target prefix really is a path segment, thus
                 // it can end with /, a query, a target or a parameter
                 char c=target.charAt(t.length());
@@ -1229,7 +1330,7 @@
             _protectedTargets = null;
             return;
         }
-        
+
         _protectedTargets = Arrays.copyOf(targets, targets.length);
     }
 
@@ -1250,7 +1351,6 @@
     @Override
     public void removeAttribute(String name)
     {
-        checkManagedAttribute(name,null);
         _attributes.removeAttribute(name);
     }
 
@@ -1264,7 +1364,6 @@
     @Override
     public void setAttribute( String name, Object value)
     {
-        checkManagedAttribute(name,value);
         _attributes.setAttribute(name,value);
     }
 
@@ -1277,37 +1376,16 @@
     {
         _attributes.clearAttributes();
         _attributes.addAll(attributes);
-        Enumeration<String> e = _attributes.getAttributeNames();
-        while (e.hasMoreElements())
-        {
-            String name = e.nextElement();
-            checkManagedAttribute(name,attributes.getAttribute(name));
-        }
     }
 
     /* ------------------------------------------------------------ */
     @Override
     public void clearAttributes()
     {
-        Enumeration<String> e = _attributes.getAttributeNames();
-        while (e.hasMoreElements())
-        {
-            String name = e.nextElement();
-            checkManagedAttribute(name,null);
-        }
         _attributes.clearAttributes();
     }
 
     /* ------------------------------------------------------------ */
-    public void checkManagedAttribute(String name, Object value)
-    {
-        if (_managedAttributes != null && _managedAttributes.containsKey(name))
-        {
-            setManagedAttribute(name,value);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
     public void setManagedAttribute(String name, Object value)
     {
         Object old = _managedAttributes.put(name,value);
@@ -1406,10 +1484,10 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * Set the base resource for this context.
-     * @param resourceBase A string representing the base resource for the context. Any string accepted 
-     * by {@link Resource#newResource(String)} may be passed and the call is equivalent to 
+     * @param resourceBase A string representing the base resource for the context. Any string accepted
+     * by {@link Resource#newResource(String)} may be passed and the call is equivalent to
      * <code>setBaseResource(newResource(resourceBase));</code>
      */
     public void setResourceBase(String resourceBase)
@@ -1448,8 +1526,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     */
     public void setWelcomeFiles(String[] files)
     {
         _welcomeFiles = files;
@@ -1486,7 +1562,7 @@
     {
         if (errorHandler != null)
             errorHandler.setServer(getServer());
-        updateBean(_errorHandler,errorHandler);
+        updateBean(_errorHandler,errorHandler,true);
         _errorHandler = errorHandler;
     }
 
@@ -1500,7 +1576,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Set the maximum size of a form post, to protect against DOS attacks from large forms.
-     * @param maxSize
+     * @param maxSize the maximum size of the form content (in bytes)
      */
     public void setMaxFormContentSize(int maxSize)
     {
@@ -1516,7 +1592,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
-     * @param max
+     * @param max the maximum number of form keys
      */
     public void setMaxFormKeys(int max)
     {
@@ -1618,11 +1694,11 @@
             encoding = _localeEncodingMap.get(locale.getLanguage());
         return encoding;
     }
-    
+
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * Get all of the locale encodings
-     * 
+     *
      * @return a map of all the locale encodings: key is name of the locale and value is the char encoding
      */
     public Map<String,String> getLocaleEncodings()
@@ -1647,7 +1723,7 @@
         {
             path = URIUtil.canonicalPath(path);
             Resource resource = _baseResource.addPath(path);
-            
+
             if (checkAlias(path,resource))
                 return resource;
             return null;
@@ -1662,14 +1738,14 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param path
-     * @param resource
+     * @param path the path to check the alias for
+     * @param resource the resource
      * @return True if the alias is OK
      */
     public boolean checkAlias(String path, Resource resource)
     {
         // Is the resource aliased?
-        if (resource.getAlias() != null)
+        if (resource.isAlias())
         {
             if (LOG.isDebugEnabled())
                 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
@@ -1689,19 +1765,25 @@
         }
         return true;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
+     * @param url the url to convert to a Resource
+     * @return the Resource for that url
+     * @throws IOException if unable to create a Resource from the URL
      */
     public Resource newResource(URL url) throws IOException
     {
         return Resource.newResource(url);
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
+     * @param uri the URI to convert to a Resource
+     * @return the Resource for that URI
+     * @throws IOException if unable to create a Resource from the URL
      */
     public Resource newResource(URI uri) throws IOException
     {
@@ -1785,7 +1867,7 @@
     {
         return _aliasChecks;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * @param checks list of AliasCheck instances
@@ -1798,6 +1880,16 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * clear the list of AliasChecks
+     */
+    public void clearAliasChecks()
+    {
+        _aliasChecks.clear();
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /**
      * Context.
      * <p>
      * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
@@ -1805,7 +1897,7 @@
      *
      *
      */
-    public class Context extends NoContext
+    public class Context extends StaticContext
     {
         protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers
         protected boolean _extendedListenerTypes = false;
@@ -1935,21 +2027,17 @@
 
             try
             {
-                String query = null;
-                int q = 0;
-                if ((q = uriInContext.indexOf('?')) > 0)
-                {
-                    query = uriInContext.substring(q + 1);
-                    uriInContext = uriInContext.substring(0,q);
-                }
+                HttpURI uri = new HttpURI(null,null,0,uriInContext);
 
-                String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
-                if (pathInContext!=null)
-                {
-                    String uri = URIUtil.addPaths(getContextPath(),uriInContext);
-                    ContextHandler context = ContextHandler.this;
-                    return new Dispatcher(context,uri,pathInContext,query);
-                }
+                String pathInfo=URIUtil.canonicalPath(uri.getDecodedPath());
+                if (pathInfo==null)
+                    return null;
+
+                String contextPath=getContextPath();
+                if (contextPath!=null && contextPath.length()>0)
+                    uri.setPath(URIUtil.addPaths(contextPath,uri.getPath()));
+
+                return new Dispatcher(ContextHandler.this,uri,pathInfo);
             }
             catch (Exception e)
             {
@@ -1996,7 +2084,7 @@
         {
             Resource resource = ContextHandler.this.getResource(path);
             if (resource != null && resource.exists())
-                return resource.getURL();
+                return resource.getURI().toURL();
             return null;
         }
 
@@ -2120,7 +2208,6 @@
         @Override
         public synchronized void setAttribute(String name, Object value)
         {
-            checkManagedAttribute(name,value);
             Object old_value = super.getAttribute(name);
 
             if (value == null)
@@ -2128,11 +2215,11 @@
             else
                 super.setAttribute(name,value);
 
-            if (!_contextAttributeListeners.isEmpty())
+            if (!_servletContextAttributeListeners.isEmpty())
             {
                 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value == null?value:old_value);
 
-                for (ServletContextAttributeListener l : _contextAttributeListeners)
+                for (ServletContextAttributeListener l : _servletContextAttributeListeners)
                 {
                     if (old_value == null)
                         l.attributeAdded(event);
@@ -2151,15 +2238,13 @@
         @Override
         public synchronized void removeAttribute(String name)
         {
-            checkManagedAttribute(name,null);
-
             Object old_value = super.getAttribute(name);
             super.removeAttribute(name);
-            if (old_value != null &&!_contextAttributeListeners.isEmpty())
+            if (old_value != null &&!_servletContextAttributeListeners.isEmpty())
             {
                 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value);
 
-                for (ServletContextAttributeListener l : _contextAttributeListeners)
+                for (ServletContextAttributeListener l : _servletContextAttributeListeners)
                     l.attributeRemoved(event);
             }
         }
@@ -2212,8 +2297,8 @@
 
             try
             {
-                @SuppressWarnings("unchecked")
-                Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className);
+                @SuppressWarnings({ "unchecked", "rawtypes" })
+                Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):(Class)_classLoader.loadClass(className);
                 addListener(clazz);
             }
             catch (ClassNotFoundException e)
@@ -2283,55 +2368,54 @@
 
         public void setExtendedListenerTypes (boolean extended)
         {
-           _extendedListenerTypes = extended;
+            _extendedListenerTypes = extended;
         }
 
-       public boolean isExtendedListenerTypes()
-       {
-           return _extendedListenerTypes;
-       }
+        public boolean isExtendedListenerTypes()
+        {
+            return _extendedListenerTypes;
+        }
 
+        @Override
+        public ClassLoader getClassLoader()
+        {
+            if (!_enabled)
+                throw new UnsupportedOperationException();
 
-       @Override
-       public ClassLoader getClassLoader()
-       {
-           if (!_enabled)
-               throw new UnsupportedOperationException();
-           
-           //no security manager just return the classloader
-           if (System.getSecurityManager() == null)
-               return _classLoader;
-           else
-           {
-               //check to see if the classloader of the caller is the same as the context
-               //classloader, or a parent of it
-               try
-               {
-                   Class<?> reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
-                   Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE);
-                   Class<?> caller = (Class<?>)getCallerClass.invoke(null, 2);
+            //no security manager just return the classloader
+            if (!_usingSecurityManager)
+                return _classLoader;
+            else
+            {
+                //check to see if the classloader of the caller is the same as the context
+                //classloader, or a parent of it
+                try
+                {
+                    Class<?> reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
+                    Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE);
+                    Class<?> caller = (Class<?>)getCallerClass.invoke(null, 2);
 
-                   boolean ok = false;
-                   ClassLoader callerLoader = caller.getClassLoader();
-                   while (!ok && callerLoader != null)
-                   {
-                       if (callerLoader == _classLoader) 
-                           ok = true;
-                       else
-                           callerLoader = callerLoader.getParent();    
-                   }
+                    boolean ok = false;
+                    ClassLoader callerLoader = caller.getClassLoader();
+                    while (!ok && callerLoader != null)
+                    {
+                        if (callerLoader == _classLoader)
+                            ok = true;
+                        else
+                            callerLoader = callerLoader.getParent();
+                    }
 
-                   if (ok)
-                       return _classLoader;
-               }
-               catch (Exception e)      
-               {
-                   LOG.warn("Unable to check classloader of caller",e);
-               }
-              
-               AccessController.checkPermission(new RuntimePermission("getClassLoader"));
-               return _classLoader;
-           }
+                    if (ok)
+                        return _classLoader;
+                }
+                catch (Exception e)
+                {
+                    LOG.warn("Unable to check classloader of caller",e);
+                }
+
+                AccessController.checkPermission(new RuntimePermission("getClassLoader"));
+                return _classLoader;
+            }
         }
 
         @Override
@@ -2365,23 +2449,29 @@
             return _enabled;
         }
 
-
-
         public <T> T createInstance (Class<T> clazz) throws Exception
         {
             T o = clazz.newInstance();
             return o;
         }
+
+        @Override
+        public String getVirtualServerName()
+        {
+            String[] hosts = getVirtualHosts();
+            if (hosts!=null && hosts.length>0)
+                return hosts[0];
+            return null;
+        }
     }
 
-
-    public static class NoContext extends AttributesMap implements ServletContext
+    public static class StaticContext extends AttributesMap implements ServletContext
     {
         private int _effectiveMajorVersion = SERVLET_MAJOR_VERSION;
         private int _effectiveMinorVersion = SERVLET_MINOR_VERSION;
 
         /* ------------------------------------------------------------ */
-        public NoContext()
+        public StaticContext()
         {
         }
 
@@ -2448,12 +2538,7 @@
         @Override
         public String getServerInfo()
         {
-            // NOTE: DO NOT CHANGE
-            //   this is used by weld to detect Jetty
-            //   implementation version
-            // See: https://github.com/weld/core/blob/master/environments/servlet/core/src/main/java/org/jboss/weld/environment/jetty/JettyContainer.java
-            //   and its touch(ContainerContext) method
-            return "jetty/" + Server.getVersion();
+            return __serverInfo;
         }
 
         @Override
@@ -2523,7 +2608,6 @@
             return null;
         }
 
-
         @Override
         public boolean setInitParameter(String name, String value)
         {
@@ -2679,7 +2763,6 @@
         @Override
         public ClassLoader getClassLoader()
         {
-            AccessController.checkPermission(new RuntimePermission("getClassLoader"));
             return ContextHandler.class.getClassLoader();
         }
 
@@ -2718,13 +2801,9 @@
             LOG.warn(__unimplmented);
         }
 
-        /**
-         * @see javax.servlet.ServletContext#getVirtualServerName()
-         */
         @Override
         public String getVirtualServerName()
         {
-            // TODO 3.1 Auto-generated method stub
             return null;
         }
     }
@@ -2758,53 +2837,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Approve Aliases with same suffix.
-     * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
-     * approved because both the resource and alias end with ".html".
-     */
-    @Deprecated
-    public static class ApproveSameSuffixAliases implements AliasCheck
-    {
-        {
-            LOG.warn("ApproveSameSuffixAlias is not safe for production");
-        }
-        
-        @Override
-        public boolean check(String path, Resource resource)
-        {
-            int dot = path.lastIndexOf('.');
-            if (dot<0)
-                return false;
-            String suffix=path.substring(dot);
-            return resource.toString().endsWith(suffix);
-        }
-    }
-
-
-    /* ------------------------------------------------------------ */
-    /** Approve Aliases with a path prefix.
-     * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
-     * approved because both the resource and alias end with "/foobar.html".
-     */
-    @Deprecated
-    public static class ApprovePathPrefixAliases implements AliasCheck
-    {
-        {
-            LOG.warn("ApprovePathPrefixAliases is not safe for production");
-        }
-        
-        @Override
-        public boolean check(String path, Resource resource)
-        {
-            int slash = path.lastIndexOf('/');
-            if (slash<0 || slash==path.length()-1)
-                return false;
-            String suffix=path.substring(slash);
-            return resource.toString().endsWith(suffix);
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
     /** Approve Aliases of a non existent directory.
      * If a directory "/foobar/" does not exist, then the resource is
      * aliased to "/foobar".  Accept such aliases.
@@ -2816,17 +2848,36 @@
         {
             if (resource.exists())
                 return false;
-            
+
             String a=resource.getAlias().toString();
-            String r=resource.getURL().toString();
-            
+            String r=resource.getURI().toString();
+
             if (a.length()>r.length())
                 return a.startsWith(r) && a.length()==r.length()+1 && a.endsWith("/");
             if (a.length()<r.length())
                 return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");
-            
-            return a.equals(r); 
+
+            return a.equals(r);
         }
     }
 
+
+    /** Listener for all threads entering context scope, including async IO callbacks
+     */
+    public static interface ContextScopeListener extends EventListener
+    {
+        /**
+         * @param context The context being entered
+         * @param request A request that is applicable to the scope, or null
+         * @param reason An object that indicates the reason the scope is being entered
+         */
+        void enterScope(Context context, Request request, Object reason);
+
+
+        /**
+         * @param context The context being exited
+         * @param request A request that is applicable to the scope, or null
+         */
+        void exitScope(Context context, Request request);
+    }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
index b4f359b..186c094 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
@@ -19,11 +19,9 @@
 package org.eclipse.jetty.server.handler;
 
 import java.io.IOException;
-import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -236,6 +234,7 @@
     /* ------------------------------------------------------------ */
     /** Add a context handler.
      * @param contextPath  The context path to add
+     * @param resourceBase the base (root) Resource
      * @return the ContextHandler just added
      */
     public ContextHandler addContext(String contextPath,String resourceBase)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
index 651abd8..d6c90b8 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DebugHandler.java
@@ -27,9 +27,11 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.server.AbstractConnector;
 import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.DebugListener;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.util.DateCache;
@@ -42,6 +44,7 @@
  * Details of the request and response are written to an output stream
  * and the current thread name is updated with information that will link
  * to the details in that output.
+ * @deprecated Use {@link DebugListener}
  */
 public class DebugHandler extends HandlerWrapper implements Connection.Listener
 {
@@ -64,8 +67,8 @@
         boolean suspend=false;
         boolean retry=false;
         String name=(String)request.getAttribute("org.eclipse.jetty.thread.name");
-        if (name==null)
-            name=old_name+":"+baseRequest.getScheme()+"://"+baseRequest.getLocalAddr()+":"+baseRequest.getLocalPort()+baseRequest.getUri();
+        if (name == null)
+            name = old_name + ":" + baseRequest.getHttpURI();
         else
             retry=true;
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java
index fbc59c2..7fb1b04 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DefaultHandler.java
@@ -48,7 +48,6 @@
  * For all other requests a normal 404 is served.
  *
  *
- * @org.apache.xbean.XBean
  */
 public class DefaultHandler extends AbstractHandler
 {
@@ -134,7 +133,7 @@
                 {
                     writer.write("<li><a href=\"");
                     if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
-                        writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
+                        writer.write(request.getScheme()+"://"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
                     writer.write(context.getContextPath());
                     if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/"))
                         writer.write("/");
@@ -163,8 +162,9 @@
             }
 
             writer.write("</ul><hr>");
-            writer.write("<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a>&nbsp;");
-            writer.write("<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// Java Web Server</a><hr/>\n");
+
+            baseRequest.getHttpChannel().getHttpConfiguration()
+                .writePoweredBy(writer,"<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a>&nbsp;","<hr/>\n");
 
             writer.write("\n</BODY>\n</HTML>\n");
             writer.flush();
@@ -173,7 +173,7 @@
             {
                 writer.writeTo(out);
             }
-        } 
+        }
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
index f109431..016c578 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
@@ -39,6 +39,7 @@
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.Jetty;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -141,7 +142,7 @@
     protected void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message)
         throws IOException
         {
-        writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n");
+        writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n");
         writer.write("<title>Error ");
         writer.write(Integer.toString(code));
 
@@ -162,7 +163,9 @@
         writeErrorPageMessage(request,writer,code,message,uri);
         if (showStacks)
             writeErrorPageStacks(request,writer);
-        writer.write("<hr><i><small>Powered by Jetty://</small></i><hr/>\n");
+
+        Request.getBaseRequest(request).getHttpChannel().getHttpConfiguration()
+            .writePoweredBy(writer,"<hr>","<hr/>\n");
     }
 
     /* ------------------------------------------------------------ */
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
index 21c3a32..e8ebe86 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerCollection.java
@@ -35,14 +35,13 @@
 import org.eclipse.jetty.util.annotation.ManagedObject;
 
 /* ------------------------------------------------------------ */
-/** A collection of handlers.
+/** 
+ * A collection of handlers.
  * <p>
  * The default implementations  calls all handlers in list order,
  * regardless of the response status or exceptions. Derived implementation
  * may alter the order or the conditions of calling the contained
  * handlers.
- * <p>
- *
  */
 @ManagedObject("Handler of multiple handlers")
 public class HandlerCollection extends AbstractHandlerContainer
@@ -136,17 +135,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    @Override
-    public void setServer(Server server)
-    {
-        super.setServer(server);
-        Handler[] handlers=getHandlers();
-        if (handlers!=null)
-            for (Handler h : handlers)
-                h.setServer(server);
-    }
-
-    /* ------------------------------------------------------------ */
     /* Add a handler.
      * This implementation adds the passed handler to the end of the existing collection of handlers.
      * @see org.eclipse.jetty.server.server.HandlerContainer#addHandler(org.eclipse.jetty.server.server.Handler)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
index 82f9b34..f567f4b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HandlerWrapper.java
@@ -25,11 +25,13 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.LifeCycle;
 
 /* ------------------------------------------------------------ */
 /** A <code>HandlerWrapper</code> acts as a {@link Handler} but delegates the {@link Handler#handle handle} method and
@@ -85,37 +87,38 @@
         
         Handler old=_handler;
         _handler=handler;
-        updateBean(old,_handler);
+        updateBean(old,_handler,true);
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * Replace the current handler with another HandlerWrapper
+     * linked to the current handler.  
+     * <p>
+     * This is equivalent to:
+     * <pre>
+     *   wrapper.setHandler(getHandler());
+     *   setHandler(wrapper);
+     * </pre>
+     * @param wrapper the wrapper to insert
+     */
+    public void insertHandler(HandlerWrapper wrapper)
+    {
+        if (wrapper==null || wrapper.getHandler()!=null)
+            throw new IllegalArgumentException();
+        wrapper.setHandler(getHandler());
+        setHandler(wrapper);
     }
 
     /* ------------------------------------------------------------ */
     @Override
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
-        if (_handler!=null && isStarted())
-        {
-            _handler.handle(target,baseRequest, request, response);
-        }
+        Handler handler=_handler;
+        if (handler!=null)
+            handler.handle(target,baseRequest, request, response);
     }
 
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public void setServer(Server server)
-    {
-        if (server==getServer())
-            return;
-        
-        if (isStarted())
-            throw new IllegalStateException(STARTED);
-
-        super.setServer(server);
-        Handler h=getHandler();
-        if (h!=null)
-            h.setServer(server);
-    }
-
-
     /* ------------------------------------------------------------ */
     @Override
     protected void expandChildren(List<Handler> list, Class<?> byClass)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HotSwapHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HotSwapHandler.java
index 6da22cf..f185450 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HotSwapHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/HotSwapHandler.java
@@ -77,7 +77,7 @@
             throw new IllegalArgumentException("Parameter handler is null.");
         try
         {
-            updateBean(_handler,handler);
+            updateBean(_handler,handler,true);
             _handler=handler;
             Server server = getServer();
             handler.setServer(server);
@@ -124,20 +124,6 @@
 
     /* ------------------------------------------------------------ */
     @Override
-    public void setServer(Server server)
-    {
-        if (isRunning())
-            throw new IllegalStateException(RUNNING);
-
-        super.setServer(server);
-
-        Handler h = getHandler();
-        if (h != null)
-            h.setServer(server);
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
     protected void expandChildren(List<Handler> list, Class<?> byClass)
     {
         expandHandler(_handler,list,byClass);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
index cec075e..ffca1ac 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
@@ -57,12 +57,11 @@
  * are always applied, so that even if an entry matches the white list, a black list
  * entry will override it.
  * <p>
- * <p>
  * You can change white list policy setting whiteListByPath to true. In this mode a request will be white listed
  * IF it has a matching URL in the white list, otherwise the black list applies, e.g. in default mode when
  * whiteListByPath = false and wl = "127.0.0.1|/foo", /bar request from 127.0.0.1 will be blacklisted,
  * if whiteListByPath=true then not.
- * </p>
+ * <p>
  * Internet addresses may be specified as absolute address or as a combination of
  * four octet wildcard specifications (a.b.c.d) that are defined as follows.
  * </p>
@@ -70,9 +69,9 @@
  * nnn - an absolute value (0-255)
  * mmm-nnn - an inclusive range of absolute values,
  *           with following shorthand notations:
- *           nnn- => nnn-255
- *           -nnn => 0-nnn
- *           -    => 0-255
+ *           nnn- =&gt; nnn-255
+ *           -nnn =&gt; 0-nnn
+ *           -    =&gt; 0-255
  * a,b,... - a list of wildcard specifications
  * </pre>
  * <p>
@@ -201,7 +200,7 @@
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
         // Get the real remote IP (not the one set by the forwarded headers (which may be forged))
-        HttpChannel<?> channel = baseRequest.getHttpChannel();
+        HttpChannel channel = baseRequest.getHttpChannel();
         if (channel!=null)
         {
             EndPoint endp=channel.getEndPoint();
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java
index 9cbc84c..f1b73c9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java
@@ -26,22 +26,20 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.HttpConnection;
 import org.eclipse.jetty.server.Request;
 
 /**
  * Handler to adjust the idle timeout of requests while dispatched.
  * Can be applied in jetty.xml with
  * <pre>
- *   &lt;Get id='handler' name='Handler'/>
- *   &lt;Set name='Handler'>
- *     &lt;New id='idleTimeoutHandler' class='org.eclipse.jetty.server.handler.IdleTimeoutHandler'>
- *       &lt;Set name='Handler'>&lt;Ref id='handler'/>&lt;/Set>
- *       &lt;Set name='IdleTimeoutMs'>5000&lt;/Set>
- *     &lt;/New>
- *   &lt;/Set>
+ *   &lt;Get id='handler' name='Handler'/&gt;
+ *   &lt;Set name='Handler'&gt;
+ *     &lt;New id='idleTimeoutHandler' class='org.eclipse.jetty.server.handler.IdleTimeoutHandler'&gt;
+ *       &lt;Set name='Handler'&gt;&lt;Ref id='handler'/&gt;&lt;/Set&gt;
+ *       &lt;Set name='IdleTimeoutMs'&gt;5000&lt;/Set&gt;
+ *     &lt;/New&gt;
+ *   &lt;/Set&gt;
  * </pre>
  */
 public class IdleTimeoutHandler extends HandlerWrapper
@@ -80,7 +78,7 @@
     @Override
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
-        final HttpChannel<?> channel = baseRequest.getHttpChannel();
+        final HttpChannel channel = baseRequest.getHttpChannel();
         final long idle_timeout=baseRequest.getHttpChannel().getIdleTimeout();
         channel.setIdleTimeout(_idleTimeoutMs);
         
@@ -90,35 +88,35 @@
         }
         finally
         {
-                if (_applyToAsync && request.isAsyncStarted())
+            if (_applyToAsync && request.isAsyncStarted())
+            {
+                request.getAsyncContext().addListener(new AsyncListener()
                 {
-                    request.getAsyncContext().addListener(new AsyncListener()
+                    @Override
+                    public void onTimeout(AsyncEvent event) throws IOException
+                    {                            
+                    }
+
+                    @Override
+                    public void onStartAsync(AsyncEvent event) throws IOException
                     {
-                        @Override
-                        public void onTimeout(AsyncEvent event) throws IOException
-                        {                            
-                        }
-                        
-                        @Override
-                        public void onStartAsync(AsyncEvent event) throws IOException
-                        {
-                        }
-                        
-                        @Override
-                        public void onError(AsyncEvent event) throws IOException
-                        {
-                            channel.setIdleTimeout(idle_timeout);
-                        }
-                        
-                        @Override
-                        public void onComplete(AsyncEvent event) throws IOException
-                        {
-                            channel.setIdleTimeout(idle_timeout);
-                        }
-                    });
-                }
-                else 
-                    channel.setIdleTimeout(idle_timeout);
+                    }
+
+                    @Override
+                    public void onError(AsyncEvent event) throws IOException
+                    {
+                        channel.setIdleTimeout(idle_timeout);
+                    }
+
+                    @Override
+                    public void onComplete(AsyncEvent event) throws IOException
+                    {
+                        channel.setIdleTimeout(idle_timeout);
+                    }
+                });
+            }
+            else 
+                channel.setIdleTimeout(idle_timeout);
         }
     }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ManagedAttributeListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ManagedAttributeListener.java
new file mode 100644
index 0000000..6702dc2
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ManagedAttributeListener.java
@@ -0,0 +1,107 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/* ------------------------------------------------------------ */
+/** Enable Jetty style JMX MBeans from within a Context 
+ */
+public class ManagedAttributeListener implements  ServletContextListener, ServletContextAttributeListener
+{
+    private static final Logger LOG = Log.getLogger(ManagedAttributeListener.class);
+
+    final Set<String> _managedAttributes=new HashSet<>();
+    final ContextHandler _context;
+    
+    public ManagedAttributeListener(ContextHandler context,String... managedAttributes)
+    {
+        _context=context;
+
+        for (String attr:managedAttributes)
+            _managedAttributes.add(attr);
+        
+        if (LOG.isDebugEnabled())
+            LOG.debug("managedAttributes {}",_managedAttributes);
+    }
+
+    @Override
+    public void attributeReplaced(ServletContextAttributeEvent event)
+    {
+        if (_managedAttributes.contains(event.getName()))
+            updateBean(event.getName(),event.getValue(),event.getServletContext().getAttribute(event.getName()));
+    }
+    
+    @Override
+    public void attributeRemoved(ServletContextAttributeEvent event)
+    {
+        if (_managedAttributes.contains(event.getName()))
+            updateBean(event.getName(),event.getValue(),null);                    
+    }
+    
+    @Override
+    public void attributeAdded(ServletContextAttributeEvent event)
+    {
+        if (_managedAttributes.contains(event.getName()))
+            updateBean(event.getName(),null,event.getValue());    
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent event)
+    {                 
+        // Update existing attributes
+        Enumeration<String> e = event.getServletContext().getAttributeNames();
+        while (e.hasMoreElements())
+        {
+            String name = e.nextElement();
+            if (_managedAttributes.contains(name))
+                updateBean(name,null,event.getServletContext().getAttribute(name));
+        }
+    }
+    
+    @Override
+    public void contextDestroyed(ServletContextEvent event)
+    {
+        Enumeration<String> e = _context.getServletContext().getAttributeNames();
+        while (e.hasMoreElements())
+        {
+            String name = e.nextElement();
+            if (_managedAttributes.contains(name))
+                updateBean(name,event.getServletContext().getAttribute(name),null);
+        }
+    }
+    
+    protected void updateBean(String name,Object oldBean,Object newBean)
+    {
+        LOG.info("update {} {}->{} on {}",name,oldBean,newBean,_context);
+        if (LOG.isDebugEnabled())
+            LOG.debug("update {} {}->{} on {}",name,oldBean,newBean,_context);
+        _context.updateBean(oldBean,newBean,false);
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java
index 00ec275..6b8d05b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java
@@ -20,67 +20,27 @@
 
 import java.io.IOException;
 
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
 import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.server.AsyncContextState;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.RequestLog;
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.util.component.AbstractLifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
+import org.eclipse.jetty.server.Server;
 
 
 /**
  * RequestLogHandler.
  * This handler can be used to wrap an individual context for context logging.
+ * To set a {@link RequestLog} instance for the entire {@link Server}, use 
+ * {@link Server#setRequestLog(RequestLog)} instead of this handler.
  *
- *
- * @org.apache.xbean.XBean
+ * @see Server#setRequestLog(RequestLog)
  */
 public class RequestLogHandler extends HandlerWrapper
 {
-    private static final Logger LOG = Log.getLogger(RequestLogHandler.class);
     private RequestLog _requestLog;
-    private final AsyncListener _listener = new AsyncListener()
-    {
-        
-        @Override
-        public void onTimeout(AsyncEvent event) throws IOException
-        {
-            
-        }
-        
-        @Override
-        public void onStartAsync(AsyncEvent event) throws IOException
-        {
-            event.getAsyncContext().addListener(this);
-        }
-        
-        @Override
-        public void onError(AsyncEvent event) throws IOException
-        {
-            HttpServletResponse response = (HttpServletResponse)event.getAsyncContext().getResponse();
-            if (!response.isCommitted())
-                response.setStatus(500);
-            
-        }
-        
-        @Override
-        public void onComplete(AsyncEvent event) throws IOException
-        {
-            AsyncContextState context = (AsyncContextState)event.getAsyncContext();
-            Request request=context.getHttpChannelState().getBaseRequest();
-            Response response=request.getResponse();
-            _requestLog.log(request,response);
-        }
-    };
 
     /* ------------------------------------------------------------ */
     /*
@@ -90,29 +50,10 @@
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
             throws IOException, ServletException
     {
-        try
-        {
-            super.handle(target, baseRequest, request, response);
-        }
-        catch(Error|IOException|ServletException|RuntimeException e)
-        {
-            if (!response.isCommitted() && !baseRequest.getHttpChannelState().isAsync())
-                response.setStatus(500);
-            throw e;
-        }
-        finally
-        {
-            if (_requestLog != null && baseRequest.getDispatcherType().equals(DispatcherType.REQUEST))
-            {
-                if (baseRequest.getHttpChannelState().isAsync())
-                {
-                    if (baseRequest.getHttpChannelState().isInitial())
-                        baseRequest.getAsyncContext().addListener(_listener);
-                }
-                else
-                    _requestLog.log(baseRequest, (Response)response);
-            }
-        }
+        if (baseRequest.getDispatcherType()==DispatcherType.REQUEST)
+            baseRequest.getHttpChannel().addRequestLog(_requestLog);
+        if (_handler!=null)
+            _handler.handle(target,baseRequest, request, response);
     }
 
     /* ------------------------------------------------------------ */
@@ -128,35 +69,5 @@
         return _requestLog;
     }
     
-    /* ------------------------------------------------------------ */
-    @Override
-    protected void doStart() throws Exception
-    {
-        if (_requestLog==null)
-        {
-            LOG.warn("!RequestLog");
-            _requestLog=new NullRequestLog();
-        }
-        super.doStart();
-    }
-    
-    /* ------------------------------------------------------------ */
-    @Override
-    protected void doStop() throws Exception
-    {
-        super.doStop();
-        if (_requestLog instanceof NullRequestLog)
-            _requestLog=null;
-    }
 
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
-    /* ------------------------------------------------------------ */
-    private static class NullRequestLog extends AbstractLifeCycle implements RequestLog
-    {
-        @Override
-        public void log(Request request, Response response)
-        {            
-        }
-    }
 }
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
index 286284d..b937c2f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
@@ -45,8 +45,9 @@
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.resource.FileResource;
+import org.eclipse.jetty.util.resource.PathResource;
 import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.resource.ResourceFactory;
 
 
 /* ------------------------------------------------------------ */
@@ -57,9 +58,8 @@
  * Requests for resources that do not exist are let pass (Eg no 404's).
  *
  *
- * @org.apache.xbean.XBean
  */
-public class ResourceHandler extends HandlerWrapper
+public class ResourceHandler extends HandlerWrapper implements ResourceFactory
 {
     private static final Logger LOG = Log.getLogger(ResourceHandler.class);
 
@@ -68,12 +68,13 @@
     Resource _defaultStylesheet;
     Resource _stylesheet;
     String[] _welcomeFiles={"index.html"};
-    MimeTypes _mimeTypes = new MimeTypes();
+    MimeTypes _mimeTypes;
     String _cacheControl;
     boolean _directory;
+    boolean _gzip;
     boolean _etags;
-    int _minMemoryMappedContentLength=1024;
-    int _minAsyncContentLength=0;
+    int _minMemoryMappedContentLength=0;
+    int _minAsyncContentLength=16*1024;
 
     /* ------------------------------------------------------------ */
     public ResourceHandler()
@@ -180,7 +181,8 @@
     {
         Context scontext = ContextHandler.getCurrentContext();
         _context = (scontext==null?null:scontext.getContextHandler());
-
+        _mimeTypes = _context==null?new MimeTypes():_context.getMimeTypes();
+        
         super.doStart();
     }
 
@@ -298,28 +300,28 @@
     /* ------------------------------------------------------------ */
     /*
      */
-    public Resource getResource(String path) throws MalformedURLException
+    @Override
+    public Resource getResource(String path)
     {
-        if (path==null || !path.startsWith("/"))
-            throw new MalformedURLException(path);
-
         if (LOG.isDebugEnabled())
             LOG.debug("{} getResource({})",_context==null?_baseResource:_context,_baseResource,path);
-        
-        Resource base = _baseResource;
-        if (base==null)
-        {
-            if (_context==null)
-                return null;
-            return _context.getResource(path);
-        }
 
+        if (path==null || !path.startsWith("/"))
+            return null;
+        
         try
         {
+            Resource base = _baseResource;
+            if (base==null)
+            {
+                if (_context==null)
+                    return null;
+                return _context.getResource(path);
+            }
+
             path=URIUtil.canonicalPath(path);
             Resource r = base.addPath(path);
-            
-            if (r!=null && r.getAlias()!=null && (_context==null || !_context.checkAlias(path, r)))
+            if (r!=null && r.isAlias() && (_context==null || !_context.checkAlias(path, r)))
             {
                 if (LOG.isDebugEnabled())
                     LOG.debug("resource={} alias={}",r,r.getAlias());
@@ -329,7 +331,7 @@
         }
         catch(Exception e)
         {
-            LOG.ignore(e);
+            LOG.debug(e);
         }
 
         return null;
@@ -500,11 +502,12 @@
         doResponseHeaders(response,resource,mime);
         if (_etags)
             baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
+        if (last_modified>0)
+            response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified);
         
         if(skipContentBody)
             return;
         
-        
         // Send the content
         OutputStream out =null;
         try {out = response.getOutputStream();}
@@ -546,7 +549,7 @@
                 if (_minMemoryMappedContentLength>0 && 
                     resource.length()>_minMemoryMappedContentLength &&
                     resource.length()<Integer.MAX_VALUE &&
-                    resource instanceof FileResource)
+                    resource instanceof PathResource)
                 {
                     ByteBuffer buffer = BufferUtil.toMappedBuffer(resource.getFile());
                     ((HttpOutput)out).sendContent(buffer,callback);
@@ -566,7 +569,7 @@
                 // Can we use a memory mapped file?
                 if (_minMemoryMappedContentLength>0 && 
                     resource.length()>_minMemoryMappedContentLength &&
-                    resource instanceof FileResource)
+                    resource instanceof PathResource)
                 {
                     ByteBuffer buffer = BufferUtil.toMappedBuffer(resource.getFile());
                     ((HttpOutput)out).sendContent(buffer);
@@ -590,7 +593,7 @@
         if (_directory)
         {
             String listing = resource.getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0);
-            response.setContentType("text/html; charset=UTF-8");
+            response.setContentType("text/html;charset=utf-8");
             response.getWriter().println(listing);
         }
         else
@@ -601,9 +604,9 @@
     /** Set the response headers.
      * This method is called to set the response headers such as content type and content length.
      * May be extended to add additional headers.
-     * @param response
-     * @param resource
-     * @param mimeType
+     * @param response the http response
+     * @param resource the resource
+     * @param mimeType the mime type
      */
     protected void doResponseHeaders(HttpServletResponse response, Resource resource, String mimeType)
     {
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java
index 06faa35..6a7f8af 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ScopedHandler.java
@@ -40,7 +40,7 @@
  * {@link #doHandle(String, Request, HttpServletRequest, HttpServletResponse)} method
  * is called on all contained handlers.</p>
  *
- * <p>For example if Scoped handlers A, B & C were chained together, then
+ * <p>For example if Scoped handlers A, B &amp; C were chained together, then
  * the calling order would be:</p>
  * <pre>
  * A.handle(...)
@@ -52,7 +52,7 @@
  *              C.doHandle(...)
  * </pre>
  *
- * <p>If non scoped handler X was in the chained A, B, X & C, then
+ * <p>If non scoped handler X was in the chained A, B, X &amp; C, then
  * the calling order would be:</p>
  * <pre>
  * A.handle(...)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java
index 4cea6f8..417faf9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java
@@ -27,7 +27,6 @@
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnection;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.util.URIUtil;
 
@@ -42,7 +41,7 @@
     @Override
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
-        HttpChannel<?> channel = baseRequest.getHttpChannel();
+        HttpChannel channel = baseRequest.getHttpChannel();
         if (baseRequest.isSecure() || (channel == null))
         {
             // nothing to do
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
index 6a4daa3..5a67363 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java
@@ -198,8 +198,10 @@
         doShutdown(baseRequest, response);
     }
 
-    protected void doShutdown(Request baseRequest, HttpServletResponse response) throws IOException {
-        for (Connector connector : getServer().getConnectors()) {
+    protected void doShutdown(Request baseRequest, HttpServletResponse response) throws IOException 
+    {
+        for (Connector connector : getServer().getConnectors()) 
+        {
             connector.shutdown();
         }
 
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java
index d2694ee..d287acb 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/StatisticsHandler.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
@@ -31,7 +32,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.server.AsyncContextEvent;
+import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpChannelState;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
@@ -40,12 +43,15 @@
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.ManagedOperation;
 import org.eclipse.jetty.util.component.Graceful;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.statistic.CounterStatistic;
 import org.eclipse.jetty.util.statistic.SampleStatistic;
 
 @ManagedObject("Request Statistics Gathering")
 public class StatisticsHandler extends HandlerWrapper implements Graceful
 {
+    private static final Logger LOG = Log.getLogger(StatisticsHandler.class);
     private final AtomicLong _statsStartedAt = new AtomicLong();
 
     private final CounterStatistic _requestStats = new CounterStatistic();
@@ -66,6 +72,8 @@
 
     private final AtomicReference<FutureCallback> _shutdown=new AtomicReference<>();
     
+    private final AtomicBoolean _wrapWarning = new AtomicBoolean();
+    
     private final AsyncListener _onCompletion = new AsyncListener()
     {
         @Override
@@ -135,17 +143,17 @@
     }
 
     @Override
-    public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
+    public void handle(String path, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
         _dispatchedStats.increment();
 
         final long start;
-        HttpChannelState state = request.getHttpChannelState();
+        HttpChannelState state = baseRequest.getHttpChannelState();
         if (state.isInitial())
         {
             // new request
             _requestStats.increment();
-            start = request.getTimeStamp();
+            start = baseRequest.getTimeStamp();
         }
         else
         {
@@ -156,7 +164,19 @@
 
         try
         {
-            super.handle(path, request, httpRequest, httpResponse);
+            Handler handler = getHandler();
+            if (handler!=null && _shutdown.get()==null && isStarted())
+                handler.handle(path, baseRequest, request, response);
+            else if (baseRequest.isHandled())
+            {
+                if (_wrapWarning.compareAndSet(false,true))
+                    LOG.warn("Bad statistics configuration. Latencies will be incorrect in {}",this);
+            }
+            else
+            {
+                baseRequest.setHandled(true);
+                response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503);
+            }
         }
         finally
         {
@@ -178,13 +198,13 @@
             {
                 long d=_requestStats.decrement();
                 _requestTimeStats.set(dispatched);
-                updateResponse(request);
+                updateResponse(baseRequest);
                 
                 // If we have no more dispatches, should we signal shutdown?
                 FutureCallback shutdown = _shutdown.get();
                 if (shutdown!=null)
                 {
-                    httpResponse.flushBuffer();
+                    response.flushBuffer();
                     if (d==0)
                         shutdown.succeeded();
                 }   
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipFactory.java
new file mode 100644
index 0000000..0da0808
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipFactory.java
@@ -0,0 +1,32 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.util.zip.Deflater;
+
+import org.eclipse.jetty.server.Request;
+
+public interface GzipFactory
+{
+    Deflater getDeflater(Request request, long content_length);
+
+    boolean isMimeTypeGzipable(String mimetype);
+
+    void recycle(Deflater deflater);
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java
new file mode 100644
index 0000000..05a16a4
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java
@@ -0,0 +1,604 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.eclipse.jetty.http.GzipHttpContent.ETAG_GZIP_QUOTE;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.zip.Deflater;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.GzipHttpContent;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.pathmap.PathSpecSet;
+import org.eclipse.jetty.server.HttpOutput;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.IncludeExclude;
+import org.eclipse.jetty.util.RegexSet;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/**
+ * A Handler that can dynamically GZIP compress responses.   Unlike 
+ * previous and 3rd party GzipFilters, this mechanism works with asynchronously
+ * generated responses and does not need to wrap the response or it's output
+ * stream.  Instead it uses the efficient {@link org.eclipse.jetty.server.HttpOutput.Interceptor} mechanism.
+ * <p>
+ * The handler can be applied to the entire server (a gzip.mod is included in
+ * the distribution) or it may be applied to individual contexts.
+ * </p>
+ */
+public class GzipHandler extends HandlerWrapper implements GzipFactory
+{
+    private static final Logger LOG = Log.getLogger(GzipHandler.class);
+
+    public final static String GZIP = "gzip";
+    public final static String DEFLATE = "deflate";
+    public final static int DEFAULT_MIN_GZIP_SIZE=16;
+    private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
+    private int _compressionLevel=Deflater.DEFAULT_COMPRESSION;
+    private boolean _checkGzExists = true;
+    
+    // non-static, as other GzipHandler instances may have different configurations
+    private final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
+
+    private final IncludeExclude<String> _agentPatterns=new IncludeExclude<>(RegexSet.class);
+    private final IncludeExclude<String> _methods = new IncludeExclude<>();
+    private final IncludeExclude<String> _paths = new IncludeExclude<>(PathSpecSet.class);
+    private final IncludeExclude<String> _mimeTypes = new IncludeExclude<>();
+    
+    private HttpField _vary;
+
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Instantiates a new gzip handler.
+     * The excluded Mime Types are initialized to common known 
+     * images, audio, video and other already compressed types.
+     * The included methods is initialized to GET.
+     * The excluded agent patterns are set to exclude MSIE 6.0
+     */
+    public GzipHandler()
+    {
+        _methods.include(HttpMethod.GET.asString());
+        for (String type:MimeTypes.getKnownMimeTypes())
+        {
+            if ("image/svg+xml".equals(type))
+                _paths.exclude("*.svgz");
+            else if (type.startsWith("image/")||
+                type.startsWith("audio/")||
+                type.startsWith("video/"))
+                _mimeTypes.exclude(type);
+        }
+        _mimeTypes.exclude("application/compress");
+        _mimeTypes.exclude("application/zip");
+        _mimeTypes.exclude("application/gzip");
+        _mimeTypes.exclude("application/bzip2");
+        _mimeTypes.exclude("application/x-rar-compressed");
+        LOG.debug("{} mime types {}",this,_mimeTypes);
+        
+        _agentPatterns.exclude(".*MSIE 6.0.*");
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param patterns Regular expressions matching user agents to exclude
+     */
+    public void addExcludedAgentPatterns(String... patterns)
+    {
+        _agentPatterns.exclude(patterns);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param methods The methods to exclude in compression
+     */
+    public void addExcludedMethods(String... methods)
+    {
+        for (String m : methods)
+            _methods.exclude(m);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set the mime types.
+     * @param types The mime types to exclude (without charset or other parameters).
+     * For backward compatibility the mimetypes may be comma separated strings, but this
+     * will not be supported in future versions.
+     */
+    public void addExcludedMimeTypes(String... types)
+    {
+        for (String t : types)
+            _mimeTypes.exclude(StringUtil.csvSplit(t));
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param pathspecs Path specs (as per servlet spec) to exclude. If a 
+     * ServletContext is available, the paths are relative to the context path,
+     * otherwise they are absolute.
+     * For backward compatibility the pathspecs may be comma separated strings, but this
+     * will not be supported in future versions.
+     */
+    public void addExcludedPaths(String... pathspecs)
+    {
+        for (String p : pathspecs)
+            _paths.exclude(StringUtil.csvSplit(p));
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param patterns Regular expressions matching user agents to exclude
+     */
+    public void addIncludedAgentPatterns(String... patterns)
+    {
+        _agentPatterns.include(patterns);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param methods The methods to include in compression
+     */
+    public void addIncludedMethods(String... methods)
+    {
+        for (String m : methods)
+            _methods.include(m);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Add included mime types. Inclusion takes precedence over
+     * exclusion.
+     * @param types The mime types to include (without charset or other parameters)
+     * For backward compatibility the mimetypes may be comma separated strings, but this
+     * will not be supported in future versions.
+     */
+    public void addIncludedMimeTypes(String... types)
+    {
+        for (String t : types)
+            _mimeTypes.include(StringUtil.csvSplit(t));
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Add path specs to include. Inclusion takes precedence over exclusion.
+     * @param pathspecs Path specs (as per servlet spec) to include. If a 
+     * ServletContext is available, the paths are relative to the context path,
+     * otherwise they are absolute
+     * For backward compatibility the pathspecs may be comma separated strings, but this
+     * will not be supported in future versions.
+     */
+    public void addIncludedPaths(String... pathspecs)
+    {
+        for (String p : pathspecs)
+            _paths.include(StringUtil.csvSplit(p));
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void doStart() throws Exception
+    {
+        _vary=(_agentPatterns.size()>0)?GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING_USER_AGENT:GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING;
+        super.doStart();
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean getCheckGzExists()
+    {
+        return _checkGzExists;
+    }
+
+    /* ------------------------------------------------------------ */
+    public int getCompressionLevel()
+    {
+        return _compressionLevel;
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public Deflater getDeflater(Request request, long content_length)
+    {
+        String ua = request.getHttpFields().get(HttpHeader.USER_AGENT);
+        if (ua!=null && !isAgentGzipable(ua))
+        {
+            LOG.debug("{} excluded user agent {}",this,request);
+            return null;
+        }
+        
+        if (content_length>=0 && content_length<_minGzipSize)
+        {
+            LOG.debug("{} excluded minGzipSize {}",this,request);
+            return null;
+        }
+
+        // If not HTTP/2, then we must check the accept encoding header
+        if (request.getHttpVersion()!=HttpVersion.HTTP_2)
+        {
+            HttpField accept = request.getHttpFields().getField(HttpHeader.ACCEPT_ENCODING);
+
+            if (accept==null)
+            {
+                LOG.debug("{} excluded !accept {}",this,request);
+                return null;
+            }
+            boolean gzip = accept.contains("gzip");
+
+            if (!gzip)
+            {
+                LOG.debug("{} excluded not gzip accept {}",this,request);
+                return null;
+            }
+        }
+        
+        Deflater df = _deflater.get();
+        if (df==null)
+            df=new Deflater(_compressionLevel,true);        
+        else
+            _deflater.set(null);
+        
+        return df;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String[] getExcludedAgentPatterns()
+    {
+        Set<String> excluded=_agentPatterns.getExcluded();
+        return excluded.toArray(new String[excluded.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getExcludedMethods()
+    {
+        Set<String> excluded=_methods.getExcluded();
+        return excluded.toArray(new String[excluded.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getExcludedMimeTypes()
+    {
+        Set<String> excluded=_mimeTypes.getExcluded();
+        return excluded.toArray(new String[excluded.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getExcludedPaths()
+    {
+        Set<String> excluded=_paths.getExcluded();
+        return excluded.toArray(new String[excluded.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getIncludedAgentPatterns()
+    {
+        Set<String> includes=_agentPatterns.getIncluded();
+        return includes.toArray(new String[includes.size()]);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String[] getIncludedMethods()
+    {
+        Set<String> includes=_methods.getIncluded();
+        return includes.toArray(new String[includes.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getIncludedMimeTypes()
+    {
+        Set<String> includes=_mimeTypes.getIncluded();
+        return includes.toArray(new String[includes.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getIncludedPaths()
+    {
+        Set<String> includes=_paths.getIncluded();
+        return includes.toArray(new String[includes.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public String[] getMethods()
+    {
+        return getIncludedMethods();
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Get the minimum reponse size.
+     *
+     * @return minimum reponse size
+     */
+    public int getMinGzipSize()
+    {
+        return _minGzipSize;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+    {
+        ServletContext context = baseRequest.getServletContext();
+        String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
+        LOG.debug("{} handle {} in {}",this,baseRequest,context);
+        
+        HttpOutput out = baseRequest.getResponse().getHttpOutput();   
+        // Are we already being gzipped?
+        HttpOutput.Interceptor interceptor = out.getInterceptor();
+        while (interceptor!=null)
+        {
+            if (interceptor instanceof GzipHttpOutputInterceptor)
+            {
+                LOG.debug("{} already intercepting {}",this,request);
+                _handler.handle(target,baseRequest, request, response);
+                return;
+            }
+            interceptor=interceptor.getNextInterceptor();
+        }
+        
+        // If not a supported method - no Vary because no matter what client, this URI is always excluded
+        if (!_methods.matches(baseRequest.getMethod()))
+        {
+            LOG.debug("{} excluded by method {}",this,request);
+            _handler.handle(target,baseRequest, request, response);
+            return;
+        }
+        
+        // If not a supported URI- no Vary because no matter what client, this URI is always excluded
+        // Use pathInfo because this is be
+        if (!isPathGzipable(path))
+        {
+            LOG.debug("{} excluded by path {}",this,request);
+            _handler.handle(target,baseRequest, request, response);
+            return;
+        }
+
+        // Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
+        String mimeType = context==null?null:context.getMimeType(path);
+        if (mimeType!=null)
+        {
+            mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);
+            if (!isMimeTypeGzipable(mimeType))
+            {
+                LOG.debug("{} excluded by path suffix mime type {}",this,request);
+                // handle normally without setting vary header
+                _handler.handle(target,baseRequest, request, response);
+                return;
+            }
+        }
+        
+        if (_checkGzExists && context!=null)
+        {
+            String realpath=request.getServletContext().getRealPath(path);
+            if (realpath!=null)
+            {
+                File gz=new File(realpath+".gz");
+                if (gz.exists())
+                {
+                    LOG.debug("{} gzip exists {}",this,request);
+                    // allow default servlet to handle
+                    _handler.handle(target,baseRequest, request, response);
+                    return;
+                }
+            }
+        }
+        
+        // Special handling for etags
+        String etag = baseRequest.getHttpFields().get(HttpHeader.IF_NONE_MATCH); 
+        if (etag!=null)
+        {
+            int i=etag.indexOf(ETAG_GZIP_QUOTE);
+            if (i>0)
+            {
+                while (i>=0)
+                {
+                    etag=etag.substring(0,i)+etag.substring(i+GzipHttpContent.ETAG_GZIP.length());
+                    i=etag.indexOf(ETAG_GZIP_QUOTE,i);
+                }
+                baseRequest.getHttpFields().put(new HttpField(HttpHeader.IF_NONE_MATCH,etag));
+            }
+        }
+
+        // install interceptor and handle
+        out.setInterceptor(new GzipHttpOutputInterceptor(this,_vary,baseRequest.getHttpChannel(),out.getInterceptor()));
+        if (_handler!=null)
+            _handler.handle(target,baseRequest, request, response);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Checks to see if the userAgent is excluded
+     *
+     * @param ua the user agent
+     * @return boolean true if excluded
+     */
+    protected boolean isAgentGzipable(String ua)
+    {
+        if (ua == null)
+            return false;
+        
+        return _agentPatterns.matches(ua);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public boolean isMimeTypeGzipable(String mimetype)
+    {
+        return _mimeTypes.matches(mimetype);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Checks to see if the path is included or not excluded 
+     *
+     * @param requestURI
+     *            the request uri
+     * @return boolean true if gzipable
+     */
+    protected boolean isPathGzipable(String requestURI)
+    {
+        if (requestURI == null)
+            return true;
+        
+        return _paths.matches(requestURI);
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void recycle(Deflater deflater)
+    {
+        deflater.reset();
+        if (_deflater.get()==null)
+            _deflater.set(deflater);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param checkGzExists If true, check if a static gz file exists for
+     * the resource that the DefaultServlet may serve as precompressed.
+     */
+    public void setCheckGzExists(boolean checkGzExists)
+    {
+        _checkGzExists = checkGzExists;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param compressionLevel  The compression level to use to initialize {@link Deflater#setLevel(int)}
+     */
+    public void setCompressionLevel(int compressionLevel)
+    {
+        _compressionLevel = compressionLevel;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param patterns Regular expressions matching user agents to exclude
+     */
+    public void setExcludedAgentPatterns(String... patterns)
+    {
+        _agentPatterns.getExcluded().clear();
+        addExcludedAgentPatterns(patterns);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param method to exclude
+     */
+    public void setExcludedMethods(String... method)
+    {
+        _methods.getExcluded().clear();
+        _methods.exclude(method);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set the mime types.
+     * @param types The mime types to exclude (without charset or other parameters)
+     */
+    public void setExcludedMimeTypes(String... types)
+    {
+        _mimeTypes.getExcluded().clear();
+        _mimeTypes.exclude(types);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param pathspecs Path specs (as per servlet spec) to exclude. If a 
+     * ServletContext is available, the paths are relative to the context path,
+     * otherwise they are absolute.
+     */
+    public void setExcludedPaths(String... pathspecs)
+    {
+        _paths.getExcluded().clear();
+        _paths.exclude(pathspecs);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param patterns Regular expressions matching user agents to include
+     */
+    public void setIncludedAgentPatterns(String... patterns)
+    {
+        _agentPatterns.getIncluded().clear();
+        addIncludedAgentPatterns(patterns);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param methods The methods to include in compression
+     */
+    public void setIncludedMethods(String... methods)
+    {
+        _methods.getIncluded().clear();
+        _methods.include(methods);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Set included mime types. Inclusion takes precedence over
+     * exclusion.
+     * @param types The mime types to include (without charset or other parameters)
+     */
+    public void setIncludedMimeTypes(String... types)
+    {
+        _mimeTypes.getIncluded().clear();
+        _mimeTypes.include(types);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set the path specs to include. Inclusion takes precedence over exclusion.
+     * @param pathspecs Path specs (as per servlet spec) to include. If a 
+     * ServletContext is available, the paths are relative to the context path,
+     * otherwise they are absolute
+     */
+    public void setIncludedPaths(String... pathspecs)
+    {
+        _paths.getIncluded().clear();
+        _paths.include(pathspecs);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Set the minimum response size to trigger dynamic compresssion
+     *
+     * @param minGzipSize minimum response size in bytes
+     */
+    public void setMinGzipSize(int minGzipSize)
+    {
+        _minGzipSize = minGzipSize;
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java
new file mode 100644
index 0000000..c7fc799
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java
@@ -0,0 +1,368 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.WritePendingException;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+
+import org.eclipse.jetty.http.GzipHttpContent;
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpOutput;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.IteratingNestedCallback;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor
+{
+    public static Logger LOG = Log.getLogger(GzipHttpOutputInterceptor.class);
+    private final static byte[] GZIP_HEADER = new byte[] { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 };
+
+    public final static HttpField VARY_ACCEPT_ENCODING_USER_AGENT=new PreEncodedHttpField(HttpHeader.VARY,HttpHeader.ACCEPT_ENCODING+", "+HttpHeader.USER_AGENT);
+    public final static HttpField VARY_ACCEPT_ENCODING=new PreEncodedHttpField(HttpHeader.VARY,HttpHeader.ACCEPT_ENCODING.asString());
+    
+    private enum GZState {  MIGHT_COMPRESS, NOT_COMPRESSING, COMMITTING, COMPRESSING, FINISHED};
+    private final AtomicReference<GZState> _state = new AtomicReference<>(GZState.MIGHT_COMPRESS);
+    private final CRC32 _crc = new CRC32();
+
+    private final GzipFactory _factory;
+    private final HttpOutput.Interceptor _interceptor;
+    private final HttpChannel _channel;
+    private final HttpField _vary;
+    private final int _bufferSize;
+    
+    private Deflater _deflater;
+    private ByteBuffer _buffer;
+
+    public GzipHttpOutputInterceptor(GzipFactory factory, HttpChannel channel, HttpOutput.Interceptor next)
+    {
+        this(factory,VARY_ACCEPT_ENCODING_USER_AGENT,channel.getHttpConfiguration().getOutputBufferSize(),channel,next);
+    }
+    
+    public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, HttpChannel channel, HttpOutput.Interceptor next)
+    {
+        this(factory,vary,channel.getHttpConfiguration().getOutputBufferSize(),channel,next);
+    }
+    
+    public GzipHttpOutputInterceptor(GzipFactory factory, HttpField vary, int bufferSize, HttpChannel channel, HttpOutput.Interceptor next)
+    {
+        _factory=factory;
+        _channel=channel;
+        _interceptor=next;
+        _vary=vary;
+        _bufferSize=bufferSize;
+    }
+
+    public HttpOutput.Interceptor getNextInterceptor()
+    {
+        return _interceptor;
+    }
+    
+    @Override
+    public boolean isOptimizedForDirectBuffers()
+    {
+        return false; // No point as deflator is in user space.
+    }
+    
+    
+    @Override
+    public void write(ByteBuffer content, boolean complete, Callback callback)
+    {
+        switch (_state.get())
+        {
+            case MIGHT_COMPRESS:
+                commit(content,complete,callback);
+                break;
+                
+            case NOT_COMPRESSING:
+                _interceptor.write(content, complete, callback);
+                return;
+                
+            case COMMITTING:
+                callback.failed(new WritePendingException());
+                break;
+
+            case COMPRESSING:
+                gzip(content,complete,callback);
+                break;
+
+            default:
+                callback.failed(new IllegalStateException("state="+_state.get()));
+                break;
+        }
+    }
+
+    private void addTrailer()
+    {
+        int i=_buffer.limit();
+        _buffer.limit(i+8);
+        
+        int v=(int)_crc.getValue();
+        _buffer.put(i++,(byte)(v & 0xFF));
+        _buffer.put(i++,(byte)((v>>>8) & 0xFF));
+        _buffer.put(i++,(byte)((v>>>16) & 0xFF));
+        _buffer.put(i++,(byte)((v>>>24) & 0xFF));
+        
+        v=_deflater.getTotalIn();
+        _buffer.put(i++,(byte)(v & 0xFF));
+        _buffer.put(i++,(byte)((v>>>8) & 0xFF));
+        _buffer.put(i++,(byte)((v>>>16) & 0xFF));
+        _buffer.put(i++,(byte)((v>>>24) & 0xFF));
+    }
+    
+    
+    private void gzip(ByteBuffer content, boolean complete, final Callback callback)
+    {
+        if (content.hasRemaining() || complete)
+            new GzipBufferCB(content,complete,callback).iterate();
+        else
+            callback.succeeded();
+    }
+
+    protected void commit(ByteBuffer content, boolean complete, Callback callback)
+    {
+        // Are we excluding because of status?
+        int sc = _channel.getResponse().getStatus();
+        if (sc>0 && (sc<200 || sc==204 || sc==205 || sc>=300))
+        {
+            LOG.debug("{} exclude by status {}",this,sc);
+            noCompression();
+            _interceptor.write(content, complete, callback);
+            return;
+        }
+        
+        // Are we excluding because of mime-type?
+        String ct = _channel.getResponse().getContentType();
+        if (ct!=null)
+        {
+            ct=MimeTypes.getContentTypeWithoutCharset(ct);
+            if (!_factory.isMimeTypeGzipable(StringUtil.asciiToLowerCase(ct)))
+            {
+                LOG.debug("{} exclude by mimeType {}",this,ct);
+                noCompression();
+                _interceptor.write(content, complete, callback);
+                return;
+            }
+        }
+        
+        // Has the Content-Encoding header already been set?
+        String ce=_channel.getResponse().getHeader("Content-Encoding");
+        if (ce != null)
+        {
+            LOG.debug("{} exclude by content-encoding {}",this,ce);
+            noCompression();
+            _interceptor.write(content, complete, callback);
+            return;
+        }
+        
+        // Are we the thread that commits?
+        if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING))
+        {
+            // We are varying the response due to accept encoding header.
+            HttpFields fields = _channel.getResponse().getHttpFields();
+            fields.add(_vary);
+
+            long content_length = _channel.getResponse().getContentLength();
+            if (content_length<0 && complete)
+                content_length=content.remaining();
+            
+            _deflater = _factory.getDeflater(_channel.getRequest(),content_length);
+            
+            if (_deflater==null)
+            {
+                LOG.debug("{} exclude no deflater",this);
+                _state.set(GZState.NOT_COMPRESSING);
+                _interceptor.write(content, complete, callback);
+                return;
+            }
+
+            fields.put(GzipHttpContent.CONTENT_ENCODING_GZIP);
+            _crc.reset();
+            _buffer=_channel.getByteBufferPool().acquire(_bufferSize,false);
+            BufferUtil.fill(_buffer,GZIP_HEADER,0,GZIP_HEADER.length);
+
+            // Adjust headers
+            _channel.getResponse().setContentLength(-1);
+            String etag=fields.get(HttpHeader.ETAG);
+            if (etag!=null)
+            {
+                int end = etag.length()-1;
+                etag=(etag.charAt(end)=='"')?etag.substring(0,end)+GzipHttpContent.ETAG_GZIP+'"':etag+GzipHttpContent.ETAG_GZIP;
+                fields.put(HttpHeader.ETAG,etag);
+            }
+            
+            LOG.debug("{} compressing {}",this,_deflater);
+            _state.set(GZState.COMPRESSING);
+            
+            gzip(content,complete,callback);
+        }
+        else
+            callback.failed(new WritePendingException());
+    }
+
+    public void noCompression()
+    {
+        while (true)
+        {
+            switch (_state.get())
+            {
+                case NOT_COMPRESSING:
+                    return;
+
+                case MIGHT_COMPRESS:
+                    if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.NOT_COMPRESSING))
+                        return;
+                    break;
+
+                default:
+                    throw new IllegalStateException(_state.get().toString());
+            }
+        }
+    }
+
+    public void noCompressionIfPossible()
+    {
+        while (true)
+        {
+            switch (_state.get())
+            {
+                case COMPRESSING:
+                case NOT_COMPRESSING:
+                    return;
+
+                case MIGHT_COMPRESS:
+                    if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.NOT_COMPRESSING))
+                        return;
+                    break;
+
+                default:
+                    throw new IllegalStateException(_state.get().toString());
+            }
+        }
+    }
+    
+    public boolean mightCompress()
+    {
+        return _state.get()==GZState.MIGHT_COMPRESS;
+    }
+    
+    private class GzipBufferCB extends IteratingNestedCallback
+    {        
+        private ByteBuffer _copy;
+        private final ByteBuffer _content;
+        private final boolean _last;
+        public GzipBufferCB(ByteBuffer content, boolean complete, Callback callback)
+        {
+            super(callback);
+            _content=content;
+            _last=complete;
+        }
+
+        @Override
+        protected Action process() throws Exception
+        {
+            if (_deflater==null)
+                return Action.SUCCEEDED;
+                
+            if (_deflater.needsInput())
+            {                
+                if (BufferUtil.isEmpty(_content))
+                {                    
+                    if (_deflater.finished())
+                    {
+                        _factory.recycle(_deflater);
+                        _deflater=null;
+                        _channel.getByteBufferPool().release(_buffer);
+                        _buffer=null;
+                        if (_copy!=null)
+                        {
+                            _channel.getByteBufferPool().release(_copy);
+                            _copy=null;
+                        }
+                        return Action.SUCCEEDED;
+                    }
+                    
+                    if (!_last)
+                    {
+                        return Action.SUCCEEDED;
+                    }
+                    
+                    _deflater.finish();
+                }
+                else if (_content.hasArray())
+                {
+                    byte[] array=_content.array();
+                    int off=_content.arrayOffset()+_content.position();
+                    int len=_content.remaining();
+                    BufferUtil.clear(_content);
+                    
+                    _crc.update(array,off,len);
+                    _deflater.setInput(array,off,len);                
+                    if (_last)
+                        _deflater.finish();
+                }
+                else
+                {
+                    if (_copy==null)
+                        _copy=_channel.getByteBufferPool().acquire(_bufferSize,false);
+                    BufferUtil.clearToFill(_copy);
+                    int took=BufferUtil.put(_content,_copy);
+                    BufferUtil.flipToFlush(_copy,0);
+                    if (took==0)
+                        throw new IllegalStateException();
+                   
+                    byte[] array=_copy.array();
+                    int off=_copy.arrayOffset()+_copy.position();
+                    int len=_copy.remaining();
+
+                    _crc.update(array,off,len);
+                    _deflater.setInput(array,off,len);                
+                    if (_last && BufferUtil.isEmpty(_content))
+                        _deflater.finish();
+                }
+            }
+
+            BufferUtil.compact(_buffer);
+            int off=_buffer.arrayOffset()+_buffer.limit();
+            int len=_buffer.capacity()-_buffer.limit() - (_last?8:0);
+            if (len>0)
+            {
+                int produced=_deflater.deflate(_buffer.array(),off,len,Deflater.NO_FLUSH);
+                _buffer.limit(_buffer.limit()+produced);
+            }
+            boolean finished=_deflater.finished();
+            
+            if (finished)
+                addTrailer();
+                
+            _interceptor.write(_buffer,finished,this);
+            return Action.SCHEDULED;
+        }
+    }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/package-info.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/package-info.java
new file mode 100644
index 0000000..89ffc89
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/package-info.java
@@ -0,0 +1,23 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.
+//  ========================================================================
+//
+
+/**
+ * Jetty GZIP Handler 
+ */
+package org.eclipse.jetty.server.handler.gzip;
+
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java
index 64718e3..7fbc25e 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java
@@ -23,6 +23,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSessionActivationListener;
@@ -45,7 +46,7 @@
 public abstract class AbstractSession implements AbstractSessionManager.SessionIf
 {
     final static Logger LOG = SessionHandler.LOG;
-    public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
+    public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
     private  String _clusterId; // ID without any node (ie "worker") id appended
     private  String _nodeId;    // ID of session with node(ie "worker") id appended
     private final AbstractSessionManager _manager;
@@ -97,6 +98,7 @@
     /* ------------------------------------------------------------- */
     /**
      * asserts that the session is valid
+     * @throws IllegalStateException if the sesion is invalid
      */
     protected void checkValid() throws IllegalStateException
     {
@@ -106,8 +108,8 @@
     
     /* ------------------------------------------------------------- */
     /** Check to see if session has expired as at the time given.
-     * @param time
-     * @return
+     * @param time the time in milliseconds
+     * @return true if expired
      */
     protected boolean checkExpiry(long time)
     {
@@ -154,6 +156,12 @@
     {
         return _cookieSet;
     }
+    
+    /* ------------------------------------------------------------- */
+    public void setCookieSetTime(long time)
+    {
+        _cookieSet = time;
+    }
 
     /* ------------------------------------------------------------- */
     @Override
@@ -463,11 +471,12 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param name
-     * @param value
+     * @param name the name of the attribute
+     * @param value the value of the attribute
+     * @return true if attribute changed
      * @deprecated use changeAttribute(String,Object) instead
-     * @return
      */
+    @Deprecated
     protected boolean updateAttribute (String name, Object value)
     {
         Object old=null;
@@ -497,9 +506,9 @@
      * in the session. The appropriate session attribute listeners are
      * also called.
      * 
-     * @param name
-     * @param value
-     * @return
+     * @param name the name of the attribute
+     * @param value the value of the attribute
+     * @return the old value for the attribute
      */
     protected Object changeAttribute (String name, Object value)
     {
@@ -559,7 +568,11 @@
     }
 
     /* ------------------------------------------------------------- */
-    /** If value implements HttpSessionBindingListener, call valueBound() */
+    /** 
+     * Bind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)}) 
+     * @param name the name with which the object is bound or unbound  
+     * @param value the bound value
+     */
     public void bindValue(java.lang.String name, Object value)
     {
         if (value!=null&&value instanceof HttpSessionBindingListener)
@@ -600,7 +613,11 @@
     }
 
     /* ------------------------------------------------------------- */
-    /** If value implements HttpSessionBindingListener, call valueUnbound() */
+    /**
+     * Unbind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)}) 
+     * @param name the name with which the object is bound or unbound  
+     * @param value the bound value
+     */
     public void unbindValue(java.lang.String name, Object value)
     {
         if (value!=null&&value instanceof HttpSessionBindingListener)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionIdManager.java
index 9d48270..07a6f7f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionIdManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionIdManager.java
@@ -67,13 +67,13 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Set the workname. If set, the workername is dot appended to the session
+     * Set the workername. If set, the workername is dot appended to the session
      * ID and can be used to assist session affinity in a load balancer.
      * A worker name starting with $ is used as a request attribute name to
      * lookup the worker name that can be dynamically set by a request
-     * customiser.
+     * Customizer.
      *
-     * @param workerName
+     * @param workerName the name of the worker
      */
     public void setWorkerName(String workerName)
     {
@@ -244,8 +244,8 @@
 
     /** Get the session ID with any worker ID.
      *
-     * @param clusterId
-     * @param request
+     * @param clusterId the cluster id
+     * @param request the request
      * @return sessionId plus any worker ID.
      */
     @Override
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java
index d253946..408d08d 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java
@@ -53,15 +53,12 @@
 import org.eclipse.jetty.util.statistic.CounterStatistic;
 import org.eclipse.jetty.util.statistic.SampleStatistic;
 
-/* ------------------------------------------------------------ */
 /**
- * An Abstract implementation of SessionManager. The partial implementation of
- * SessionManager interface provides the majority of the handling required to
- * implement a SessionManager. Concrete implementations of SessionManager based
- * on AbstractSessionManager need only implement the newSession method to return
- * a specialised version of the Session inner class that provides an attribute
- * Map.
+ * An Abstract implementation of SessionManager.
  * <p>
+ * The partial implementation of SessionManager interface provides the majority of the handling required to implement a
+ * SessionManager. Concrete implementations of SessionManager based on AbstractSessionManager need only implement the
+ * newSession method to return a specialized version of the Session inner class that provides an attribute Map.
  */
 @SuppressWarnings("deprecation")
 @ManagedObject("Abstract Session Manager")
@@ -405,6 +402,7 @@
     /**
      * HTTPS request. Can be overridden by setting SessionCookieConfig.setSecure(true),
      * in which case the session cookie will be marked as secure on both HTTPS and HTTP.
+     * @param secureRequestOnly true to set Session Cookie Config as secure
      */
     public void setSecureRequestOnly(boolean secureRequestOnly)
     {
@@ -423,7 +421,7 @@
      * A sessioncookie is marked as secure IFF any of the following conditions are true:
      * <ol>
      * <li>SessionCookieConfig.setSecure == true</li>
-     * <li>SessionCookieConfig.setSecure == false && _secureRequestOnly==true && request is HTTPS</li>
+     * <li>SessionCookieConfig.setSecure == false &amp;&amp; _secureRequestOnly==true &amp;&amp; request is HTTPS</li>
      * </ol>
      * According to SessionCookieConfig javadoc, case 1 can be used when:
      * "... even though the request that initiated the session came over HTTP,
@@ -431,14 +429,16 @@
      * SSL offloading load balancer. In this case, the traffic between the client
      * and the load balancer will be over HTTPS, whereas the traffic between the
      * load balancer and the web container will be over HTTP."
-     *
+     * <p>
      * For case 2, you can use _secureRequestOnly to determine if you want the
-     * Servlet Spec 3.0  default behaviour when SessionCookieConfig.setSecure==false,
+     * Servlet Spec 3.0  default behavior when SessionCookieConfig.setSecure==false,
      * which is:
+     * <cite>
      * "they shall be marked as secure only if the request that initiated the
      * corresponding session was also secure"
-     *
-     * The default for _secureRequestOnly is true, which gives the above behaviour. If
+     * </cite>
+     * <p>
+     * The default for _secureRequestOnly is true, which gives the above behavior. If
      * you set it to false, then a session cookie is NEVER marked as secure, even if
      * the initiating request was secure.
      *
@@ -563,6 +563,8 @@
     {
         AbstractSession session=newSession(request);
         session.setMaxInactiveInterval(_dftMaxIdleSecs);
+        if (request.isSecure())
+            session.setAttribute(AbstractSession.SESSION_CREATED_SECURE, Boolean.TRUE);
         addSession(session,true);
         return session;
     }
@@ -613,9 +615,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param seconds
-     */
     @Override
     public void setMaxInactiveInterval(int seconds)
     {
@@ -670,6 +669,8 @@
     /**
      * Add the session Registers the session with this manager and registers the
      * session ID with the sessionIDManager;
+     * @param session the session
+     * @param created true if session was created
      */
     protected void addSession(AbstractSession session, boolean created)
     {
@@ -702,7 +703,7 @@
     /**
      * Prepare sessions for session manager shutdown
      * 
-     * @throws Exception
+     * @throws Exception if unable to shutdown sesssions
      */
     protected abstract void shutdownSessions() throws Exception;
 
@@ -710,7 +711,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Create a new session instance
-     * @param request
+     * @param request the request to build the session from
      * @return the new session
      */
     protected abstract AbstractSession newSession(HttpServletRequest request);
@@ -747,10 +748,12 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Remove session from manager
+    /** 
+     * Remove session from manager
      * @param session The session to remove
      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
      * {@link SessionIdManager#invalidateAll(String)} should be called.
+     * @return if the session was removed 
      */
     public boolean removeSession(AbstractSession session, boolean invalidate)
     {
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java
index fd2aa4d..7f2a489 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionIdManager.java
@@ -32,6 +32,8 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
+import org.eclipse.jetty.server.SessionIdManager;
+
 /* ------------------------------------------------------------ */
 /**
  * HashSessionIdManager. An in-memory implementation of the session ID manager.
@@ -62,6 +64,7 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * @param id the id of the session
      * @return Collection of Sessions for the passed session ID
      */
     public Collection<HttpSession> getSession(String id)
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
index 3396232..a54cac0 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java
@@ -599,11 +599,13 @@
                 if (isDeleteUnrestorableSessions() && file.exists() && file.getParentFile().equals(_storeDir) )
                 {
                     file.delete();
-                    LOG.warn("Deleting file for unrestorable session "+idInCuster, error);
+                    LOG.warn("Deleting file for unrestorable session {} {}",idInCuster,error);
+                    __log.debug(error);
                 }
                 else
                 {
-                    __log.warn("Problem restoring session "+idInCuster, error);
+                    __log.warn("Problem restoring session {} {}",idInCuster, error);
+                    __log.debug(error);
                 }
             }
             else
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
index 04c02b0..9a289fd 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
@@ -245,6 +245,7 @@
      *
      * The session is idled by persisting it, then clearing the session values attribute map and finally setting
      * it to an idled state.
+     * @throws Exception if unable to save session
      */
     public synchronized void idle()
     throws Exception
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java
index b5fedd2..359f8d3 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java
@@ -530,7 +530,7 @@
          * Convert a camel case identifier into either upper or lower
          * depending on the way the db stores identifiers.
          *
-         * @param identifier
+         * @param identifier the raw identifier
          * @return the converted identifier
          */
         public String convertIdentifier (String identifier)
@@ -629,8 +629,8 @@
     /**
      * Configure jdbc connection information via a jdbc Driver
      *
-     * @param driverClassName
-     * @param connectionUrl
+     * @param driverClassName the driver classname
+     * @param connectionUrl the driver connection url
      */
     public void setDriverInfo (String driverClassName, String connectionUrl)
     {
@@ -641,8 +641,8 @@
     /**
      * Configure jdbc connection information via a jdbc Driver
      *
-     * @param driverClass
-     * @param connectionUrl
+     * @param driverClass the driver class
+     * @param connectionUrl the driver connection url
      */
     public void setDriverInfo (Driver driverClass, String connectionUrl)
     {
@@ -682,9 +682,10 @@
     }
 
     /**
-     * @param name
+     * @param name the name of the blob
      * @deprecated see DbAdaptor.setBlobType
      */
+    @Deprecated
     public void setBlobType (String name)
     {
         _dbAdaptor.setBlobType(name);
@@ -704,27 +705,30 @@
     }
 
     /**
-     * @return
+     * @return the blob type
      * @deprecated see DbAdaptor.getBlobType
      */
+    @Deprecated
     public String getBlobType ()
     {
         return _dbAdaptor.getBlobType();
     }
 
     /**
-     * @return
+     * @return the long type
      * @deprecated see DbAdaptor.getLogType
      */
+    @Deprecated
     public String getLongType()
     {
         return _dbAdaptor.getLongType();
     }
 
     /**
-     * @param longType
+     * @param longType the long type
      * @deprecated see DbAdaptor.setLongType
      */
+    @Deprecated
     public void setLongType(String longType)
     {
        _dbAdaptor.setLongType(longType);
@@ -1026,7 +1030,7 @@
      * Get a connection from the driver or datasource.
      *
      * @return the connection for the datasource
-     * @throws SQLException
+     * @throws SQLException if unable to get the connection
      */
     protected Connection getConnection ()
     throws SQLException
@@ -1036,11 +1040,6 @@
         else
             return DriverManager.getConnection(_connectionUrl);
     }
-    
-
-
-
-
 
     /**
      * Set up the tables in the database
@@ -1251,6 +1250,8 @@
      */
     private void scavenge ()
     {
+        Set<String> candidateIds = getAllCandidateExpiredSessionIds();
+        
         Connection connection = null;
         try
         {
@@ -1284,7 +1285,7 @@
                         }
                     }
                 }
-                scavengeSessions(expiredSessionIds, false);
+                scavengeSessions(candidateIds, expiredSessionIds, false);
 
 
                 //Pass 2: find sessions that have expired a while ago for which this node was their last manager
@@ -1307,7 +1308,7 @@
                                 if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId="+sessionId+" last managed by "+getWorkerName());
                             }
                         }
-                        scavengeSessions(expiredSessionIds, false);
+                        scavengeSessions(candidateIds, expiredSessionIds, false);
                     }
 
 
@@ -1330,9 +1331,13 @@
                                 if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId="+sessionId);
                             }
                         }
-                        scavengeSessions(expiredSessionIds, true);
+                        scavengeSessions(candidateIds, expiredSessionIds, true);
                     }
                 }
+                
+                //Tell session managers to check remaining sessions in memory that may have expired 
+                //but are no longer in the database
+                scavengeSessions(candidateIds);
             }
         }
         catch (Exception e)
@@ -1364,24 +1369,20 @@
     /**
      * @param expiredSessionIds
      */
-    private void scavengeSessions (Set<String> expiredSessionIds, boolean forceDelete)
+    private void scavengeSessions (Set<String> candidateIds, Set<String> expiredSessionIds, boolean forceDelete)
     {       
         Set<String> remainingIds = new HashSet<String>(expiredSessionIds);
-        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
-        for (int i=0; contexts!=null && i<contexts.length; i++)
+        Set<SessionManager> managers = getAllSessionManagers();
+        for (SessionManager m:managers)
         {
-            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
-            if (sessionHandler != null)
+            Set<String> successfullyExpiredIds = ((JDBCSessionManager)m).expire(expiredSessionIds);
+            if (successfullyExpiredIds != null)
             {
-                SessionManager manager = sessionHandler.getSessionManager();
-                if (manager != null && manager instanceof JDBCSessionManager)
-                {
-                    Set<String> successfullyExpiredIds = ((JDBCSessionManager)manager).expire(expiredSessionIds);
-                    if (successfullyExpiredIds != null)
-                        remainingIds.removeAll(successfullyExpiredIds);
-                }
+                remainingIds.removeAll(successfullyExpiredIds);
+                candidateIds.removeAll(successfullyExpiredIds);
             }
         }
+    
 
         //Any remaining ids are of those sessions that no context removed
         if (!remainingIds.isEmpty() && forceDelete)
@@ -1403,6 +1404,63 @@
             }
         }
     }
+    
+    /**
+     * These are the session ids that the session managers thought had 
+     * expired, but were not expired in the database. This could be
+     * because the session is live on another node, or that the
+     * session no longer exists in the database because some other
+     * node removed it.
+     * @param candidateIds
+     */
+    private void scavengeSessions (Set<String> candidateIds)
+    {
+        if (candidateIds.isEmpty())
+            return;
+        
+        
+        Set<SessionManager> managers = getAllSessionManagers();
+        
+        for (SessionManager m:managers)
+        {
+            //tell the session managers to check the sessions that have expired in memory
+            //if they are no longer in the database, they should be removed
+            ((JDBCSessionManager)m).expireCandidates(candidateIds);
+        }
+    }
+    
+    private Set<String>  getAllCandidateExpiredSessionIds()
+    {
+        HashSet<String> candidateIds = new HashSet<>();
+        
+        Set<SessionManager> managers = getAllSessionManagers();
+        
+        for (SessionManager m:managers)
+        {
+            candidateIds.addAll(((JDBCSessionManager)m).getCandidateExpiredIds());
+        }
+        
+        return candidateIds;
+    }
+    
+    
+    private Set<SessionManager> getAllSessionManagers()
+    {
+        HashSet<SessionManager> managers = new HashSet<>();
+    
+        Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
+        for (int i=0; contexts!=null && i<contexts.length; i++)
+        {
+            SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
+            if (sessionHandler != null)
+            {
+                SessionManager manager = sessionHandler.getSessionManager();
+                if (manager != null && manager instanceof JDBCSessionManager)
+                    managers.add(manager);
+            }
+        }
+        return managers;
+    }
 
 
    
@@ -1412,7 +1470,7 @@
     {
         if (expiredIds == null || expiredIds.isEmpty())
             return;
-
+        
         String[] ids = expiredIds.toArray(new String[expiredIds.size()]);
         try (Connection con = getConnection())
         {
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java
index 1680c1b..6480b97 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java
@@ -37,6 +37,10 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.session.JDBCSessionIdManager.SessionTableSchema;
 import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
@@ -44,23 +48,24 @@
 import org.eclipse.jetty.util.log.Logger;
 
 /**
- * JDBCSessionManager
- *
+ * JDBCSessionManager.
+ * <p>
  * SessionManager that persists sessions to a database to enable clustering.
- *
+ * <p>
  * Session data is persisted to the JettySessions table:
- *
- * rowId (unique in cluster: webapp name/path + virtualhost + sessionId)
- * contextPath (of the context owning the session)
- * sessionId (unique in a context)
- * lastNode (name of node last handled session)
- * accessTime (time in milliseconds session was accessed)
- * lastAccessTime (previous time in milliseconds session was accessed)
- * createTime (time in milliseconds session created)
- * cookieTime (time in milliseconds session cookie created)
- * lastSavedTime (last time in milliseconds session access times were saved)
- * expiryTime (time in milliseconds that the session is due to expire)
- * map (attribute map)
+ * <dl>
+ * <dt>rowId</dt><dd>(unique in cluster: webapp name/path + virtualhost + sessionId)</dd>
+ * <dt>contextPath</dt><dd>(of the context owning the session)</dd>
+ * <dt>sessionId</dt><dd>(unique in a context)</dd>
+ * <dt>lastNode</dt><dd>(name of node last handled session)</dd>
+ * <dt>accessTime</dt><dd>(time in milliseconds session was accessed)</dd>
+ * <dt>lastAccessTime</dt><dd>(previous time in milliseconds session was accessed)</dd>
+ * <dt>createTime</dt><dd>(time in milliseconds session created)</dd>
+ * <dt>cookieTime</dt><dd>(time in milliseconds session cookie created)</dd>
+ * <dt>lastSavedTime</dt><dd>(last time in milliseconds session access times were saved)</dd>
+ * <dt>expiryTime</dt><dd>(time in milliseconds that the session is due to expire)</dd>
+ * <dt>map</dt><dd>(attribute map)</dd>
+ * </dl>
  *
  * As an optimization, to prevent thrashing the database, we do not persist
  * the accessTime and lastAccessTime every time the session is accessed. Rather,
@@ -94,10 +99,7 @@
         protected boolean _dirty=false;
         
         
-        /**
-         * Time in msec since the epoch that a session cookie was set for this session
-         */
-        protected long _cookieSet;
+     
         
         
         /**
@@ -139,7 +141,7 @@
         /**
          * Session from a request.
          *
-         * @param request
+         * @param request the request
          */
         protected Session (HttpServletRequest request)
         {
@@ -154,10 +156,11 @@
         
         /**
          * Session restored from database
-         * @param sessionId
-         * @param rowId
-         * @param created
-         * @param accessed
+         * @param sessionId the session id
+         * @param rowId the row id
+         * @param created the created timestamp
+         * @param accessed the access timestamp
+         * @param maxInterval the max inactive interval (in seconds)
          */
         protected Session (String sessionId, String rowId, long created, long accessed, long maxInterval)
         {
@@ -219,16 +222,7 @@
             return _canonicalContext;
         }
         
-        public void setCookieSet (long ms)
-        {
-            _cookieSet = ms;
-        }
-
-        public synchronized long getCookieSet ()
-        {
-            return _cookieSet;
-        }
-
+       
         public synchronized void setLastNode (String node)
         {
             _lastNode=node;
@@ -257,11 +251,6 @@
                 _dirty=true;
         }
 
-        @Override
-        protected void cookieSet()
-        {
-            _cookieSet = getAccessed();
-        }
 
         /**
          * Entry to session.
@@ -396,7 +385,7 @@
         {
             return "Session rowId="+_rowId+",id="+getId()+",lastNode="+_lastNode+
                             ",created="+getCreationTime()+",accessed="+getAccessed()+
-                            ",lastAccessed="+getLastAccessedTime()+",cookieSet="+_cookieSet+
+                            ",lastAccessed="+getLastAccessedTime()+",cookieSet="+getCookieSetTime()+
                             ",maxInterval="+getMaxInactiveInterval()+",lastSaved="+_lastSaved+",expiry="+_expiryTime;
         }
     }
@@ -420,7 +409,7 @@
      * If any session attribute does change, then the attributes and
      * the accessed time are persisted.
      *
-     * @param sec
+     * @param sec the save interval in seconds
      */
     public void setSaveInterval (long sec)
     {
@@ -443,7 +432,7 @@
      * This could be used eg with a JMS backplane to notify nodes
      * that the session has changed and to delete the session from
      * the node's cache, and re-read it from the database.
-     * @param session
+     * @param session the session to invalidate
      */
     public void cacheInvalidate (Session session)
     {
@@ -580,6 +569,11 @@
             }
             else
             {
+                if (memSession != null)
+                {
+                    //Session must have been removed from db by another node
+                    removeSession(memSession, true);
+                }
                 //No session in db with matching id and context path.
                 LOG.debug("getSession({}): No session in database matching id={}",idInCluster,idInCluster);
             }
@@ -706,7 +700,7 @@
     /**
      * Invalidate a session.
      *
-     * @param idInCluster
+     * @param idInCluster the id in the cluster
      */
     protected void invalidateSession (String idInCluster)
     {
@@ -781,15 +775,6 @@
         return new Session(request);
     }
     
-    
-    /**
-     * @param sessionId
-     * @param rowId
-     * @param created
-     * @param accessed
-     * @param maxInterval
-     * @return
-     */
     protected AbstractSession newSession (String sessionId, String rowId, long created, long accessed, long maxInterval)
     {
         return new Session(sessionId, rowId, created, accessed, maxInterval);
@@ -823,7 +808,8 @@
      * Expire any Sessions we have in memory matching the list of
      * expired Session ids.
      *
-     * @param sessionIds
+     * @param sessionIds the session ids to expire
+     * @return the set of successfully expired ids
      */
     protected Set<String> expire (Set<String> sessionIds)
     {
@@ -885,12 +871,61 @@
         }
     }
     
-  
+    protected void expireCandidates (Set<String> candidateIds)
+    {
+        Iterator<String> itor = candidateIds.iterator();
+        long now = System.currentTimeMillis();
+        while (itor.hasNext())
+        {
+            String id = itor.next();
+
+            //check if expired in db
+            try
+            {
+                Session memSession = _sessions.get(id);
+                if (memSession == null)
+                {
+                    continue; //no longer in memory
+                }
+
+                Session s = loadSession(id,  canonicalize(_context.getContextPath()), getVirtualHost(_context));
+                if (s == null)
+                {
+                    //session no longer exists, can be safely expired
+                    memSession.timeout();
+                }
+            }
+            catch (Exception e)
+            {
+                LOG.warn("Error checking db for expiry for session {}", id);
+            }
+        }
+    }
+    
+    protected Set<String> getCandidateExpiredIds ()
+    {
+        HashSet<String> expiredIds = new HashSet<>();
+
+        Iterator<String> itor = _sessions.keySet().iterator();
+        while (itor.hasNext())
+        {
+            String id = itor.next();
+            //check to see if session should have expired
+            Session session = _sessions.get(id);
+            if (session._expiryTime > 0 &&  System.currentTimeMillis() > session._expiryTime)
+                expiredIds.add(id);           
+        }
+        return expiredIds;
+    }
+
+
     /**
      * Load a session from the database
-     * @param id
+     * @param id the id
+     * @param canonicalContextPath the canonical context path
+     * @param vhost the virtual host
      * @return the session data that was loaded
-     * @throws Exception
+     * @throws Exception if unable to load the session
      */
     protected Session loadSession (final String id, final String canonicalContextPath, final String vhost)
     throws Exception
@@ -921,7 +956,7 @@
                                                   result.getLong(_sessionTableSchema.getCreateTimeColumn()), 
                                                   result.getLong(_sessionTableSchema.getAccessTimeColumn()), 
                                                   maxInterval);
-                        session.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
+                        session.setCookieSetTime(result.getLong(_sessionTableSchema.getCookieTimeColumn()));
                         session.setLastAccessedTime(result.getLong(_sessionTableSchema.getLastAccessTimeColumn()));
                         session.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn()));
                         session.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn()));
@@ -954,7 +989,7 @@
         if (_context==null)
             load.run();
         else
-            _context.getContextHandler().handle(load);
+            _context.getContextHandler().handle(null,load);
 
         if (_exception.get()!=null)
         {
@@ -970,8 +1005,8 @@
     /**
      * Insert a session into the database.
      *
-     * @param session
-     * @throws Exception
+     * @param session the session
+     * @throws Exception if unable to store the session
      */
     protected void storeSession (Session session)
     throws Exception
@@ -995,7 +1030,7 @@
             statement.setLong(6, session.getAccessed());//accessTime
             statement.setLong(7, session.getLastAccessedTime()); //lastAccessTime
             statement.setLong(8, session.getCreationTime()); //time created
-            statement.setLong(9, session.getCookieSet());//time cookie was set
+            statement.setLong(9, session.getCookieSetTime());//time cookie was set
             statement.setLong(10, now); //last saved time
             statement.setLong(11, session.getExpiryTime());
             statement.setLong(12, session.getMaxInactiveInterval());
@@ -1023,7 +1058,7 @@
      * Update data on an existing persisted session.
      *
      * @param data the session
-     * @throws Exception
+     * @throws Exception if unable to update the session
      */
     protected void updateSession (Session data)
     throws Exception
@@ -1066,7 +1101,7 @@
      * Update the node on which the session was last seen to be my node.
      *
      * @param data the session
-     * @throws Exception
+     * @throws Exception if unable to update the session node
      */
     protected void updateSessionNode (Session data)
     throws Exception
@@ -1120,8 +1155,8 @@
      * Delete a session from the database. Should only be called
      * when the session has been invalidated.
      *
-     * @param data
-     * @throws Exception
+     * @param data the session data
+     * @throws Exception if unable to delete the session
      */
     protected void deleteSession (Session data)
     throws Exception
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
index f89aaa4..2126583 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java
@@ -158,7 +158,7 @@
                 session = baseRequest.getSession(false);
                 if (session != null)
                 {
-                    if (session != old_session)
+                    if ((session != old_session) && (request.getDispatcherType() == DispatcherType.ASYNC || request.getDispatcherType() == DispatcherType.REQUEST))
                     {
                         access = session;
                         HttpCookie cookie = _sessionManager.access(session,request.isSecure());
@@ -192,11 +192,14 @@
         }
         finally
         {
+            //if we accessed an existing session entering this context, then complete it
             if (access != null)
                 _sessionManager.complete(access);
 
+            
+            //if there is a session that was created during handling this context, then complete it
             HttpSession session = baseRequest.getSession(false);
-            if (session != null && old_session == null && session != access)
+            if ((session != null && old_session == null && session != access) && (request.getDispatcherType() == DispatcherType.ASYNC || request.getDispatcherType() == DispatcherType.REQUEST))
                 _sessionManager.complete(session);
 
             if (old_session_manager != null && old_session_manager != _sessionManager)
@@ -228,8 +231,8 @@
     /**
      * Look for a requested session ID in cookies and URI parameters
      *
-     * @param baseRequest
-     * @param request
+     * @param baseRequest the request to check
+     * @param request the request to check
      */
     protected void checkRequestedSessionId(Request baseRequest, HttpServletRequest request)
     {
@@ -321,9 +324,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @param listener
-     */
     public void addEventListener(EventListener listener)
     {
         if (_sessionManager != null)
@@ -331,9 +331,6 @@
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param listener
-     */
     public void removeEventListener(EventListener listener)
     {
         if (_sessionManager != null)
diff --git a/jetty-server/src/test/config/etc/keystore b/jetty-server/src/test/config/etc/keystore
new file mode 100644
index 0000000..d6592f9
--- /dev/null
+++ b/jetty-server/src/test/config/etc/keystore
Binary files differ
diff --git a/jetty-server/src/main/config/etc/keystore.pkf b/jetty-server/src/test/config/etc/keystore.pkf
similarity index 100%
rename from jetty-server/src/main/config/etc/keystore.pkf
rename to jetty-server/src/test/config/etc/keystore.pkf
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
index 4b827a7..0868953 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AbstractHttpTest.java
@@ -18,9 +18,6 @@
 
 package org.eclipse.jetty.server;
 
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -29,6 +26,9 @@
 import java.net.Socket;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -36,15 +36,25 @@
 
 import org.eclipse.jetty.io.ArrayByteBufferPool;
 import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.toolchain.test.TestTracker;
 import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser;
 import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.StdErrLog;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 public abstract class AbstractHttpTest
 {
+    private final static Set<String> __noBodyCodes = new HashSet<>(Arrays.asList(new String[]{"100","101","102","204","304"}));
+    
+    @Rule
+    public TestTracker tracker = new TestTracker();
+
     protected static Server server;
     protected static ServerConnector connector;
     protected String httpVersion;
@@ -80,16 +90,17 @@
         socket.setSoTimeout((int)connector.getIdleTimeout());
         BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
         PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
-        String request = "GET / " + httpVersion + "\r\n";
 
-        writer.write(request);
-        writer.write("Host: localhost");
-        writer.println("\r\n");
+        writer.write("GET / " + httpVersion + "\r\n");
+        writer.write("Host: localhost\r\n");
+        writer.write("\r\n");
         writer.flush();
 
         SimpleHttpResponse response = httpParser.readResponse(reader);
-        if ("HTTP/1.1".equals(httpVersion) && response.getHeaders().get("content-length") == null && response
-                .getHeaders().get("transfer-encoding") == null)
+        if ("HTTP/1.1".equals(httpVersion) 
+            && response.getHeaders().get("content-length") == null 
+            && response.getHeaders().get("transfer-encoding") == null
+            && !__noBodyCodes.contains(response.getCode()))
             assertThat("If HTTP/1.1 response doesn't contain transfer-encoding or content-length headers, " +
                     "it should contain connection:close", response.getHeaders().get("connection"), is("close"));
         return response;
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java
index 2ef8d4b..928f121 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java
@@ -18,11 +18,6 @@
 
 package org.eclipse.jetty.server;
 
-import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -47,6 +42,11 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 public class AsyncRequestReadTest
 {
     private static Server server;
@@ -75,11 +75,11 @@
     {
         server.setHandler(new AsyncStreamHandler());
         server.start();
-        
+
         try (final Socket socket =  new Socket("localhost",connector.getLocalPort()))
         {
             socket.setSoTimeout(1000);
-            
+
             byte[] content = new byte[32*4096];
             Arrays.fill(content, (byte)120);
 
@@ -93,8 +93,8 @@
             byte[] h=header.getBytes(StandardCharsets.ISO_8859_1);
             out.write(h);
             out.write(content);
-            
-            
+
+
             header=
                 "POST / HTTP/1.1\r\n"+
                     "Host: localhost\r\n"+
@@ -123,7 +123,7 @@
     {
         server.setHandler(new AsyncStreamHandler());
         server.start();
-        
+
         asyncReadTest(64,4,4,20);
         asyncReadTest(256,16,16,50);
         asyncReadTest(256,1,128,10);
@@ -184,7 +184,7 @@
 
             final AsyncContext async = request.startAsync();
             // System.err.println("handle "+request.getContentLength());
-            
+
             new Thread()
             {
                 @Override
@@ -194,7 +194,7 @@
                     try(InputStream in = request.getInputStream();)
                     {
                         // System.err.println("reading...");
-                        
+
                         byte[] b = new byte[4*4096];
                         int read;
                         while((read =in.read(b))>=0)
@@ -216,18 +216,18 @@
             }.start();
         }
     }
-    
+
 
     @Test
     public void testPartialRead() throws Exception
     {
         server.setHandler(new PartialReaderHandler());
         server.start();
-        
+
         try (final Socket socket =  new Socket("localhost",connector.getLocalPort()))
         {
-            socket.setSoTimeout(1000);
-            
+            socket.setSoTimeout(10000);
+
             byte[] content = new byte[32*4096];
             Arrays.fill(content, (byte)88);
 
@@ -241,7 +241,7 @@
             byte[] h=header.getBytes(StandardCharsets.ISO_8859_1);
             out.write(h);
             out.write(content);
-            
+
             header= "POST /?read=10 HTTP/1.1\r\n"+
                     "Host: localhost\r\n"+
                     "Content-Length: "+content.length+"\r\n"+
@@ -252,7 +252,7 @@
             out.write(h);
             out.write(content);
             out.flush();
-            
+
             BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
             assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
             assertThat(in.readLine(),containsString("Content-Length:"));
@@ -273,11 +273,11 @@
     {
         server.setHandler(new PartialReaderHandler());
         server.start();
-        
+
         try (final Socket socket =  new Socket("localhost",connector.getLocalPort()))
         {
             socket.setSoTimeout(10000);
-            
+
             byte[] content = new byte[32*4096];
             Arrays.fill(content, (byte)88);
 
@@ -308,11 +308,11 @@
     {
         server.setHandler(new PartialReaderHandler());
         server.start();
-        
+
         try (final Socket socket =  new Socket("localhost",connector.getLocalPort()))
         {
             socket.setSoTimeout(1000);
-            
+
             byte[] content = new byte[32*4096];
             Arrays.fill(content, (byte)88);
 
@@ -334,7 +334,7 @@
             assertThat(in.readLine(),containsString("Server:"));
             in.readLine();
             assertThat(in.readLine(),containsString("XXXXXXX"));
-            
+
             socket.close();
         }
     }
@@ -346,7 +346,7 @@
         {
             httpResponse.setStatus(200);
             request.setHandled(true);
-                        
+
             BufferedReader in = request.getReader();
             PrintWriter out =httpResponse.getWriter();
             int read=Integer.valueOf(request.getParameter("read"));
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java
index 9487f13..3b28b83 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncStressTest.java
@@ -202,7 +202,7 @@
             long resume_after=-1;
             long complete_after=-1;
 
-            final String uri=baseRequest.getUri().toString();
+            final String uri=baseRequest.getHttpURI().toString();
 
             if (request.getParameter("read")!=null)
                 read_before=Integer.parseInt(request.getParameter("read"));
@@ -255,7 +255,7 @@
                                     Request br=(Request)asyncContext.getRequest();
                                     System.err.println("\n"+e.toString());
                                     System.err.println(baseRequest+"=="+br);
-                                    System.err.println(uri+"=="+br.getUri());
+                                    System.err.println(uri+"=="+br.getHttpURI());
                                     System.err.println(asyncContext+"=="+br.getHttpChannelState());
 
                                     LOG.warn(e);
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java
index dd49732..be12cd9 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectionOpenCloseTest.java
@@ -188,8 +188,8 @@
         server.start();
 
         final AtomicInteger callbacks = new AtomicInteger();
-        final CountDownLatch openLatch = new CountDownLatch(1);
-        final CountDownLatch closeLatch = new CountDownLatch(1);
+        final CountDownLatch openLatch = new CountDownLatch(2);
+        final CountDownLatch closeLatch = new CountDownLatch(2);
         connector.addBean(new Connection.Listener.Adapter()
         {
             @Override
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorCloseTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorCloseTestBase.java
index 4977a54..8bcff8a 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorCloseTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorCloseTestBase.java
@@ -30,11 +30,14 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * HttpServer Tester.
  */
+@RunWith(AdvancedRunner.class)
 public abstract class ConnectorCloseTestBase extends HttpServerTestFixture
 {
     private static String __content =
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java
index ce71002..02eced9 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java
@@ -18,11 +18,17 @@
 
 package org.eclipse.jetty.server;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.Socket;
 import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.concurrent.Exchanger;
 import java.util.concurrent.TimeUnit;
 
@@ -31,16 +37,29 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
+import org.eclipse.jetty.toolchain.test.TestTracker;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.StdErrLog;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@RunWith(AdvancedRunner.class)
 public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
 {
+    @Rule
+    public TestTracker tracker = new TestTracker();
+    
     protected static final int MAX_IDLE_TIME=500;
     private int sleepTime = MAX_IDLE_TIME + MAX_IDLE_TIME/5;
     private int minimumTestRuntime = MAX_IDLE_TIME-MAX_IDLE_TIME/5;
@@ -51,8 +70,15 @@
         System.setProperty("org.eclipse.jetty.io.nio.IDLE_TICK","100");
     }
 
+    @Before
+    public void before()
+    {
+        super.before();
+        if (_httpConfiguration!=null)
+            _httpConfiguration.setBlockingTimeout(-1L);
+    }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithRequest10() throws Exception
     {
         configureServer(new HelloWorldHandler());
@@ -82,7 +108,7 @@
         Assert.assertTrue(System.currentTimeMillis() - start < maximumTestRuntime);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithRequest11() throws Exception
     {
         configureServer(new EchoHandler());
@@ -115,7 +141,7 @@
         Assert.assertTrue(System.currentTimeMillis() - start < maximumTestRuntime);
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithRequest10NoClientClose() throws Exception
     {
         final Exchanger<EndPoint> exchanger = new Exchanger<>();
@@ -189,7 +215,7 @@
         Assert.assertFalse(endPoint.isOpen());
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithRequest10ClientIgnoresClose() throws Exception
     {
         final Exchanger<EndPoint> exchanger = new Exchanger<>();
@@ -265,7 +291,7 @@
         Assert.assertFalse(endPoint.isOpen());
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithRequest11NoClientClose() throws Exception
     {
         final Exchanger<EndPoint> exchanger = new Exchanger<>();
@@ -342,7 +368,232 @@
         Assert.assertFalse(endPoint.isOpen());
     }
 
-    @Test
+    @Test(timeout=60000)
+    @Ignore // TODO make more stable
+    public void testNoBlockingTimeoutRead() throws Exception
+    {
+        _httpConfiguration.setBlockingTimeout(-1L);
+        
+        configureServer(new EchoHandler());
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+        InputStream is=client.getInputStream();
+        Assert.assertFalse(client.isClosed());
+
+        OutputStream os=client.getOutputStream();
+        os.write(("GET / HTTP/1.1\r\n"+
+                "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                "Transfer-Encoding: chunked\r\n" +
+                "Content-Type: text/plain\r\n" +
+                "Connection: close\r\n" +
+                "\r\n"+
+                "5\r\n"+
+                "LMNOP\r\n")
+                .getBytes("utf-8"));
+        os.flush();
+
+        long start = System.currentTimeMillis();
+        try
+        {
+            Thread.sleep(250);
+            os.write("1".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(250);
+            os.write("0".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(250);
+            os.write("\r".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(250);
+            os.write("\n".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(250);
+            os.write("0123456789ABCDEF\r\n".getBytes("utf-8"));
+            os.write("0\r\n".getBytes("utf-8"));
+            os.write("\r\n".getBytes("utf-8"));
+            os.flush();   
+        }
+        catch(Exception e)
+        {
+            e.printStackTrace();
+        }
+        long duration=System.currentTimeMillis() - start;
+        Assert.assertThat(duration,Matchers.greaterThan(500L));
+
+        // read the response
+        String response = IO.toString(is);
+        Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK"));
+        Assert.assertThat(response,Matchers.containsString("LMNOP0123456789ABCDEF"));
+
+    }
+    
+    @Test(timeout=60000)
+    @Ignore // TODO make more stable
+    public void testBlockingTimeoutRead() throws Exception
+    {
+        _httpConfiguration.setBlockingTimeout(750L);
+        
+        configureServer(new EchoHandler());
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+        InputStream is=client.getInputStream();
+        Assert.assertFalse(client.isClosed());
+
+        OutputStream os=client.getOutputStream();
+        os.write(("GET / HTTP/1.1\r\n"+
+                "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                "Transfer-Encoding: chunked\r\n" +
+                "Content-Type: text/plain\r\n" +
+                "Connection: close\r\n" +
+                "\r\n"+
+                "5\r\n"+
+                "LMNOP\r\n")
+                .getBytes("utf-8"));
+        os.flush();
+
+        long start = System.currentTimeMillis();
+        try
+        {
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
+            Thread.sleep(300);
+            os.write("1".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(300);
+            os.write("0".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(300);
+            os.write("\r".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(300);
+            os.write("\n".getBytes("utf-8"));
+            os.flush();
+            Thread.sleep(300);
+            os.write("0123456789ABCDEF\r\n".getBytes("utf-8"));
+            os.write("0\r\n".getBytes("utf-8"));
+            os.write("\r\n".getBytes("utf-8"));
+            os.flush();   
+        }
+        catch(Exception e)
+        {
+        }
+        finally
+        {
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
+        }
+        long duration=System.currentTimeMillis() - start;
+        Assert.assertThat(duration,Matchers.greaterThan(500L));
+        
+        try
+        {
+            // read the response
+            String response = IO.toString(is);
+            Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 500 "));
+            Assert.assertThat(response,Matchers.containsString("InterruptedIOException"));
+        }
+        catch(SSLException e)
+        {
+        }
+
+    }
+
+    @Test(timeout=60000)
+    @Ignore // TODO make more stable
+    public void testNoBlockingTimeoutWrite() throws Exception
+    {
+        configureServer(new HugeResponseHandler());
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+
+        Assert.assertFalse(client.isClosed());
+
+        OutputStream os=client.getOutputStream();
+        BufferedReader is=new BufferedReader(new InputStreamReader(client.getInputStream(),StandardCharsets.ISO_8859_1),2048);
+
+        os.write((
+                "GET / HTTP/1.0\r\n"+
+                "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                "connection: keep-alive\r\n"+
+                "Connection: close\r\n"+
+        "\r\n").getBytes("utf-8"));
+        os.flush();
+        
+        // read the header
+        String line=is.readLine();
+        Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK"));
+        while(line.length()!=0)
+            line=is.readLine();
+        
+        for (int i=0;i<(128*1024);i++)
+        {
+            if (i%1028==0)
+            {
+                Thread.sleep(20);
+                // System.err.println("read "+System.currentTimeMillis());
+            }
+            line=is.readLine();
+            Assert.assertThat(line,Matchers.notNullValue());
+            Assert.assertEquals(1022,line.length());
+        }
+    }
+
+    @Test(timeout=60000)
+    @Ignore // TODO make more stable
+    public void testBlockingTimeoutWrite() throws Exception
+    {
+        _httpConfiguration.setBlockingTimeout(750L);
+        configureServer(new HugeResponseHandler());
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+
+        Assert.assertFalse(client.isClosed());
+
+        OutputStream os=client.getOutputStream();
+        BufferedReader is=new BufferedReader(new InputStreamReader(client.getInputStream(),StandardCharsets.ISO_8859_1),2048);
+
+        os.write((
+                "GET / HTTP/1.0\r\n"+
+                "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                "connection: keep-alive\r\n"+
+                "Connection: close\r\n"+
+        "\r\n").getBytes("utf-8"));
+        os.flush();
+        
+        // read the header
+        String line=is.readLine();
+        Assert.assertThat(line,Matchers.startsWith("HTTP/1.1 200 OK"));
+        while(line.length()!=0)
+            line=is.readLine();
+
+        long start=System.currentTimeMillis();
+        try
+        {
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
+            ((StdErrLog)Log.getLogger(AbstractConnection.class)).setHideStacks(true);
+            for (int i=0;i<(128*1024);i++)
+            {
+                if (i%1028==0)
+                {
+                    Thread.sleep(20);
+                    // System.err.println("read "+System.currentTimeMillis());
+                }
+                line=is.readLine();
+                if (line==null)
+                    break;
+            }
+        }
+        catch(Throwable e)
+        {}
+        finally
+        {
+            ((StdErrLog)Log.getLogger(AbstractConnection.class)).setHideStacks(false);
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
+        }
+        long end=System.currentTimeMillis();
+        long duration = end-start;
+        Assert.assertThat(duration,Matchers.lessThan(20L*128L));
+    }
+    
+    @Test(timeout=60000)
     public void testMaxIdleNoRequest() throws Exception
     {
         configureServer(new EchoHandler());
@@ -351,6 +602,38 @@
         InputStream is=client.getInputStream();
         Assert.assertFalse(client.isClosed());
 
+        OutputStream os=client.getOutputStream();
+        os.write("GET ".getBytes("utf-8"));
+        os.flush();
+
+        Thread.sleep(sleepTime);
+        long start = System.currentTimeMillis();
+        try
+        {
+            IO.toString(is);
+            Assert.assertEquals(-1, is.read());
+        }
+        catch(SSLException e)
+        {
+            e.printStackTrace();
+        }
+        catch(Exception e)
+        {
+            e.printStackTrace();
+        }
+        Assert.assertTrue(System.currentTimeMillis() - start < maximumTestRuntime);
+
+    }
+
+    @Test(timeout=60000)
+    public void testMaxIdleNothingSent() throws Exception
+    {
+        configureServer(new EchoHandler());
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+        InputStream is=client.getInputStream();
+        Assert.assertFalse(client.isClosed());
+
         Thread.sleep(sleepTime);
         long start = System.currentTimeMillis();
         try
@@ -360,7 +643,7 @@
         }
         catch(SSLException e)
         {
-
+            // e.printStackTrace();
         }
         catch(Exception e)
         {
@@ -370,7 +653,7 @@
 
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithSlowRequest() throws Exception
     {
         configureServer(new EchoHandler());
@@ -410,7 +693,7 @@
         }
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithSlowResponse() throws Exception
     {
         configureServer(new SlowResponseHandler());
@@ -439,7 +722,7 @@
         }
     }
 
-    @Test
+    @Test(timeout=60000)
     public void testMaxIdleWithWait() throws Exception
     {
         configureServer(new WaitHandler());
@@ -482,6 +765,27 @@
             out.close();
         }
     }
+    
+    protected static class HugeResponseHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            response.setStatus(200);
+            OutputStream out = response.getOutputStream();
+            byte[] buffer = new byte[128*1024*1024];
+            Arrays.fill(buffer,(byte)'x');
+            for (int i=0;i<128*1024;i++)
+            {
+                buffer[i*1024+1022]='\r';
+                buffer[i*1024+1023]='\n';
+            }
+            ByteBuffer bb = ByteBuffer.wrap(buffer);
+            ((HttpOutput)out).sendContent(bb);
+            out.close();
+        }
+    }
 
     protected static class WaitHandler extends AbstractHandler
     {
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/DumpHandler.java b/jetty-server/src/test/java/org/eclipse/jetty/server/DumpHandler.java
index f7e08a3..806d413 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/DumpHandler.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/DumpHandler.java
@@ -106,6 +106,8 @@
         writer.write("<pre>\ncontentType="+request.getContentType()+"\n</pre>\n");
         writer.write("<pre>\nencoding="+request.getCharacterEncoding()+"\n</pre>\n");
         writer.write("<pre>\nservername="+request.getServerName()+"\n</pre>\n");
+        writer.write("<pre>\nlocal="+request.getLocalAddr()+":"+request.getLocalPort()+"\n</pre>\n");
+        writer.write("<pre>\nremote="+request.getRemoteAddr()+":"+request.getRemotePort()+"\n</pre>\n");
         writer.write("<h3>Header:</h3><pre>");
         writer.write(request.getMethod()+" "+request.getRequestURI()+" "+request.getProtocol()+"\n");
         Enumeration<String> headers = request.getHeaderNames();
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java
index 6264c86..d758a4d 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java
@@ -21,7 +21,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.Socket;
-import java.nio.ByteBuffer;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.nio.charset.StandardCharsets;
@@ -30,12 +29,11 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.util.thread.Scheduler;
 import org.hamcrest.Matchers;
@@ -80,10 +78,10 @@
         }
 
         @Override
-        public void onSelected()
+        public Runnable onSelected()
         {
             _lastSelected=System.currentTimeMillis();
-            super.onSelected();
+            return super.onSelected();
         }
 
         long getLastSelected()
@@ -100,15 +98,15 @@
         }
 
         @Override
-        protected HttpChannelOverHttp newHttpChannel(HttpInput<ByteBuffer> httpInput)
+        protected HttpChannelOverHttp newHttpChannel()
         {
-            return new HttpChannelOverHttp(getConnector(), getHttpConfiguration(), getEndPoint(), this, httpInput)
+            return new HttpChannelOverHttp(this, getConnector(), getHttpConfiguration(), getEndPoint(), this)
             {
                 @Override
-                public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
+                public boolean startRequest(String method, String uri, HttpVersion version)
                 {
                     getRequest().setAttribute("DispatchedAt",((ExtendedEndPoint)getEndPoint()).getLastSelected());
-                    return super.startRequest(httpMethod,method,uri,version);
+                    return super.startRequest(method,uri,version);
                 }
             };
         }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java
index 8312da2..8e67c62 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java
@@ -18,116 +18,286 @@
 
 package org.eclipse.jetty.server;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertThat;
+
+import java.io.EOFException;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.ConnectException;
 import java.net.Socket;
-import java.nio.charset.StandardCharsets;
+import java.nio.channels.ClosedChannelException;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.io.EofException;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.StatisticsHandler;
 import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
-public class GracefulStopTest
+public class GracefulStopTest 
 {
-    private Server server;
-
-    @Before
-    public void setup() throws Exception
+    /**
+     * Test of standard graceful timeout mechanism when a block request does
+     * not complete
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testGracefulNoWaiter() throws Exception
     {
-        server = new Server(0);
-        StatisticsHandler stats = new StatisticsHandler();
-        TestHandler test=new TestHandler();
-        server.setHandler(stats);
-        stats.setHandler(test);
-        server.setStopTimeout(10 * 1000);
-        
+        Server server= new Server();
+        server.setStopTimeout(1000);
+
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        TestHandler handler = new TestHandler();
+        server.setHandler(handler);
+
         server.start();
+        final int port=connector.getLocalPort();
+        Socket client = new Socket("127.0.0.1", port);
+        client.getOutputStream().write((
+                "POST / HTTP/1.0\r\n"+
+                        "Host: localhost:"+port+"\r\n" +
+                        "Content-Type: plain/text\r\n" +
+                        "Content-Length: 10\r\n" +
+                        "\r\n"+
+                        "12345"
+                ).getBytes());
+        client.getOutputStream().flush();
+        handler.latch.await();
+
+        long start = System.nanoTime();
+        server.stop();
+        long stop = System.nanoTime();
+        
+        // No Graceful waiters
+        assertThat(TimeUnit.NANOSECONDS.toMillis(stop-start),lessThan(900L));
+
+        assertThat(client.getInputStream().read(),Matchers.is(-1));
+
+        assertThat(handler.handling.get(),Matchers.is(false));
+        assertThat(handler.thrown.get(),
+                Matchers.anyOf(
+                instanceOf(ClosedChannelException.class),
+                instanceOf(EofException.class),
+                instanceOf(EOFException.class))
+                );
+
+        client.close();
     }
 
+    /**
+     * Test of standard graceful timeout mechanism when a block request does
+     * not complete
+     * @throws Exception on test failure
+     */
     @Test
-    public void testGraceful() throws Exception
+    public void testGracefulTimeout() throws Exception
     {
-        new Thread()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    TimeUnit.SECONDS.sleep(1);
-                    server.stop();
-                }
-                catch (Exception e)
-                {
-                    e.printStackTrace();
-                }
-            }
-        }.start();
+        Server server= new Server();
+        server.setStopTimeout(1000);
 
-        try(Socket socket = new Socket("localhost",server.getBean(NetworkConnector.class).getLocalPort());)
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        TestHandler handler = new TestHandler();
+        StatisticsHandler stats = new StatisticsHandler();
+        server.setHandler(stats);
+        stats.setHandler(handler);
+
+        server.start();
+        final int port=connector.getLocalPort();
+        Socket client = new Socket("127.0.0.1", port);
+        client.getOutputStream().write((
+                "POST / HTTP/1.0\r\n"+
+                        "Host: localhost:"+port+"\r\n" +
+                        "Content-Type: plain/text\r\n" +
+                        "Content-Length: 10\r\n" +
+                        "\r\n"+
+                        "12345"
+                ).getBytes());
+        client.getOutputStream().flush();
+        handler.latch.await();
+
+        long start = System.nanoTime();
+        try
         {
-            socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
-            String out = IO.toString(socket.getInputStream());
-            Assert.assertThat(out,Matchers.containsString("200 OK"));
+            server.stop();
+            Assert.fail();
         }
-    }
-    
-    @Test
-    public void testGracefulTimout() throws Exception
-    {
-        server.setStopTimeout(100);
-        new Thread()
+        catch(TimeoutException e)
         {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    TimeUnit.SECONDS.sleep(1);
-                    server.stop();
-                }
-                catch (Exception e)
-                {
-                    //e.printStackTrace();
-                }
-            }
-        }.start();
+            long stop = System.nanoTime();
+            // No Graceful waiters
+            assertThat(TimeUnit.NANOSECONDS.toMillis(stop-start),greaterThan(900L));
+        }
 
-        try(Socket socket = new Socket("localhost",server.getBean(NetworkConnector.class).getLocalPort());)
+        assertThat(client.getInputStream().read(),Matchers.is(-1));
+
+        assertThat(handler.handling.get(),Matchers.is(false));
+        assertThat(handler.thrown.get(),instanceOf(ClosedChannelException.class));
+
+        client.close();
+    }
+
+
+    /**
+     * Test of standard graceful timeout mechanism when a block request does
+     * complete. Note that even though the request completes after 100ms, the
+     * stop always takes 1000ms
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testGracefulComplete() throws Exception
+    {
+        Server server= new Server();
+        server.setStopTimeout(10000);
+
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.addConnector(connector);
+
+        TestHandler handler = new TestHandler();
+        StatisticsHandler stats = new StatisticsHandler();
+        server.setHandler(stats);
+        stats.setHandler(handler);
+
+        server.start();
+        final int port=connector.getLocalPort();
+
+        try(final Socket client1 = new Socket("127.0.0.1", port);final Socket client2 = new Socket("127.0.0.1", port);)
         {
-            socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
-            String out = IO.toString(socket.getInputStream());
-            Assert.assertEquals("",out);
+            client1.getOutputStream().write((
+                    "POST / HTTP/1.0\r\n"+
+                            "Host: localhost:"+port+"\r\n" +
+                            "Content-Type: plain/text\r\n" +
+                            "Content-Length: 10\r\n" +
+                            "\r\n"+
+                            "12345"
+                    ).getBytes());
+            client1.getOutputStream().flush();
+            handler.latch.await();
+
+            new Thread()
+            {
+                @Override
+                public void run() 
+                {
+                    long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
+                    long end = now+500;
+                    
+
+                    
+                    try
+                    {
+                        Thread.sleep(100);
+
+                        // Try creating a new connection
+                        try
+                        {
+                            new Socket("127.0.0.1", port);
+                            throw new IllegalStateException();
+                        }
+                        catch(ConnectException e)
+                        {
+                            
+                        }
+                        
+                        // Try another request on existing connection
+
+                        client2.getOutputStream().write((
+                                "GET / HTTP/1.0\r\n"+
+                                        "Host: localhost:"+port+"\r\n" +
+                                        "\r\n"
+                                ).getBytes());
+                        client2.getOutputStream().flush();
+                        String response2 = IO.toString(client2.getInputStream());
+                        assertThat(response2, containsString(" 503 "));
+
+                        now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
+                        Thread.sleep(end-now);
+                        client1.getOutputStream().write("567890".getBytes());
+                    }
+                    catch(Exception e)
+                    {
+                        e.printStackTrace();
+                    }
+                }
+            }.start();
+
+            long start = System.nanoTime();
+            server.stop();
+            long stop = System.nanoTime();
+            assertThat(TimeUnit.NANOSECONDS.toMillis(stop-start),greaterThan(490L));
+            assertThat(TimeUnit.NANOSECONDS.toMillis(stop-start),lessThan(10000L));
+
+            String response = IO.toString(client1.getInputStream());
+
+            assertThat(handler.handling.get(),Matchers.is(false));
+            assertThat(response, containsString(" 200 OK"));
+            assertThat(response, containsString("read 10/10"));
+            
+            assertThat(stats.getRequests(),Matchers.is(2));
+            assertThat(stats.getResponses5xx(),Matchers.is(1));
         }
     }
 
-    private static class TestHandler extends AbstractHandler
-    {
+
+    static class TestHandler extends AbstractHandler 
+    {		
+        final CountDownLatch latch = new CountDownLatch(1);
+        final AtomicReference<Throwable> thrown = new AtomicReference<Throwable>();
+        final AtomicBoolean handling = new AtomicBoolean(false);
+
         @Override
-        public void handle(final String s, final Request request, final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse)
-            throws IOException, ServletException
+        public void handle(String target, Request baseRequest,
+                HttpServletRequest request, HttpServletResponse response)
+                        throws IOException, ServletException 
         {
+            handling.set(true);
+            latch.countDown();
+            int c=0;
             try
             {
-                TimeUnit.SECONDS.sleep(2);
-            }
-            catch (InterruptedException e)
-            {
-            }
+                int content_length = request.getContentLength();
+                InputStream in = request.getInputStream();
 
-            httpServletResponse.getWriter().write("OK");
-            httpServletResponse.setStatus(200);
-            request.setHandled(true);
+                while(true)
+                {
+                    if (in.read()<0)
+                        break;
+                    c++;
+                }
+
+                baseRequest.setHandled(true);
+                response.setStatus(200);
+                response.getWriter().printf("read %d/%d%n",c,content_length);
+            }
+            catch(Throwable th)
+            {
+                thrown.set(th);
+            }
+            finally
+            {
+                handling.set(false);
+            }
         }
     }
 
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
index bdf9eb1..56f4899 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
@@ -25,8 +25,6 @@
 package org.eclipse.jetty.server;
 
 import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.startsWith;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
@@ -49,6 +47,7 @@
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.eclipse.jetty.util.log.AbstractLogger;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.log.StdErrLog;
@@ -56,12 +55,8 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
-/**
- *
- */
 public class HttpConnectionTest
 {
     private Server server;
@@ -202,7 +197,7 @@
     public void testBadPathDotDotPath() throws Exception
     {
         String response=connector.getResponses("GET /ooops/../../path HTTP/1.0\nHost: localhost:80\n\n");
-        checkContains(response,0,"HTTP/1.1 400 Bad Request");
+        checkContains(response,0,"HTTP/1.1 400 Bad URI");
     }
     
     @Test
@@ -217,28 +212,28 @@
     public void testBadPathEncodedDotDotPath() throws Exception
     {
         String response=connector.getResponses("GET /ooops/%2e%2e/%2e%2e/path HTTP/1.0\nHost: localhost:80\n\n");
-        checkContains(response,0,"HTTP/1.1 400 Bad Request");
+        checkContains(response,0,"HTTP/1.1 400 Bad URI");
     }
     
     @Test
     public void testBadDotDotPath() throws Exception
     {
         String response=connector.getResponses("GET ../path HTTP/1.0\nHost: localhost:80\n\n");
-        checkContains(response,0,"HTTP/1.1 400 Bad Request");
+        checkContains(response,0,"HTTP/1.1 400 Bad URI");
     }
     
     @Test
     public void testBadSlashDotDotPath() throws Exception
     {
         String response=connector.getResponses("GET /../path HTTP/1.0\nHost: localhost:80\n\n");
-        checkContains(response,0,"HTTP/1.1 400 Bad Request");
+        checkContains(response,0,"HTTP/1.1 400 Bad URI");
     }
 
     @Test
     public void testEncodedBadDotDotPath() throws Exception
     {
         String response=connector.getResponses("GET %2e%2e/path HTTP/1.0\nHost: localhost:80\n\n");
-        checkContains(response,0,"HTTP/1.1 400 Bad Request");
+        checkContains(response,0,"HTTP/1.1 400 Bad URI");
     }
 
     @Test
@@ -449,7 +444,7 @@
                                            "12345\015\012"+
                                            "0;\015\012\015\012");
             offset = checkContains(response,offset,"HTTP/1.1 200");
-            offset = checkContains(response,offset,"encoding=ISO-8859-1");
+            offset = checkContains(response,offset,"encoding=iso-8859-1");
             offset = checkContains(response,offset,"/R1");
             offset = checkContains(response,offset,"12345");
 
@@ -689,6 +684,7 @@
 
     /**
      * Creates a request header over 1k in size, by creating a single header entry with an huge value.
+     * @throws Exception if test failure
      */
     @Test
     public void testOversizedBuffer() throws Exception
@@ -717,6 +713,7 @@
 
     /**
      * Creates a request header with over 1000 entries.
+     * @throws Exception if test failure
      */
     @Test
     public void testExcessiveHeader() throws Exception
@@ -768,7 +765,7 @@
 
         try
         {
-            ((StdErrLog)Log.getLogger(HttpChannel.class)).info("Excpect IOException: Response header too large...");
+            ((AbstractLogger)Log.getLogger(HttpChannel.class)).info("Excpect IOException: Response header too large...");
             ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
             int offset = 0;
 
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java
new file mode 100644
index 0000000..5e7454c
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java
@@ -0,0 +1,593 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.Queue;
+import java.util.concurrent.TimeoutException;
+
+import javax.servlet.ReadListener;
+
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AdvancedRunner.class)
+public class HttpInputTest
+{
+    Queue<String> _history = new ConcurrentArrayQueue<String>()
+            {
+                @Override
+                public boolean add(String s)
+                {
+                    //System.err.println("history: "+s);
+                    return super.add(s);
+                }
+            };
+    Queue<String> _fillAndParseSimulate = new ConcurrentArrayQueue<>();
+    HttpInput _in;
+    
+    ReadListener _listener = new ReadListener()
+    {
+        @Override
+        public void onError(Throwable t)
+        {
+            _history.add("onError:"+t);
+        }
+        
+        @Override
+        public void onDataAvailable() throws IOException
+        {
+            _history.add("onDataAvailable");
+        }
+        
+        @Override
+        public void onAllDataRead() throws IOException
+        {
+            _history.add("onAllDataRead");
+        }
+    };
+    
+    public class TContent extends HttpInput.Content
+    {
+        private final String _content;
+        public TContent(String content)
+        {
+            super(BufferUtil.toBuffer(content));
+            _content=content;
+        }
+        
+        @Override
+        public void succeeded()
+        {
+            _history.add("Content succeeded "+_content);
+            super.succeeded();
+        }
+        
+        @Override
+        public void failed(Throwable x)
+        {
+            _history.add("Content failed "+_content);
+            super.failed(x);
+        }
+    }
+    
+    @Before
+    public void before()
+    {
+        _in=new HttpInput(new HttpChannelState(new HttpChannel(null,new HttpConfiguration(),null,null)
+        {
+            @Override
+            public void asyncReadFillInterested()
+            {
+                _history.add("asyncReadFillInterested");
+            }
+        })
+        {
+            
+            @Override
+            public void onReadUnready()
+            {
+                _history.add("unready");
+                super.onReadUnready();
+            }
+
+            @Override
+            public boolean onReadPossible()
+            {
+                _history.add("onReadPossible");
+                return super.onReadPossible();
+            }
+            
+            @Override
+            public boolean onReadReady()
+            {
+                _history.add("ready");
+                return super.onReadReady();
+            }
+        })
+        {
+            @Override
+            protected void produceContent() throws IOException
+            {
+                _history.add("produceContent "+_fillAndParseSimulate.size()); 
+                
+                for (String s=_fillAndParseSimulate.poll();s!=null;s=_fillAndParseSimulate.poll())
+                {
+                    if ("_EOF_".equals(s))
+                        _in.eof();
+                    else
+                        _in.addContent(new TContent(s));
+                }
+            }
+
+            @Override
+            protected void blockForContent() throws IOException
+            {
+                _history.add("blockForContent"); 
+                super.blockForContent();
+            }
+        };
+    }
+    
+    @After
+    public void after()
+    {
+        assertThat(_history.poll(),nullValue());
+    }
+    
+    @Test
+    public void testEmpty() throws Exception
+    {
+        assertThat(_in.available(),equalTo(0));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_history.poll(),nullValue());
+    }
+
+    @Test
+    public void testRead() throws Exception
+    {
+        _in.addContent(new TContent("AB"));
+        _in.addContent(new TContent("CD"));
+        _fillAndParseSimulate.offer("EF");
+        _fillAndParseSimulate.offer("GH");
+        assertThat(_in.available(),equalTo(2));
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.isReady(),equalTo(true));
+
+        assertThat(_in.getContentConsumed(),equalTo(0L));
+        assertThat(_in.read(),equalTo((int)'A'));
+        assertThat(_in.getContentConsumed(),equalTo(1L));
+        assertThat(_in.read(),equalTo((int)'B'));
+        assertThat(_in.getContentConsumed(),equalTo(2L));
+        
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.read(),equalTo((int)'C'));
+        assertThat(_in.read(),equalTo((int)'D'));
+        
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.read(),equalTo((int)'E'));
+        assertThat(_in.read(),equalTo((int)'F'));
+
+        assertThat(_history.poll(),equalTo("produceContent 2"));
+        assertThat(_history.poll(),equalTo("Content succeeded EF"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.read(),equalTo((int)'G'));
+        assertThat(_in.read(),equalTo((int)'H'));
+        
+        assertThat(_history.poll(),equalTo("Content succeeded GH"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.getContentConsumed(),equalTo(8L));
+        
+        assertThat(_history.poll(),nullValue());
+    }
+
+    @Test
+    public void testBlockingRead() throws Exception
+    {
+        new Thread()
+        {
+            public void run() 
+            {
+                try
+                {
+                    Thread.sleep(500);
+                    _in.addContent(new TContent("AB"));
+                }
+                catch(Throwable th)
+                {
+                    th.printStackTrace();
+                }
+            }
+        }.start();
+        
+        assertThat(_in.read(),equalTo((int)'A'));
+        
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("blockForContent"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.read(),equalTo((int)'B'));
+        
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),nullValue());
+    }
+
+    @Test
+    public void testReadEOF() throws Exception
+    {
+        _in.addContent(new TContent("AB"));
+        _in.addContent(new TContent("CD"));
+        _in.eof();
+
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.available(),equalTo(2));
+        assertThat(_in.isFinished(),equalTo(false));
+
+        assertThat(_in.read(),equalTo((int)'A'));
+        assertThat(_in.read(),equalTo((int)'B'));
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.read(),equalTo((int)'C'));
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.read(),equalTo((int)'D'));
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),nullValue());
+        assertThat(_in.isFinished(),equalTo(false));
+        
+        assertThat(_in.read(),equalTo(-1));
+        assertThat(_in.isFinished(),equalTo(true));
+        
+        assertThat(_history.poll(),nullValue());
+    }
+
+    @Test
+    public void testReadEarlyEOF() throws Exception
+    {
+        _in.addContent(new TContent("AB"));
+        _in.addContent(new TContent("CD"));
+        _in.earlyEOF();
+
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.available(),equalTo(2));
+        assertThat(_in.isFinished(),equalTo(false));
+
+        assertThat(_in.read(),equalTo((int)'A'));
+        assertThat(_in.read(),equalTo((int)'B'));
+        
+        assertThat(_in.read(),equalTo((int)'C'));
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.read(),equalTo((int)'D'));
+        
+        try
+        {
+            _in.read();
+            fail();
+        }
+        catch(EOFException eof)
+        {
+            assertThat(_in.isFinished(),equalTo(true));
+        }
+
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),nullValue());
+    }
+    
+    @Test
+    public void testBlockingEOF() throws Exception
+    {
+        new Thread()
+        {
+            public void run() 
+            {
+                try
+                {
+                    Thread.sleep(500);
+                    _in.eof();
+                }
+                catch(Throwable th)
+                {
+                    th.printStackTrace();
+                }
+            }
+        }.start();
+
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.read(),equalTo(-1));
+        assertThat(_in.isFinished(),equalTo(true));
+        
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("blockForContent"));
+        assertThat(_history.poll(),nullValue());   
+    }
+    
+    @Test
+    public void testAsyncEmpty() throws Exception
+    {
+        _in.setReadListener(_listener);
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+    }
+    
+
+    @Test
+    public void testAsyncRead() throws Exception
+    {
+        _in.setReadListener(_listener);
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.addContent(new TContent("AB"));
+        _fillAndParseSimulate.add("CD");
+        
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.read(),equalTo((int)'A'));
+        
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.read(),equalTo((int)'B'));
+
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_history.poll(),equalTo("produceContent 1"));
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.read(),equalTo((int)'C'));
+        
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.read(),equalTo((int)'D'));
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),nullValue());
+        
+
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+    }
+    
+    @Test
+    public void testAsyncEOF() throws Exception
+    {
+        _in.setReadListener(_listener);
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        _in.eof();
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.read(),equalTo(-1));
+        assertThat(_in.isFinished(),equalTo(true));
+        assertThat(_history.poll(),equalTo("ready"));
+        assertThat(_history.poll(),nullValue());
+    }
+    
+    @Test
+    public void testAsyncReadEOF() throws Exception
+    {
+        _in.setReadListener(_listener);
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.addContent(new TContent("AB"));
+        _fillAndParseSimulate.add("_EOF_");
+        
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.read(),equalTo((int)'A'));
+        
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_in.read(),equalTo((int)'B'));
+
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_history.poll(),equalTo("produceContent 1"));
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isFinished(),equalTo(false));
+        assertThat(_in.read(),equalTo(-1));        
+        assertThat(_in.isFinished(),equalTo(true));
+        assertThat(_history.poll(),equalTo("ready"));
+        assertThat(_history.poll(),nullValue());
+        
+        assertThat(_in.isReady(),equalTo(true));
+        assertThat(_history.poll(),nullValue());
+
+    }
+
+    
+    @Test
+    public void testAsyncError() throws Exception
+    {
+        _in.setReadListener(_listener);
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        _in.run();
+        assertThat(_history.poll(),equalTo("onDataAvailable"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(false));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),equalTo("unready"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.failed(new TimeoutException());
+        assertThat(_history.poll(),equalTo("onReadPossible"));
+        assertThat(_history.poll(),nullValue());
+        
+        _in.run();
+        assertThat(_in.isFinished(),equalTo(true));
+        assertThat(_history.poll(),equalTo("onError:java.util.concurrent.TimeoutException"));
+        assertThat(_history.poll(),nullValue());
+
+        assertThat(_in.isReady(),equalTo(true));
+        try
+        {
+            _in.read();
+            fail();
+        }
+        catch(IOException e)
+        {
+            assertThat(e.getCause(),Matchers.instanceOf(TimeoutException.class));
+            assertThat(_in.isFinished(),equalTo(true));   
+        }
+
+        assertThat(_history.poll(),nullValue());
+    }
+    
+
+    @Test
+    public void testRecycle() throws Exception
+    {
+        testAsyncRead();
+        _in.recycle();
+        testAsyncRead();
+        _in.recycle();
+        testReadEOF();
+    }
+    
+    @Test
+    public void testConsumeAll() throws Exception
+    {
+        _in.addContent(new TContent("AB"));
+        _in.addContent(new TContent("CD"));
+        _fillAndParseSimulate.offer("EF");
+        _fillAndParseSimulate.offer("GH");
+        assertThat(_in.read(),equalTo((int)'A'));
+        
+        assertFalse(_in.consumeAll());
+        assertThat(_in.getContentConsumed(),equalTo(8L));
+
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),equalTo("produceContent 2"));
+        assertThat(_history.poll(),equalTo("Content succeeded EF"));
+        assertThat(_history.poll(),equalTo("Content succeeded GH"));
+        assertThat(_history.poll(),equalTo("produceContent 0"));
+        assertThat(_history.poll(),nullValue());
+    }
+    
+    @Test
+    public void testConsumeAllEOF() throws Exception
+    {
+        _in.addContent(new TContent("AB"));
+        _in.addContent(new TContent("CD"));
+        _fillAndParseSimulate.offer("EF");
+        _fillAndParseSimulate.offer("GH");
+        _fillAndParseSimulate.offer("_EOF_");
+        assertThat(_in.read(),equalTo((int)'A'));
+        
+        assertTrue(_in.consumeAll());
+        assertThat(_in.getContentConsumed(),equalTo(8L));
+
+        assertThat(_history.poll(),equalTo("Content succeeded AB"));
+        assertThat(_history.poll(),equalTo("Content succeeded CD"));
+        assertThat(_history.poll(),equalTo("produceContent 3"));
+        assertThat(_history.poll(),equalTo("Content succeeded EF"));
+        assertThat(_history.poll(),equalTo("Content succeeded GH"));
+        assertThat(_history.poll(),nullValue());
+    }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java
index 250ac7c..57cf8a4 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToAsyncCommitBadBehaviourTest.java
@@ -30,6 +30,7 @@
 import java.util.concurrent.TimeoutException;
 
 import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -86,6 +87,13 @@
         public void handle(String target, Request baseRequest, final HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
         {
             final CyclicBarrier resumeBarrier = new CyclicBarrier(1);
+            
+            if (baseRequest.getDispatcherType()==DispatcherType.ERROR)
+            {
+                response.sendError(500);
+                return;
+            }
+            
             if (request.getAttribute(CONTEXT_ATTRIBUTE) == null)
             {
                 final AsyncContext asyncContext = baseRequest.startAsync();
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
index 4c20965..0ecebb6 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
@@ -18,8 +18,19 @@
 
 package org.eclipse.jetty.server;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -31,6 +42,7 @@
 import java.util.Arrays;
 import java.util.concurrent.Exchanger;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.ServletOutputStream;
@@ -40,27 +52,21 @@
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.EofException;
 import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
 import org.eclipse.jetty.toolchain.test.annotation.Slow;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.AbstractLogger;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.StdErrLog;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
-
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import org.junit.runner.RunWith;
 
 /**
  *
  */
+@RunWith(AdvancedRunner.class)
 public abstract class HttpServerTestBase extends HttpServerTestFixture
 {
     private static final String REQUEST1_HEADER = "POST / HTTP/1.0\n" + "Host: localhost\n" + "Content-Type: text/xml; charset=utf-8\n" + "Connection: close\n" + "Content-Length: ";
@@ -105,7 +111,7 @@
                     + "</nimbus>\n";
     protected static final String RESPONSE2 =
             "HTTP/1.1 200 OK\n" +
-                    "Content-Type: text/xml; charset=ISO-8859-1\n" +
+                    "Content-Type: text/xml;charset=iso-8859-1\n" +
                     "Content-Length: " + RESPONSE2_CONTENT.getBytes().length + "\n" +
                     "Server: Jetty(" + Server.getVersion() + ")\n" +
                     "\n" +
@@ -183,7 +189,7 @@
         {
             client.setSoTimeout(10000);
             ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
-            ((StdErrLog) Log.getLogger(HttpConnection.class)).info("expect request is too large, then ISE extra data ...");
+            ((AbstractLogger) Log.getLogger(HttpConnection.class)).info("expect request is too large, then ISE extra data ...");
             OutputStream os = client.getOutputStream();
 
             byte[] buffer = new byte[64 * 1024];
@@ -214,7 +220,7 @@
         try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
         {
             ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
-            ((StdErrLog)Log.getLogger(HttpConnection.class)).info("expect URI is too large, then ISE extra data ...");
+            ((AbstractLogger)Log.getLogger(HttpConnection.class)).info("expect URI is too large, then ISE extra data ...");
             OutputStream os = client.getOutputStream();
 
             byte[] buffer = new byte[64 * 1024];
@@ -334,7 +340,7 @@
         try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
         {
             ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true);
-            ((StdErrLog)Log.getLogger(HttpConnection.class)).info("expect header is too large, then ISE extra data ...");
+            ((AbstractLogger)Log.getLogger(HttpConnection.class)).info("expect header is too large, then ISE extra data ...");
             OutputStream os = client.getOutputStream();
 
             byte[] buffer = new byte[64 * 1024];
@@ -1025,8 +1031,8 @@
             }
 
             String in = new String(b, 0, i, StandardCharsets.UTF_8);
-            assertTrue(in.contains("123456789"));
-            assertTrue(in.contains("abcdefghZ"));
+            assertThat(in,containsString("123456789"));
+            assertThat(in,containsString("abcdefghZ"));
             assertFalse(in.contains("Wibble"));
 
             in = new String(b, i, b.length - i, StandardCharsets.UTF_16);
@@ -1125,9 +1131,9 @@
             os.flush();
 
             String in = IO.toString(is);
-            assertTrue(in.contains("123456789"));
-            assertTrue(in.contains("abcdefghi"));
-            assertTrue(in.contains("Wibble"));
+            assertThat(in,containsString("123456789"));
+            assertThat(in,containsString("abcdefghi"));
+            assertThat(in,containsString("Wibble"));
         }
     }
 
@@ -1176,7 +1182,7 @@
         try
         {
             ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
-            ((StdErrLog)Log.getLogger(HttpChannel.class)).info("Expecting exception after commit then could not send 500....");
+            ((AbstractLogger)Log.getLogger(HttpChannel.class)).info("Expecting exception after commit then could not send 500....");
             OutputStream os = client.getOutputStream();
             InputStream is = client.getInputStream();
 
@@ -1193,7 +1199,7 @@
 
             assertEquals(-1, is.read()); // Closed by error!
 
-            assertTrue(in.contains("HTTP/1.1 200 OK"));
+            assertThat(in,containsString("HTTP/1.1 200 OK"));
             assertTrue(in.indexOf("Transfer-Encoding: chunked") > 0);
             assertTrue(in.indexOf("Now is the time for all good men to come to the aid of the party") > 0);
             assertThat(in, Matchers.not(Matchers.containsString("\r\n0\r\n")));
@@ -1423,6 +1429,7 @@
         {
             int point = points[j];
 
+            // System.err.println("write: "+new String(bytes, last, point - last));
             os.write(bytes, last, point - last);
             last = point;
             os.flush();
@@ -1433,6 +1440,7 @@
         }
 
         // Write the last fragment
+        // System.err.println("Write: "+new String(bytes, last, bytes.length - last));
         os.write(bytes, last, bytes.length - last);
         os.flush();
         Thread.sleep(PAUSE);
@@ -1443,9 +1451,7 @@
     {
         configureServer(new NoopHandler());
         final int REQS = 2;
-        char[] fill = new char[65 * 1024];
-        Arrays.fill(fill, '.');
-        String content = "This is a loooooooooooooooooooooooooooooooooo" +
+        final String content = "This is a coooooooooooooooooooooooooooooooooo" +
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
@@ -1454,9 +1460,8 @@
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
                 "ooooooooooooooooooooooooooooooooooooooooooooo" +
-                "oooooooooooonnnnnnnnnnnnnnnnggggggggg content" +
-                new String(fill);
-        final byte[] bytes = content.getBytes();
+                "oooooooooooonnnnnnnnnnnnnnnntent";
+        final int cl = content.getBytes().length;
 
         Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
         final OutputStream out = client.getOutputStream();
@@ -1468,12 +1473,15 @@
             {
                 try
                 {
+                    byte[] bytes=(
+                            "GET / HTTP/1.1\r\n"+
+                                    "Host: localhost\r\n"
+                                    +"Content-Length: " + cl + "\r\n" +
+                                    "\r\n"+
+                                    content).getBytes(StandardCharsets.ISO_8859_1);
+                                    
                     for (int i = 0; i < REQS; i++)
-                    {
-                        out.write("GET / HTTP/1.1\r\nHost: localhost\r\n".getBytes(StandardCharsets.ISO_8859_1));
-                        out.write(("Content-Length: " + bytes.length + "\r\n" + "\r\n").getBytes(StandardCharsets.ISO_8859_1));
                         out.write(bytes, 0, bytes.length);
-                    }
                     out.write("GET / HTTP/1.1\r\nHost: last\r\nConnection: close\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1));
                     out.flush();
                 }
@@ -1485,7 +1493,7 @@
         }.start();
 
         String resps = readResponse(client);
-
+                
         int offset = 0;
         for (int i = 0; i < (REQS + 1); i++)
         {
@@ -1495,6 +1503,71 @@
         }
     }
 
+    @Test
+    public void testWriteBodyAfterNoBodyResponse() throws Exception
+    {
+        configureServer(new WriteBodyAfterNoBodyResponseHandler());
+        Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort());
+        final OutputStream out=client.getOutputStream();
+
+        out.write("GET / HTTP/1.1\r\nHost: test\r\n\r\n".getBytes());
+        out.write("GET / HTTP/1.1\r\nHost: test\r\nConnection: close\r\n\r\n".getBytes());
+        out.flush();
+        
+        
+        BufferedReader in =new BufferedReader(new InputStreamReader(client.getInputStream()));
+
+        String line=in.readLine();
+        assertThat(line, containsString(" 304 "));
+        while (true)
+        {
+                line=in.readLine();
+                if (line==null)
+                        throw new EOFException();
+                if (line.length()==0)
+                        break;
+                
+            assertThat(line, not(containsString("Content-Length")));
+            assertThat(line, not(containsString("Content-Type")));
+            assertThat(line, not(containsString("Transfer-Encoding")));
+        }
+
+        line=in.readLine();
+        assertThat(line, containsString(" 304 "));
+        while (true)
+        {
+                line=in.readLine();
+                if (line==null)
+                        throw new EOFException();
+                if (line.length()==0)
+                        break;
+                
+            assertThat(line, not(containsString("Content-Length")));
+            assertThat(line, not(containsString("Content-Type")));
+            assertThat(line, not(containsString("Transfer-Encoding")));
+        }
+
+        do 
+        {
+                line=in.readLine();
+        }
+        while (line!=null);
+        
+    }
+
+    private class WriteBodyAfterNoBodyResponseHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            response.setStatus(304);
+            response.getOutputStream().print("yuck");
+            response.flushBuffer();
+        }
+    }
+    
+    
     public class NoopHandler extends AbstractHandler
     {
         @Override
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
index b201816..333ebad 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestFixture.java
@@ -37,6 +37,7 @@
 import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.toolchain.test.PropertyFlag;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.junit.After;
 import org.junit.Before;
 
@@ -45,8 +46,10 @@
     protected static final long PAUSE=10L;
     protected static final int LOOPS= PropertyFlag.isEnabled("test.stress")?250:50;
 
+    protected QueuedThreadPool _threadPool;
     protected Server _server;
     protected URI _serverURI;
+    protected HttpConfiguration _httpConfiguration;
     protected ServerConnector _connector;
     protected String _scheme="http";
 
@@ -62,15 +65,23 @@
     @Before
     public void before()
     {
-        _server = new Server();
+        _threadPool = new QueuedThreadPool();
+        _server = new Server(_threadPool);
     }
 
     protected void startServer(ServerConnector connector) throws Exception
     {
+        startServer(connector,new HandlerWrapper());
+    }
+    
+    protected void startServer(ServerConnector connector, Handler handler) throws Exception
+    {
         _connector = connector;
-        _connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setSendDateHeader(false);
+        _httpConfiguration=_connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration();
+        _httpConfiguration.setBlockingTimeout(-1);
+        _httpConfiguration.setSendDateHeader(false);
         _server.addConnector(_connector);
-        _server.setHandler(new HandlerWrapper());
+        _server.setHandler(handler);
         _server.start();
         _serverURI = _server.getURI();
     }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java
deleted file mode 100644
index ee5a2a9..0000000
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpURITest.java
+++ /dev/null
@@ -1,402 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import org.eclipse.jetty.http.HttpURI;
-import org.eclipse.jetty.util.MultiMap;
-import org.eclipse.jetty.util.TypeUtil;
-import org.eclipse.jetty.util.Utf8Appendable;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class HttpURITest
-{
-    private final String[][] partial_tests=
-    {
-       /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null},
-       /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"},
-       /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null},
-       /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"},
-       /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null},
-       /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"},
-       /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null},
-       /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"},
-       /* 8*/ {"//host/path/info",null,"//host","host",null,"/path/info",null,null,null},
-       /* 9*/ {"//user@host/path/info",null,"//user@host","host",null,"/path/info",null,null,null},
-       /*10*/ {"//user@host:8080/path/info",null,"//user@host:8080","host","8080","/path/info",null,null,null},
-       /*11*/ {"//host:8080/path/info",null,"//host:8080","host","8080","/path/info",null,null,null},
-       /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null},
-       /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"},
-       /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null},
-       /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"},
-       /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null},
-       /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"},
-       /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null},
-       /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"},
-       /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"},
-       /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"},
-       /*22*/ {"http:///;?#","http","//",null,null,"/","","",""},
-       /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null},
-       /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null},
-       /*25*/ {"//host:8080//",null,"//host:8080","host","8080","//",null,null,null},
-       /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null},
-       /*27*/ {"//",null,"//",null,null,null,null,null,null},
-       /*28*/ {"/;param",null, null, null,null,"/", "param",null,null},
-       /*29*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null},
-       /*30*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null},
-       /*31*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"},
-       /*32*/ {"http://localhost:8080", "http", "//localhost:8080", "localhost", "8080", null, null, null, null},
-       /*33*/ {"./?foo:bar=:1:1::::",null,null,null,null,"./",null,"foo:bar=:1:1::::",null}
-    };
-
-    @Test
-    public void testPartialURIs() throws Exception
-    {
-        HttpURI uri = new HttpURI(true);
-
-        for (int t=0;t<partial_tests.length;t++)
-        {
-            uri.parse(partial_tests[t][0].getBytes(),0,partial_tests[t][0].length());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][1],uri.getScheme());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][2],uri.getAuthority());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][3],uri.getHost());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][4]==null?-1:Integer.parseInt(partial_tests[t][4]),uri.getPort());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][5],uri.getPath());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][6],uri.getParam());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][7],uri.getQuery());
-            assertEquals(t+" "+partial_tests[t][0],partial_tests[t][8],uri.getFragment());
-            assertEquals(partial_tests[t][0], uri.toString());
-        }
-
-    }
-
-    private final String[][] path_tests=
-    {
-       /* 0*/ {"/path/info",null,null,null,null,"/path/info",null,null,null},
-       /* 1*/ {"/path/info#fragment",null,null,null,null,"/path/info",null,null,"fragment"},
-       /* 2*/ {"/path/info?query",null,null,null,null,"/path/info",null,"query",null},
-       /* 3*/ {"/path/info?query#fragment",null,null,null,null,"/path/info",null,"query","fragment"},
-       /* 4*/ {"/path/info;param",null,null,null,null,"/path/info","param",null,null},
-       /* 5*/ {"/path/info;param#fragment",null,null,null,null,"/path/info","param",null,"fragment"},
-       /* 6*/ {"/path/info;param?query",null,null,null,null,"/path/info","param","query",null},
-       /* 7*/ {"/path/info;param?query#fragment",null,null,null,null,"/path/info","param","query","fragment"},
-       /* 8*/ {"//host/path/info",null,null,null,null,"//host/path/info",null,null,null},
-       /* 9*/ {"//user@host/path/info",null,null,null,null,"//user@host/path/info",null,null,null},
-       /*10*/ {"//user@host:8080/path/info",null,null,null,null,"//user@host:8080/path/info",null,null,null},
-       /*11*/ {"//host:8080/path/info",null,null,null,null,"//host:8080/path/info",null,null,null},
-       /*12*/ {"http:/path/info","http",null,null,null,"/path/info",null,null,null},
-       /*13*/ {"http:/path/info#fragment","http",null,null,null,"/path/info",null,null,"fragment"},
-       /*14*/ {"http:/path/info?query","http",null,null,null,"/path/info",null,"query",null},
-       /*15*/ {"http:/path/info?query#fragment","http",null,null,null,"/path/info",null,"query","fragment"},
-       /*16*/ {"http:/path/info;param","http",null,null,null,"/path/info","param",null,null},
-       /*17*/ {"http:/path/info;param#fragment","http",null,null,null,"/path/info","param",null,"fragment"},
-       /*18*/ {"http:/path/info;param?query","http",null,null,null,"/path/info","param","query",null},
-       /*19*/ {"http:/path/info;param?query#fragment","http",null,null,null,"/path/info","param","query","fragment"},
-       /*20*/ {"http://user@host:8080/path/info;param?query#fragment","http","//user@host:8080","host","8080","/path/info","param","query","fragment"},
-       /*21*/ {"xxxxx://user@host:8080/path/info;param?query#fragment","xxxxx","//user@host:8080","host","8080","/path/info","param","query","fragment"},
-       /*22*/ {"http:///;?#","http","//",null,null,"/","","",""},
-       /*23*/ {"/path/info?a=?query",null,null,null,null,"/path/info",null,"a=?query",null},
-       /*24*/ {"/path/info?a=;query",null,null,null,null,"/path/info",null,"a=;query",null},
-       /*25*/ {"//host:8080//",null,null,null,null,"//host:8080//",null,null,null},
-       /*26*/ {"file:///path/info","file","//",null,null,"/path/info",null,null,null},
-       /*27*/ {"//",null,null,null,null,"//",null,null,null},
-       /*28*/ {"http://localhost/","http","//localhost","localhost",null,"/",null,null,null},
-       /*29*/ {"http://localhost:8080/", "http", "//localhost:8080", "localhost","8080","/", null, null,null},
-       /*30*/ {"http://localhost/?x=y", "http", "//localhost", "localhost",null,"/", null,"x=y",null},
-       /*31*/ {"/;param",null, null, null,null,"/", "param",null,null},
-       /*32*/ {"/?x=y",null, null, null,null,"/", null,"x=y",null},
-       /*33*/ {"/?abc=test",null, null, null,null,"/", null,"abc=test",null},
-       /*34*/ {"/#fragment",null, null, null,null,"/", null,null,"fragment"},
-       /*35*/ {"http://192.0.0.1:8080/","http","//192.0.0.1:8080","192.0.0.1","8080","/",null,null,null},
-       /*36*/ {"http://[2001:db8::1]:8080/","http","//[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
-       /*37*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
-       /*38*/ {"http://[2001:db8::1]/","http","//[2001:db8::1]","[2001:db8::1]",null,"/",null,null,null},
-       /*39*/ {"//[2001:db8::1]:8080/",null,null,null,null,"//[2001:db8::1]:8080/",null,null,null},
-       /*40*/ {"http://user@[2001:db8::1]:8080/","http","//user@[2001:db8::1]:8080","[2001:db8::1]","8080","/",null,null,null},
-       /*41*/ {"*",null,null,null,null,"*",null, null,null}
-    };
-
-    @Test
-    public void testPathURIs() throws Exception
-    {
-        HttpURI uri = new HttpURI();
-
-        for (int t=0;t<path_tests.length;t++)
-        {
-            uri.parse(path_tests[t][0].getBytes(),0,path_tests[t][0].length());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][1],uri.getScheme());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][2],uri.getAuthority());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][3],uri.getHost());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][4]==null?-1:Integer.parseInt(path_tests[t][4]),uri.getPort());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][5],uri.getPath());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][6],uri.getParam());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][7],uri.getQuery());
-            assertEquals(t+" "+path_tests[t][0],path_tests[t][8],uri.getFragment());
-            assertEquals(path_tests[t][0], uri.toString());
-        }
-
-    }
-
-    @Test
-    public void testInvalidAddress() throws Exception
-    {
-        assertInvalidURI("http://[ffff::1:8080/", "Invalid URL; no closing ']' -- should throw exception");
-        assertInvalidURI("**", "only '*', not '**'");
-        assertInvalidURI("*/", "only '*', not '*/'");
-    }
-
-    private void assertInvalidURI(String invalidURI, String message)
-    {
-        HttpURI uri = new HttpURI();
-        try
-        {
-            uri.parse(invalidURI);
-            fail(message);
-        }
-        catch (IllegalArgumentException e)
-        {
-            assertTrue(true);
-        }
-    }
-
-    private final String[][] encoding_tests=
-    {
-       /* 0*/ {"/path/info","/path/info", "UTF-8"},
-       /* 1*/ {"/path/%69nfo","/path/info", "UTF-8"},
-       /* 2*/ {"http://host/path/%69nfo","/path/info", "UTF-8"},
-       /* 3*/ {"http://host/path/%69nf%c2%a4","/path/inf\u00a4", "UTF-8"},
-       /* 4*/ {"http://host/path/%E5", "/path/\u00e5", "ISO-8859-1"},
-       /* 5*/ {"/foo/%u30ED/bar%3Fabc%3D123%26xyz%3D456","/foo/\u30ed/bar?abc=123&xyz=456","UTF-8"}
-    };
-
-    @Test
-    public void testEncoded()
-    {
-        HttpURI uri = new HttpURI();
-
-        for (int t=0;t<encoding_tests.length;t++)
-        {
-            uri.parse(encoding_tests[t][0]);
-            assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath(encoding_tests[t][2]));
-            
-            if ("UTF-8".equalsIgnoreCase(encoding_tests[t][2]))
-                assertEquals(""+t,encoding_tests[t][1],uri.getDecodedPath());
-        }
-    }
-    
-    @Test
-    public void testNoPercentEncodingOfQueryUsingNonUTF8() throws Exception
-    {
-        byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
-        byte[] cp1251_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee3dd2e5ecefe5f0e0f2f3f0e0");
-        String expectedCP1251String = new String(cp1251_bytes, "cp1251");
-        String expectedCP1251Key = new String(cp1251_bytes, 0, 7, "cp1251");
-        String expectedCP1251Value = new String(cp1251_bytes, 8, cp1251_bytes.length-8, "cp1251");
-       
-        //paste both byte arrays together to form the uri
-        byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
-        int i=0;
-        for (;i<utf8_bytes.length;i++) {
-            allbytes[i] = utf8_bytes[i];
-        }
-        for (int j=0; j< cp1251_bytes.length;j++)
-            allbytes[i+j] = cp1251_bytes[j];
-        
-        //Test using a HttpUri that expects a particular charset encoding. See URIUtil.__CHARSET
-        HttpURI uri = new HttpURI(Charset.forName("cp1251"));
-        uri.parse(allbytes, 0, allbytes.length);
-        assertEquals(expectedCP1251String, uri.getQuery("cp1251"));
-        
-        //Test params decoded correctly
-        MultiMap params = new MultiMap();
-        uri.decodeQueryTo(params);
-        String val = params.getString(expectedCP1251Key);
-        assertNotNull(val);
-        assertEquals(expectedCP1251Value, val);
-        
-        //Test using HttpURI where you pass in the charset encoding.
-        HttpURI httpuri = new HttpURI();
-        httpuri.parse(allbytes,0,allbytes.length);
-        assertNotNull(httpuri.getQuery("UTF-8")); //still get back a query string, just incorrectly encoded
-        assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
-        
-        //Test params decoded correctly
-        params.clear();
-        httpuri.decodeQueryTo(params, "cp1251");
-        val = params.getString(expectedCP1251Key);
-        assertNotNull(val);
-        assertEquals(expectedCP1251Value, val);
-        
-        //test able to set the query encoding and call getQueryString multiple times
-        Request request = new Request(null,null);
-        request.setUri(httpuri);    
-        request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
-        assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
-        request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
-        assertEquals(expectedCP1251String, request.getQueryString());
-    }
-    
-    @Test
-    public void testPercentEncodingOfQueryStringUsingNonUTF8() throws UnsupportedEncodingException
-    {
-    
-      byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
-      byte[] cp1251_bytes = "%e2%fb%e1%f0%e0%ed%ee=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0".getBytes("cp1251");
-      
-      byte[] key_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee");
-      byte[] val_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0");
-      String expectedCP1251String = new String(cp1251_bytes, "cp1251");
-      String expectedCP1251Key = new String(key_bytes, "cp1251");
-      String expectedCP1251Value = new String(val_bytes, "cp1251");
-      
-      byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
-      
-      //stick both arrays together to form uri
-      int i=0;
-      for (;i<utf8_bytes.length;i++) {
-          allbytes[i] = utf8_bytes[i];
-      }
-      for (int j=0; j< cp1251_bytes.length;j++)
-          allbytes[i+j] = cp1251_bytes[j];
-
-
-      HttpURI httpuri = new HttpURI();
-      httpuri.parse(allbytes,0,allbytes.length);
-      assertNotNull(httpuri.getQuery("UTF-8")); //will be incorrectly encoded, but no errors
-      assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
-
-      //test params decoded correctly
-      MultiMap params = new MultiMap();
-      httpuri.decodeQueryTo(params, "cp1251");
-      String val = params.getString(expectedCP1251Key);
-      assertNotNull(val);
-      assertEquals(expectedCP1251Value, val);
-      
-      //test able to set the query encoding and call getQueryString multiple times
-      Request request = new Request(null,null);
-      request.setUri(httpuri);    
-      request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
-      assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
-      request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
-      assertEquals(expectedCP1251String, request.getQueryString());
-      
-    }
-
-    @Test
-    public void testUnicodeErrors() throws UnsupportedEncodingException
-    {
-        String uri="http://server/path?invalid=data%uXXXXhere%u000";
-        try
-        {
-            URLDecoder.decode(uri,"UTF-8");
-            Assert.assertTrue(false);
-        }
-        catch (IllegalArgumentException e)
-        {
-        }
-
-        HttpURI huri=new HttpURI(uri);
-        MultiMap<String> params = new MultiMap<>();
-        huri.decodeQueryTo(params);
-        assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
-
-        huri=new HttpURI(uri);
-        params = new MultiMap<>();
-        huri.decodeQueryTo(params,StandardCharsets.UTF_8);
-        assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
-
-    }
-
-    @Test
-    public void testExtB() throws Exception
-    {
-        for (String value: new String[]{"a","abcdABCD","\u00C0","\u697C","\uD869\uDED5","\uD840\uDC08"} )
-        {
-            HttpURI uri = new HttpURI("/path?value="+URLEncoder.encode(value,"UTF-8"));
-
-            MultiMap<String> parameters = new MultiMap<>();
-            uri.decodeQueryTo(parameters,StandardCharsets.UTF_8);
-            assertEquals(value,parameters.getString("value"));
-        }
-    }
-
-
-    private final String[][] connect_tests=
-    {
-       /* 0*/ {"  localhost:8080  ","localhost","8080"},
-       /* 1*/ {"  127.0.0.1:8080  ","127.0.0.1","8080"},
-       /* 2*/ {"  [127::0::0::1]:8080  ","[127::0::0::1]","8080"},
-       /* 3*/ {"  error  ",null,null},
-       /* 4*/ {"  http://localhost:8080/  ",null,null},
-    };
-
-    @Test
-    public void testCONNECT() throws Exception
-    {
-        HttpURI uri = new HttpURI();
-        for (int i=0;i<connect_tests.length;i++)
-        {
-            try
-            {
-                byte[] buf = connect_tests[i][0].getBytes(StandardCharsets.UTF_8);
-
-                uri.parseConnect(buf,2,buf.length-4);
-                assertEquals("path"+i,connect_tests[i][0].trim(),uri.getPath());
-                assertEquals("host"+i,connect_tests[i][1],uri.getHost());
-                assertEquals("port"+i,Integer.parseInt(connect_tests[i][2]),uri.getPort());
-            }
-            catch(Exception e)
-            {
-                assertNull("error"+i,connect_tests[i][1]);
-            }
-        }
-    }
-
-    @Test
-    public void testNonURIAscii() throws Exception
-    {
-        String url = "http://www.foo.com/ma\u00F1ana";
-        byte[] asISO = url.getBytes(StandardCharsets.ISO_8859_1);
-        new String(asISO, StandardCharsets.ISO_8859_1);
-
-        //use a non UTF-8 charset as the encoding and url-escape as per
-        //http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars
-        String s = URLEncoder.encode(url, "ISO-8859-1");
-        HttpURI uri = new HttpURI(StandardCharsets.ISO_8859_1);
-
-        //parse it, using the same encoding
-        uri.parse(s);
-
-        //decode the url encoding
-        String d = URLDecoder.decode(uri.getCompletePath(), "ISO-8859-1");
-        assertEquals(url, d);
-    }
-}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
index 5908ca1..9be201f 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java
@@ -24,8 +24,8 @@
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 
+import org.eclipse.jetty.io.ArrayByteBufferPool;
 import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.TypeUtil;
@@ -43,16 +43,17 @@
     {
         _bytes = BufferUtil.allocate(2048);
 
-        final ByteBufferPool bufferPool = new MappedByteBufferPool();
-        HttpChannel<?> channel = new HttpChannel<ByteBuffer>(null,new HttpConfiguration(),null,null,new ByteBufferQueuedHttpInput())
+        final ByteBufferPool pool = new ArrayByteBufferPool();
+        
+        HttpChannel channel = new HttpChannel(null,new HttpConfiguration(),null,null)
         {
             @Override
             public ByteBufferPool getByteBufferPool()
             {
-                return bufferPool;
+                return pool;
             }
         };
-
+        
         _httpOut = new HttpOutput(channel)
         {
             @Override
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
index 2776d32..fa9b44c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
@@ -37,14 +37,17 @@
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  *
  */
+@RunWith(AdvancedRunner.class)
 public class PartialRFC2616Test
 {
     private Server server;
@@ -102,7 +105,7 @@
             assertEquals("3.3.1 RFC 850 ANSI C",d3,d2);
 
             fields.putDateField("Date",d1.getTime());
-            assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date"));
+            assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.get("Date"));
         }
         catch (Exception e)
         {
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java
new file mode 100644
index 0000000..cc99a7f
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ProxyConnectionTest.java
@@ -0,0 +1,171 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class ProxyConnectionTest
+{
+    private Server _server;
+    private LocalConnector _connector;
+
+    @Before
+    public void init() throws Exception
+    {
+        _server = new Server();
+
+        
+        HttpConnectionFactory http = new HttpConnectionFactory();
+        http.getHttpConfiguration().setRequestHeaderSize(1024);
+        http.getHttpConfiguration().setResponseHeaderSize(1024);
+        
+        ProxyConnectionFactory proxy = new ProxyConnectionFactory();
+        
+        _connector = new LocalConnector(_server,null,null,null,1,proxy,http);
+        _connector.setIdleTimeout(1000);
+        _server.addConnector(_connector);
+        _server.setHandler(new DumpHandler());
+        ErrorHandler eh=new ErrorHandler();
+        eh.setServer(_server);
+        _server.addBean(eh);
+        _server.start();
+    }
+
+    @After
+    public void destroy() throws Exception
+    {
+        _server.stop();
+        _server.join();
+    }
+
+    @Test
+    public void testSimple() throws Exception
+    {
+        String response=_connector.getResponses("PROXY TCP 1.2.3.4 5.6.7.8 111 222\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        
+        Assert.assertThat(response,Matchers.containsString("HTTP/1.1 200"));
+        Assert.assertThat(response,Matchers.containsString("pathInfo=/path"));
+        Assert.assertThat(response,Matchers.containsString("local=5.6.7.8:222"));
+        Assert.assertThat(response,Matchers.containsString("remote=1.2.3.4:111"));
+    }
+    
+    @Test
+    public void testIPv6() throws Exception
+    {
+        String response=_connector.getResponses("PROXY UNKNOWN eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        
+        Assert.assertThat(response,Matchers.containsString("HTTP/1.1 200"));
+        Assert.assertThat(response,Matchers.containsString("pathInfo=/path"));
+        Assert.assertThat(response,Matchers.containsString("remote=eeee:eeee:eeee:eeee:eeee:eeee:eeee:eeee:65535"));
+        Assert.assertThat(response,Matchers.containsString("local=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:65535"));
+    }
+    
+    @Test
+    public void testTooLong() throws Exception
+    {
+        String response=_connector.getResponses("PROXY TOOLONG!!! eeee:eeee:eeee:eeee:0000:0000:0000:0000 ffff:ffff:ffff:ffff:0000:0000:0000:0000 65535 65535\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testNotComplete() throws Exception
+    {
+        _connector.setIdleTimeout(100);
+        String response=_connector.getResponses("PROXY TIMEOUT");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testBadChar() throws Exception
+    {
+        String response=_connector.getResponses("PROXY\tTCP 1.2.3.4 5.6.7.8 111 222\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testBadCRLF() throws Exception
+    {
+        String response=_connector.getResponses("PROXY TCP 1.2.3.4 5.6.7.8 111 222\r \n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testBadPort() throws Exception
+    {
+        String response=_connector.getResponses("PROXY TCP 1.2.3.4 5.6.7.8 9999999999999 222\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testMissingField() throws Exception
+    {
+        String response=_connector.getResponses("PROXY TCP 1.2.3.4 5.6.7.8 222\r\n"+
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+    
+    @Test
+    public void testHTTP() throws Exception
+    {
+        String response=_connector.getResponses(
+                "GET /path HTTP/1.1\n"+
+                "Host: server:80\n"+
+                "Connection: close\n"+
+                "\n");
+        Assert.assertThat(response,Matchers.equalTo(""));
+    }
+}
+
+
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java
deleted file mode 100644
index c33f3ef..0000000
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/QueuedHttpInputTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server;
-
-import org.junit.Test;
-
-public class QueuedHttpInputTest
-{
-    @Test
-    public void testNoContentMessageComplete() throws Exception
-    {
-        ByteBufferQueuedHttpInput input = new ByteBufferQueuedHttpInput();
-        input.messageComplete();
-
-        input.getNextContent();
-    }
-}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
index f7e9afc..081f8ee 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
@@ -18,7 +18,6 @@
 
 package org.eclipse.jetty.server;
 
-import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.startsWith;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -58,7 +57,6 @@
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.MultiPartInputStreamParser;
-import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.Utf8Appendable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -66,6 +64,7 @@
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class RequestTest
@@ -130,6 +129,7 @@
 
     }
 
+    @Ignore("Empty headers are not 7230 compliant")
     @Test
     public void testEmptyHeaders() throws Exception
     {
@@ -229,7 +229,7 @@
         contextHandler.setContextPath("/foo");
         contextHandler.setResourceBase(".");
         contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir));
-        contextHandler.addEventListener(new Request.MultiPartCleanerListener()
+        contextHandler.addEventListener(new MultiPartCleanerListener()
         {
 
             @Override
@@ -291,7 +291,7 @@
         contextHandler.setContextPath("/foo");
         contextHandler.setResourceBase(".");
         contextHandler.setHandler(new BadMultiPartRequestHandler(testTmpDir));
-        contextHandler.addEventListener(new Request.MultiPartCleanerListener()
+        contextHandler.addEventListener(new MultiPartCleanerListener()
         {
 
             @Override
@@ -358,9 +358,9 @@
         "Connection: close\n"+
         "\n";
 
-        LOG.info("Expecting NotUtf8Exception byte 62 in state 3...");
+        LOG.info("Expecting NotUtf8Exception in state 36...");
         String responses=_connector.getResponses(request);
-        assertTrue(responses.startsWith("HTTP/1.1 200"));
+        assertThat(responses,startsWith("HTTP/1.1 200"));
     }
 
     @Test
@@ -382,13 +382,13 @@
         "\n";
 
         String responses=_connector.getResponses(request);
-        assertThat(responses,Matchers.startsWith("HTTP/1.1 400"));
+        assertThat(responses, Matchers.startsWith("HTTP/1.1 400"));
     }
 
     @Test
     public void testContentTypeEncoding() throws Exception
     {
-        final ArrayList<String> results = new ArrayList<String>();
+        final ArrayList<String> results = new ArrayList<>();
         _handler._checker = new RequestTester()
         {
             @Override
@@ -428,10 +428,10 @@
         assertEquals(null,results.get(i++));
 
         assertEquals("text/html;charset=utf8",results.get(i++));
-        assertEquals("UTF-8",results.get(i++));
+        assertEquals("utf-8",results.get(i++));
 
         assertEquals("text/html; charset=\"utf8\"",results.get(i++));
-        assertEquals("UTF-8",results.get(i++));
+        assertEquals("utf-8",results.get(i++));
 
         assertTrue(results.get(i++).startsWith("text/html"));
         assertEquals(" x=z; ",results.get(i++));
@@ -440,7 +440,7 @@
     @Test
     public void testHostPort() throws Exception
     {
-        final ArrayList<String> results = new ArrayList<String>();
+        final ArrayList<String> results = new ArrayList<>();
         _handler._checker = new RequestTester()
         {
             @Override
@@ -461,7 +461,7 @@
                 "Connection: close\n"+
                 "\n");
         int i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://myhost/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("myhost",results.get(i++));
@@ -475,7 +475,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://myhost:8888/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("myhost",results.get(i++));
@@ -487,7 +487,7 @@
                 "GET http://myhost:8888/ HTTP/1.0\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://myhost:8888/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("myhost",results.get(i++));
@@ -500,7 +500,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://myhost:8888/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("myhost",results.get(i++));
@@ -515,7 +515,7 @@
                 "\n");
         i=0;
 
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://1.2.3.4/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("1.2.3.4",results.get(i++));
@@ -529,7 +529,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://1.2.3.4:8888/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("1.2.3.4",results.get(i++));
@@ -543,7 +543,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://[::1]/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("[::1]",results.get(i++));
@@ -557,7 +557,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("http://[::1]:8888/",results.get(i++));
         assertEquals("0.0.0.0",results.get(i++));
         assertEquals("[::1]",results.get(i++));
@@ -573,7 +573,7 @@
                 "Connection: close\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("https://[::1]/",results.get(i++));
         assertEquals("remote",results.get(i++));
         assertEquals("[::1]",results.get(i++));
@@ -589,7 +589,7 @@
                 "x-forwarded-proto: https\n"+
                 "\n");
         i=0;
-        assertThat(response,Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("200 OK"));
         assertEquals("https://[::1]:8888/",results.get(i++));
         assertEquals("remote",results.get(i++));
         assertEquals("[::1]",results.get(i++));
@@ -637,13 +637,89 @@
             Log.getRootLogger().debug("test l={}",l);
             String response = _connector.getResponses(request);
             Log.getRootLogger().debug(response);
-            assertThat(response,Matchers.containsString(" 200 OK"));
+            assertThat(response, Matchers.containsString(" 200 OK"));
             assertEquals(l,length.get());
             content+="x";
         }
     }
 
     @Test
+    public void testEncodedForm() throws Exception
+    {
+        _handler._checker = new RequestTester()
+        {
+            @Override
+            public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
+            {
+                String actual = request.getParameter("name2");
+                return "test2".equals(actual);
+            }
+        };
+
+
+        String content="name1=test&name2=test2&name3=&name4=test";
+        String request="POST / HTTP/1.1\r\n"+
+            "Host: whatever\r\n"+
+            "Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
+            "Content-Length: "+content.length()+"\r\n"+
+            "Connection: close\r\n"+
+            "\r\n"+
+            content;
+        String response = _connector.getResponses(request);
+        assertThat(response,Matchers.containsString(" 200 OK"));
+    }
+
+    @Test
+    public void testEncodedFormUnknownMethod() throws Exception
+    {
+        _handler._checker = new RequestTester()
+        {
+            @Override
+            public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
+            {
+                return request.getParameter("name1")==null && request.getParameter("name2")==null && request.getParameter("name3")==null;
+            }
+        };
+
+        String content="name1=test&name2=test2&name3=&name4=test";
+        String request="UNKNOWN / HTTP/1.1\r\n"+
+            "Host: whatever\r\n"+
+            "Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
+            "Content-Length: "+content.length()+"\r\n"+
+            "Connection: close\r\n"+
+            "\r\n"+
+            content;
+        String response = _connector.getResponses(request);
+        assertThat(response,Matchers.containsString(" 200 OK"));
+    }
+
+    @Test
+    public void testEncodedFormExtraMethod() throws Exception
+    {
+        _handler._checker = new RequestTester()
+        {
+            @Override
+            public boolean check(HttpServletRequest request,HttpServletResponse response) throws IOException
+            {
+                String actual = request.getParameter("name2");
+                return "test2".equals(actual);
+            }
+        };
+
+        _connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().addFormEncodedMethod("Extra");
+        String content="name1=test&name2=test2&name3=&name4=test";
+        String request="EXTRA / HTTP/1.1\r\n"+
+            "Host: whatever\r\n"+
+            "Content-Type: "+MimeTypes.Type.FORM_ENCODED.asString()+"\r\n" +
+            "Content-Length: "+content.length()+"\r\n"+
+            "Connection: close\r\n"+
+            "\r\n"+
+            content;
+        String response = _connector.getResponses(request);
+        assertThat(response,Matchers.containsString(" 200 OK"));
+    }
+    
+    @Test
     public void test8859EncodedForm() throws Exception
     {
         _handler._checker = new RequestTester()
@@ -659,7 +735,6 @@
             }
         };
 
-
         String content="name1=test&name2=test%E4&name3=&name4=test";
         String request="POST / HTTP/1.1\r\n"+
             "Host: whatever\r\n"+
@@ -888,9 +963,9 @@
                     "\n",
                     200, TimeUnit.MILLISECONDS
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertFalse(response.indexOf("Connection: close")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.not(Matchers.containsString("Connection: close")));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.1\n"+
@@ -898,9 +973,9 @@
                     "Connection: close\n"+
                     "\n"
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertTrue(response.indexOf("Connection: close")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.containsString("Connection: close"));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.1\n"+
@@ -909,18 +984,18 @@
                     "\n"
                     );
 
-        assertTrue(response.indexOf("200")>0);
-        assertTrue(response.indexOf("Connection: close")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.containsString("Connection: close"));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.0\n"+
                     "Host: whatever\n"+
                     "\n"
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertFalse(response.indexOf("Connection: close")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.not(Matchers.containsString("Connection: close")));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.0\n"+
@@ -928,8 +1003,8 @@
                     "Connection: Other, close\n"+
                     "\n"
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.0\n"+
@@ -938,9 +1013,9 @@
                     "\n",
                     200, TimeUnit.MILLISECONDS
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertTrue(response.indexOf("Connection: keep-alive")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.containsString("Connection: keep-alive"));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         _handler._checker = new RequestTester()
         {
@@ -960,9 +1035,9 @@
                     "\n",
                     200, TimeUnit.MILLISECONDS
                     );
-        assertTrue(response.indexOf("200")>0);
-        assertTrue(response.indexOf("Connection: TE,Other")>0);
-        assertTrue(response.indexOf("Hello World")>0);
+        assertThat(response, Matchers.containsString("200"));
+        assertThat(response, Matchers.containsString("Connection: TE,Other"));
+        assertThat(response, Matchers.containsString("Hello World"));
 
         response=_connector.getResponses(
                     "GET / HTTP/1.1\n"+
@@ -970,15 +1045,15 @@
                     "Connection: close\n"+
                     "\n"
                     );
-        assertThat(response,Matchers.containsString("200 OK"));
-        assertThat(response,Matchers.containsString("Connection: close"));
-        assertThat(response,Matchers.containsString("Hello World"));
+        assertThat(response, Matchers.containsString("200 OK"));
+        assertThat(response, Matchers.containsString("Connection: close"));
+        assertThat(response, Matchers.containsString("Hello World"));
     }
 
     @Test
     public void testCookies() throws Exception
     {
-        final ArrayList<Cookie> cookies = new ArrayList<Cookie>();
+        final ArrayList<Cookie> cookies = new ArrayList<>();
 
         _handler._checker = new RequestTester()
         {
@@ -1048,8 +1123,8 @@
                 "Connection: close\n"+
                 "\n"
         );
-        assertThat(response,startsWith("HTTP/1.1 200 OK"));
-        assertThat(response.substring(15),containsString("HTTP/1.1 200 OK"));
+        assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK"));
+        assertThat(response.substring(15), Matchers.containsString("HTTP/1.1 200 OK"));
         assertEquals(4,cookies.size());
         assertEquals("name", cookies.get(0).getName());
         assertEquals("value", cookies.get(0).getValue());
@@ -1073,8 +1148,8 @@
                 "Connection: close\n"+
                 "\n"
         );
-        assertThat(response,startsWith("HTTP/1.1 200 OK"));
-        assertThat(response.substring(15),containsString("HTTP/1.1 200 OK"));
+        assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK"));
+        assertThat(response.substring(15), Matchers.containsString("HTTP/1.1 200 OK"));
         assertEquals(4,cookies.size());
         assertEquals("name", cookies.get(0).getName());
         assertEquals("value", cookies.get(0).getValue());
@@ -1133,6 +1208,7 @@
 
     }
 
+    @Ignore("No longer relevant")
     @Test
     public void testCookieLeak() throws Exception
     {
@@ -1178,7 +1254,7 @@
         +
         "POST / HTTP/1.1\r\n"+
         "Host: whatever\r\n"+
-        "Cookie:\r\n"+
+        "Cookie: \r\n"+
         "Connection: close\r\n"+
         "\r\n";
 
@@ -1260,7 +1336,7 @@
         {
             long start=System.currentTimeMillis();
             String response = _connector.getResponses(request);
-            assertTrue(response.contains("Form too many keys"));
+            assertThat(response,Matchers.containsString("IllegalStateException"));
             long now=System.currentTimeMillis();
             assertTrue((now-start)<5000);
         }
@@ -1306,7 +1382,7 @@
         {
             long start=System.currentTimeMillis();
             String response = _connector.getResponses(request);
-            assertTrue(response.contains("Form too large:"));
+            assertTrue(response.contains("IllegalStateException"));
             long now=System.currentTimeMillis();
             assertTrue((now-start)<5000);
         }
@@ -1413,7 +1489,7 @@
                 request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
 
                 //We should get an error when we getParams if there was a problem parsing the multipart
-                String field1 = request.getParameter("xxx");
+                request.getParameter("xxx");
                 //A 200 response is actually wrong here
             }
             catch (RuntimeException e)
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java
index 167f5f9..602b709 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -29,6 +30,8 @@
 
 import org.eclipse.jetty.http.HttpContent;
 import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.http.ResourceHttpContent;
+import org.eclipse.jetty.toolchain.test.OS;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceCollection;
@@ -48,9 +51,9 @@
         Resource[] r = rc.getResources();
         MimeTypes mime = new MimeTypes();
 
-        ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
-        ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false);
-        ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
+        ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false,false);
+        ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false,false);
+        ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false,false);
 
         assertEquals("1 - one", getContent(rc1, "1.txt"));
         assertEquals("2 - two", getContent(rc1, "2.txt"));
@@ -78,8 +81,8 @@
         Resource[] r = rc.getResources();
         MimeTypes mime = new MimeTypes();
 
-        ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
-        ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false)
+        ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false,false);
+        ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false,false)
         {
             @Override
             public boolean isCacheable(Resource resource)
@@ -88,7 +91,7 @@
             }
         };
 
-        ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
+        ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false,false);
 
         assertEquals("1 - one", getContent(rc1, "1.txt"));
         assertEquals("2 - two", getContent(rc1, "2.txt"));
@@ -129,56 +132,89 @@
         directory=Resource.newResource(files[0].getParentFile().getAbsolutePath());
 
 
-        cache=new ResourceCache(null,directory,new MimeTypes(),false,false);
+        cache=new ResourceCache(null,directory,new MimeTypes(),false,false,false);
 
         cache.setMaxCacheSize(95);
         cache.setMaxCachedFileSize(85);
         cache.setMaxCachedFiles(4);
 
-        assertTrue(cache.lookup("does not exist")==null);
-        assertTrue(cache.lookup(names[9]) instanceof HttpContent.ResourceAsHttpContent);
+        assertTrue(cache.getContent("does not exist",4096)==null);
+        assertTrue(cache.getContent(names[9],4096) instanceof ResourceHttpContent);
+        assertTrue(cache.getContent(names[9],4096).getIndirectBuffer()!=null);
 
         HttpContent content;
-        content=cache.lookup(names[8]);
+        content=cache.getContent(names[8],4096);
         assertTrue(content!=null);
-        assertEquals(80,content.getContentLength());
+        assertEquals(80,content.getContentLengthValue());
+        assertEquals(0,cache.getCachedSize());
+        
+        if (OS.IS_LINUX)
+        {
+            // Initially not using memory mapped files
+            content.getDirectBuffer();
+            assertEquals(80,cache.getCachedSize());
 
+            // with both types of buffer loaded, this is too large for cache
+            content.getIndirectBuffer();
+            assertEquals(0,cache.getCachedSize());
+            assertEquals(0,cache.getCachedFiles());
+
+            cache=new ResourceCache(null,directory,new MimeTypes(),true,false,false);
+            cache.setMaxCacheSize(95);
+            cache.setMaxCachedFileSize(85);
+            cache.setMaxCachedFiles(4);
+            
+            content=cache.getContent(names[8],4096);
+            content.getDirectBuffer();
+            assertEquals(cache.isUseFileMappedBuffer()?0:80,cache.getCachedSize());
+
+            // with both types of buffer loaded, this is not too large for cache because
+            // mapped buffers don't count, so we can continue
+        }
+        content.getIndirectBuffer();
         assertEquals(80,cache.getCachedSize());
         assertEquals(1,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[1]);
+        content=cache.getContent(names[1],4096);
+        assertEquals(80,cache.getCachedSize());
+        content.getIndirectBuffer();
         assertEquals(90,cache.getCachedSize());
         assertEquals(2,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[2]);
+        content=cache.getContent(names[2],4096);
+        content.getIndirectBuffer();
         assertEquals(30,cache.getCachedSize());
         assertEquals(2,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[3]);
+        content=cache.getContent(names[3],4096);
+        content.getIndirectBuffer();
         assertEquals(60,cache.getCachedSize());
         assertEquals(3,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[4]);
+        content=cache.getContent(names[4],4096);
+        content.getIndirectBuffer();
         assertEquals(90,cache.getCachedSize());
         assertEquals(3,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[5]);
+        content=cache.getContent(names[5],4096);
+        content.getIndirectBuffer();
         assertEquals(90,cache.getCachedSize());
         assertEquals(2,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[6]);
+        content=cache.getContent(names[6],4096);
+        content.getIndirectBuffer();
         assertEquals(60,cache.getCachedSize());
         assertEquals(1,cache.getCachedFiles());
 
@@ -188,37 +224,43 @@
         {
             out.write(' ');
         }
-        content=cache.lookup(names[7]);
+        content=cache.getContent(names[7],4096);
+        content.getIndirectBuffer();
         assertEquals(70,cache.getCachedSize());
         assertEquals(1,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[6]);
+        content=cache.getContent(names[6],4096);
+        content.getIndirectBuffer();
         assertEquals(71,cache.getCachedSize());
         assertEquals(2,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[0]);
+        content=cache.getContent(names[0],4096);
+        content.getIndirectBuffer();
         assertEquals(72,cache.getCachedSize());
         assertEquals(3,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[1]);
+        content=cache.getContent(names[1],4096);
+        content.getIndirectBuffer();
         assertEquals(82,cache.getCachedSize());
         assertEquals(4,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[2]);
+        content=cache.getContent(names[2],4096);
+        content.getIndirectBuffer();
         assertEquals(32,cache.getCachedSize());
         assertEquals(4,cache.getCachedFiles());
 
         Thread.sleep(200);
 
-        content=cache.lookup(names[3]);
+        content=cache.getContent(names[3],4096);
+        content.getIndirectBuffer();
         assertEquals(61,cache.getCachedSize());
         assertEquals(4,cache.getCachedFiles());
 
@@ -242,7 +284,7 @@
         Resource[] resources = rc.getResources();
         MimeTypes mime = new MimeTypes();
 
-        ResourceCache cache = new ResourceCache(null,resources[0],mime,false,false);
+        ResourceCache cache = new ResourceCache(null,resources[0],mime,false,false,false);
 
         assertEquals("4 - four", getContent(cache, "four.txt"));
         assertEquals("4 - four (no extension)", getContent(cache, "four"));
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
index 9793acc..57ff712 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java
@@ -44,11 +44,13 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
 import org.eclipse.jetty.io.AbstractEndPoint;
 import org.eclipse.jetty.io.ByteArrayEndPoint;
+import org.eclipse.jetty.io.RuntimeIOException;
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.session.HashSessionIdManager;
@@ -66,7 +68,7 @@
 public class ResponseTest
 {
     private Server _server;
-    private HttpChannel<ByteBuffer> _channel;
+    private HttpChannel _channel;
 
     @Before
     public void init() throws Exception
@@ -80,33 +82,47 @@
         _server.start();
 
         AbstractEndPoint endp = new ByteArrayEndPoint(_scheduler, 5000);
-        ByteBufferQueuedHttpInput input = new ByteBufferQueuedHttpInput();
-        _channel = new HttpChannel<ByteBuffer>(connector, new HttpConfiguration(), endp, new HttpTransport()
+        _channel = new HttpChannel(connector, new HttpConfiguration(), endp, new HttpTransport()
         {
+            private Throwable _channelError;
+            
             @Override
-            public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
+            public void send(MetaData.Response info, boolean head, ByteBuffer content, boolean lastContent, Callback callback)
             {
-                callback.succeeded();
+                if (_channelError==null)
+                    callback.succeeded();
+                else
+                    callback.failed(_channelError);
+            }
+
+            @Override
+            public boolean isPushSupported()
+            {
+                return false;
             }
             
             @Override
-            public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback)
-            {
-                send(null,responseBodyContent, lastContent, callback);
+            public void push(org.eclipse.jetty.http.MetaData.Request request)
+            {   
             }
-
+            
             @Override
-            public void completed()
+            public void onCompleted()
             {
             }
 
             @Override
-            public void abort()
+            public void abort(Throwable failure)
             {
-                
+                _channelError=failure;
             }
 
-        }, input);
+            @Override
+            public boolean isOptimizedForDirectBuffers()
+            {
+                return false;
+            }
+        });
     }
 
     @After
@@ -129,9 +145,9 @@
         response.setContentType("foo/bar");
         assertEquals("foo/bar", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; charset=ISO-8859-1", response.getContentType());
+        assertEquals("foo/bar;charset=iso-8859-1", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType());
+        assertEquals("foo2/bar2;charset=iso-8859-1", response.getContentType());
         response.setHeader("name", "foo");
 
         Iterator<String> en = response.getHeaders("name").iterator();
@@ -148,16 +164,16 @@
         response.setContentType("text/html");
         assertEquals("text/html", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; charset=ISO-8859-1", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
 
         response.recycle();
         response.setContentType("text/xml;charset=ISO-8859-7");
         response.getWriter();
         assertEquals("text/xml;charset=ISO-8859-7", response.getContentType());
         response.setContentType("text/html;charset=UTF-8");
-        assertEquals("text/html; charset=ISO-8859-7", response.getContentType());
+        assertEquals("text/html;charset=ISO-8859-7", response.getContentType());
 
         response.recycle();
         response.setContentType("text/html;charset=US-ASCII");
@@ -165,9 +181,9 @@
         assertEquals("text/html;charset=US-ASCII", response.getContentType());
 
         response.recycle();
-        response.setContentType("text/html; charset=utf-8");
+        response.setContentType("text/html; charset=UTF-8");
         response.getWriter();
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
 
         response.recycle();
         response.setContentType("text/json");
@@ -178,17 +194,17 @@
         response.setContentType("text/json");
         response.setCharacterEncoding("UTF-8");
         response.getWriter();
-        assertEquals("text/json; charset=UTF-8", response.getContentType());
+        assertEquals("text/json;charset=utf-8", response.getContentType());
 
         response.recycle();
         response.setCharacterEncoding("xyz");
         response.setContentType("foo/bar");
-        assertEquals("foo/bar; charset=xyz", response.getContentType());
+        assertEquals("foo/bar;charset=xyz", response.getContentType());
 
         response.recycle();
         response.setContentType("foo/bar");
         response.setCharacterEncoding("xyz");
-        assertEquals("foo/bar; charset=xyz", response.getContentType());
+        assertEquals("foo/bar;charset=xyz", response.getContentType());
 
         response.recycle();
         response.setCharacterEncoding("xyz");
@@ -198,7 +214,7 @@
         response.recycle();
         response.setContentType("foo/bar;charset=abc");
         response.setCharacterEncoding("xyz");
-        assertEquals("foo/bar; charset=xyz", response.getContentType());
+        assertEquals("foo/bar;charset=xyz", response.getContentType());
 
         response.recycle();
         response.setCharacterEncoding("xyz");
@@ -235,14 +251,14 @@
         response.setLocale(java.util.Locale.ITALIAN);
         assertEquals(null, response.getContentType());
         response.setContentType("text/plain");
-        assertEquals("text/plain; charset=ISO-8859-2", response.getContentType());
+        assertEquals("text/plain;charset=ISO-8859-2", response.getContentType());
 
         response.recycle();
         response.setContentType("text/plain");
         response.setCharacterEncoding("utf-8");
         response.setLocale(java.util.Locale.ITALIAN);
-        assertEquals("text/plain; charset=UTF-8", response.getContentType());
-        assertTrue(response.toString().indexOf("charset=UTF-8") > 0);
+        assertEquals("text/plain;charset=utf-8", response.getContentType());
+        assertTrue(response.toString().indexOf("charset=utf-8") > 0);
     }
 
     @Test
@@ -252,25 +268,25 @@
 
         response.setContentType("foo/bar");
         response.setCharacterEncoding("utf-8");
-        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
+        assertEquals("foo/bar;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
+        assertEquals("foo/bar;charset=utf-8", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("ISO-8859-1");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
 
         response.recycle();
 
         response.setContentType("text/html");
-        response.setCharacterEncoding("utf-8");
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        response.setCharacterEncoding("UTF-8");
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.setContentType("text/xml");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("ISO-8859-1");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
     }
 
     @Test
@@ -279,25 +295,25 @@
         Response response = newResponse();
         response.setCharacterEncoding("utf-8");
         response.setContentType("foo/bar");
-        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
+        assertEquals("foo/bar;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
+        assertEquals("foo/bar;charset=utf-8", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("ISO-8859-1");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
 
         response.recycle();
 
         response.setCharacterEncoding("utf-8");
         response.setContentType("text/html");
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.setContentType("text/xml");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("iso-8859-1");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
     }
 
     @Test
@@ -306,26 +322,26 @@
         Response response = newResponse();
 
         response.setCharacterEncoding("utf16");
-        response.setContentType("foo/bar; charset=utf-8");
-        assertEquals("foo/bar; charset=utf-8", response.getContentType());
+        response.setContentType("foo/bar; charset=UTF-8");
+        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; charset=utf-8", response.getContentType());
+        assertEquals("foo/bar; charset=UTF-8", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("ISO-8859-1");
-        assertEquals("foo2/bar2; charset=UTF-8", response.getContentType());
+        assertEquals("foo2/bar2;charset=utf-8", response.getContentType());
 
         response.recycle();
 
         response.setCharacterEncoding("utf16");
         response.setContentType("text/html; charset=utf-8");
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; charset=UTF-8", response.getContentType());
+        assertEquals("text/html;charset=utf-8", response.getContentType());
         response.setContentType("text/xml");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
         response.setCharacterEncoding("iso-8859-1");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
     }
 
     @Test
@@ -336,19 +352,19 @@
         response.setContentType("foo/bar; other=xyz");
         assertEquals("foo/bar; other=xyz", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; other=xyz; charset=ISO-8859-1", response.getContentType());
+        assertEquals("foo/bar; other=xyz;charset=iso-8859-1", response.getContentType());
         response.setContentType("foo2/bar2");
-        assertEquals("foo2/bar2; charset=ISO-8859-1", response.getContentType());
+        assertEquals("foo2/bar2;charset=iso-8859-1", response.getContentType());
 
         response.recycle();
 
-        response.setCharacterEncoding("utf-8");
+        response.setCharacterEncoding("uTf-8");
         response.setContentType("text/html; other=xyz");
-        assertEquals("text/html; other=xyz; charset=UTF-8", response.getContentType());
+        assertEquals("text/html; other=xyz;charset=utf-8", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; other=xyz; charset=UTF-8", response.getContentType());
+        assertEquals("text/html; other=xyz;charset=utf-8", response.getContentType());
         response.setContentType("text/xml");
-        assertEquals("text/xml; charset=UTF-8", response.getContentType());
+        assertEquals("text/xml;charset=utf-8", response.getContentType());
     }
 
     @Test
@@ -366,17 +382,17 @@
 
         response.setCharacterEncoding("utf16");
         response.setContentType("text/html; other=xyz charset=utf-8");
-        assertEquals("text/html; other=xyz charset=utf-8; charset=UTF-16", response.getContentType());
+        assertEquals("text/html; other=xyz charset=utf-8;charset=utf-16", response.getContentType());
         response.getWriter();
-        assertEquals("text/html; other=xyz charset=utf-8; charset=UTF-16", response.getContentType());
+        assertEquals("text/html; other=xyz charset=utf-8;charset=utf-16", response.getContentType());
 
         response.recycle();
 
         response.setCharacterEncoding("utf16");
         response.setContentType("foo/bar; other=pq charset=utf-8 other=xyz");
-        assertEquals("foo/bar; other=pq charset=utf-8 other=xyz; charset=UTF-16", response.getContentType());
+        assertEquals("foo/bar; other=pq charset=utf-8 other=xyz;charset=utf-16", response.getContentType());
         response.getWriter();
-        assertEquals("foo/bar; other=pq charset=utf-8 other=xyz; charset=UTF-16", response.getContentType());
+        assertEquals("foo/bar; other=pq charset=utf-8 other=xyz;charset=utf-16", response.getContentType());
     }
 
     @Test
@@ -410,13 +426,38 @@
     }
 
     @Test
+    public void testWriteRuntimeIOException() throws Exception
+    {
+        Response response = newResponse();
+
+        PrintWriter writer = response.getWriter();
+        writer.println("test");
+        writer.flush();
+        Assert.assertFalse(writer.checkError());
+        
+        Throwable cause = new IOException("problem at mill");
+        _channel.abort(cause);
+        writer.println("test");
+        Assert.assertTrue(writer.checkError());
+        try
+        {
+            writer.println("test");
+            Assert.fail();
+        }
+        catch(RuntimeIOException e)
+        {
+            Assert.assertEquals(cause,e.getCause());
+        }
+        
+    }
+
+    @Test
     public void testEncodeRedirect()
             throws Exception
     {
         Response response = newResponse();
         Request request = response.getHttpChannel().getRequest();
-        request.setServerName("myhost");
-        request.setServerPort(8888);
+        request.setAuthority("myhost",8888);
         request.setContextPath("/path");
 
         assertEquals("http://myhost:8888/path/info;param?query=0&more=1#target", response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target"));
@@ -492,9 +533,9 @@
                     Response response = newResponse();
                     Request request = response.getHttpChannel().getRequest();
 
-                    request.setServerName(host);
-                    request.setServerPort(port);
-                    request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
+                    request.setScheme("http");
+                    request.setAuthority(host,port);
+                    request.setURIPathQuery("/path/info;param;jsessionid=12345?query=0&more=1#target");
                     request.setContextPath("/path");
                     request.setRequestedSessionId("12345");
                     request.setRequestedSessionIdFromCookie(i>2);
@@ -614,7 +655,7 @@
 
         response.addCookie(cookie);
 
-        String set = response.getHttpFields().getStringField("Set-Cookie");
+        String set = response.getHttpFields().get("Set-Cookie");
 
         assertEquals("name=value;Version=1;Path=/path;Domain=domain;Secure;HttpOnly;Comment=comment", set);
     }
@@ -658,7 +699,7 @@
     @Test
     public void testFlushAfterFullContent() throws Exception
     {
-        Response response = _channel.getResponse();
+        Response response = newResponse();
         byte[] data = new byte[]{(byte)0xCA, (byte)0xFE};
         ServletOutputStream output = response.getOutputStream();
         response.setContentLength(data.length);
@@ -676,23 +717,23 @@
         HttpFields fields = response.getHttpFields();
 
         response.addSetCookie("null",null,null,null,-1,null,false,false,-1);
-        assertEquals("null=",fields.getStringField("Set-Cookie"));
+        assertEquals("null=",fields.get("Set-Cookie"));
 
         fields.clear();
         
         response.addSetCookie("minimal","value",null,null,-1,null,false,false,-1);
-        assertEquals("minimal=value",fields.getStringField("Set-Cookie"));
+        assertEquals("minimal=value",fields.get("Set-Cookie"));
 
         fields.clear();
         //test cookies with same name, domain and path, only 1 allowed
         response.addSetCookie("everything","wrong","domain","path",0,"to be replaced",true,true,0);
         response.addSetCookie("everything","value","domain","path",0,"comment",true,true,0);
-        assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",fields.getStringField("Set-Cookie"));
+        assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",fields.get("Set-Cookie"));
         Enumeration<String> e =fields.getValues("Set-Cookie");
         assertTrue(e.hasMoreElements());
         assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",e.nextElement());
         assertFalse(e.hasMoreElements());
-        assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.getStringField("Expires"));
+        assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Expires"));
         assertFalse(e.hasMoreElements());
         
         //test cookies with same name, different domain
@@ -751,31 +792,31 @@
 
         fields.clear();
         response.addSetCookie("ev erything","va lue","do main","pa th",1,"co mment",true,true,1);
-        String setCookie=fields.getStringField("Set-Cookie");
+        String setCookie=fields.get("Set-Cookie");
         assertThat(setCookie,Matchers.startsWith("\"ev erything\"=\"va lue\";Version=1;Path=\"pa th\";Domain=\"do main\";Expires="));
         assertThat(setCookie,Matchers.endsWith(" GMT;Max-Age=1;Secure;HttpOnly;Comment=\"co mment\""));
 
         fields.clear();
         response.addSetCookie("name","value",null,null,-1,null,false,false,0);
-        setCookie=fields.getStringField("Set-Cookie");
+        setCookie=fields.get("Set-Cookie");
         assertEquals(-1,setCookie.indexOf("Version="));
         fields.clear();
         response.addSetCookie("name","v a l u e",null,null,-1,null,false,false,0);
-        setCookie=fields.getStringField("Set-Cookie");
+        setCookie=fields.get("Set-Cookie");
 
         fields.clear();
         response.addSetCookie("json","{\"services\":[\"cwa\", \"aa\"]}",null,null,-1,null,false,false,-1);
-        assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.getStringField("Set-Cookie"));
+        assertEquals("json=\"{\\\"services\\\":[\\\"cwa\\\", \\\"aa\\\"]}\"",fields.get("Set-Cookie"));
 
         fields.clear();
         response.addSetCookie("name","value","domain",null,-1,null,false,false,-1);
         response.addSetCookie("name","other","domain",null,-1,null,false,false,-1);
-        assertEquals("name=other;Domain=domain",fields.getStringField("Set-Cookie"));
+        assertEquals("name=other;Domain=domain",fields.get("Set-Cookie"));
         response.addSetCookie("name","more","domain",null,-1,null,false,false,-1);
-        assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie"));
+        assertEquals("name=more;Domain=domain",fields.get("Set-Cookie"));
         response.addSetCookie("foo","bar","domain",null,-1,null,false,false,-1);
         response.addSetCookie("foo","bob","domain",null,-1,null,false,false,-1);
-        assertEquals("name=more;Domain=domain",fields.getStringField("Set-Cookie"));
+        assertEquals("name=more;Domain=domain",fields.get("Set-Cookie"));
 
         e=fields.getValues("Set-Cookie");
         assertEquals("name=more;Domain=domain",e.nextElement());
@@ -783,14 +824,15 @@
 
         fields.clear();
         response.addSetCookie("name","value%=",null,null,-1,null,false,false,0);
-        setCookie=fields.getStringField("Set-Cookie");
+        setCookie=fields.get("Set-Cookie");
         assertEquals("name=value%=",setCookie);
 
     }
     
     private Response newResponse()
     {
-        _channel.reset();
+        _channel.recycle();
+        _channel.getRequest().setMetaData(new MetaData.Request("GET",new HttpURI("/path/info"),HttpVersion.HTTP_1_0,new HttpFields()));
         return new Response(_channel, _channel.getResponse().getHttpOutput());
     }
 
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorHttpServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorHttpServerTest.java
index 56c511b..d5e37d9 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorHttpServerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorHttpServerTest.java
@@ -18,11 +18,14 @@
 
 package org.eclipse.jetty.server;
 
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
 import org.junit.Before;
+import org.junit.runner.RunWith;
 
 /**
  * HttpServer Tester.
  */
+@RunWith(AdvancedRunner.class)
 public class ServerConnectorHttpServerTest extends HttpServerTestBase
 {
     @Before
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java
index ac4d7ec..1b3d8c4 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTest.java
@@ -18,19 +18,16 @@
 
 package org.eclipse.jetty.server;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
 import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.Socket;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -41,9 +38,19 @@
 import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.eclipse.jetty.server.handler.DefaultHandler;
 import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.toolchain.test.OS;
 import org.eclipse.jetty.util.IO;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+
 public class ServerConnectorTest
 {
     public static class ReuseInfoHandler extends AbstractHandler
@@ -74,9 +81,9 @@
             {
                 t.printStackTrace(out);
             }
-            
+
             out.printf("socket.getReuseAddress() = %b%n",socket.getReuseAddress());
-            
+
             baseRequest.setHandled(true);
         }
     }
@@ -92,7 +99,7 @@
         return new URI(String.format("http://%s:%d/",host,port));
     }
 
-    private String getResponse(URI uri) throws MalformedURLException, IOException
+    private String getResponse(URI uri) throws IOException
     {
         HttpURLConnection http = (HttpURLConnection)uri.toURL().openConnection();
         assertThat("Valid Response Code",http.getResponseCode(),anyOf(is(200),is(404)));
@@ -125,7 +132,12 @@
             String response = getResponse(uri);
             assertThat("Response",response,containsString("connector.getReuseAddress() = true"));
             assertThat("Response",response,containsString("connector._reuseAddress() = true"));
-            assertThat("Response",response,containsString("socket.getReuseAddress() = true"));
+
+            // Java on Windows is incapable of propagating reuse-address this to the opened socket.
+            if (!OS.IS_WINDOWS)
+            {
+                assertThat("Response",response,containsString("socket.getReuseAddress() = true"));
+            }
         }
         finally
         {
@@ -156,7 +168,12 @@
             String response = getResponse(uri);
             assertThat("Response",response,containsString("connector.getReuseAddress() = true"));
             assertThat("Response",response,containsString("connector._reuseAddress() = true"));
-            assertThat("Response",response,containsString("socket.getReuseAddress() = true"));
+
+            // Java on Windows is incapable of propagating reuse-address this to the opened socket.
+            if (!OS.IS_WINDOWS)
+            {
+                assertThat("Response",response,containsString("socket.getReuseAddress() = true"));
+            }
         }
         finally
         {
@@ -187,11 +204,35 @@
             String response = getResponse(uri);
             assertThat("Response",response,containsString("connector.getReuseAddress() = false"));
             assertThat("Response",response,containsString("connector._reuseAddress() = false"));
-            assertThat("Response",response,containsString("socket.getReuseAddress() = false"));
+
+            // Java on Windows is incapable of propagating reuse-address this to the opened socket.
+            if (!OS.IS_WINDOWS)
+            {
+                assertThat("Response",response,containsString("socket.getReuseAddress() = false"));
+            }
         }
         finally
         {
             server.stop();
         }
     }
+
+    @Test
+    public void testAddFirstConnectionFactory() throws Exception
+    {
+        Server server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        server.addConnector(connector);
+
+        HttpConnectionFactory http = new HttpConnectionFactory();
+        connector.addConnectionFactory(http);
+        ProxyConnectionFactory proxy = new ProxyConnectionFactory();
+        connector.addFirstConnectionFactory(proxy);
+
+        Collection<ConnectionFactory> factories = connector.getConnectionFactories();
+        assertEquals(2, factories.size());
+        assertSame(proxy, factories.iterator().next());
+        assertEquals(2, connector.getBeans(ConnectionFactory.class).size());
+        assertEquals(proxy.getProtocol(), connector.getDefaultProtocol());
+    }
 }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java
index dfc45c2..bfc0b16 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java
@@ -100,15 +100,17 @@
     private String getResponse(String request) throws UnsupportedEncodingException, IOException, InterruptedException
     {
         ServerConnector connector = (ServerConnector)_connector;
-        Socket socket = new Socket((String)null,connector.getLocalPort());
-        socket.setSoTimeout(10 * MAX_IDLE_TIME);
-        socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
-        InputStream inputStream = socket.getInputStream();
-        long start = System.currentTimeMillis();
-        String response = IO.toString(inputStream);
-        long timeElapsed = System.currentTimeMillis() - start;
-        assertTrue("Time elapsed should be at least MAX_IDLE_TIME",timeElapsed > MAX_IDLE_TIME);
-        return response;
-    }
 
+        try (Socket socket = new Socket((String)null,connector.getLocalPort()))
+        {
+            socket.setSoTimeout(10 * MAX_IDLE_TIME);
+            socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
+            InputStream inputStream = socket.getInputStream();
+            long start = System.currentTimeMillis();
+            String response = IO.toString(inputStream);
+            long timeElapsed = System.currentTimeMillis() - start;
+            assertTrue("Time elapsed should be at least MAX_IDLE_TIME",timeElapsed > MAX_IDLE_TIME);
+            return response;
+        }
+    }
 }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java
new file mode 100644
index 0000000..da186b2
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java
@@ -0,0 +1,215 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ssl.SslConnection;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AdvancedRunner.class)
+public class ThreadStarvationTest extends HttpServerTestFixture
+{
+    ServerConnector _connector;
+    
+    @Rule
+    public TestTracker tracker = new TestTracker();
+
+    @Before
+    public void init() throws Exception
+    {
+        _threadPool.setMinThreads(4);
+        _threadPool.setMaxThreads(4);
+        _threadPool.setDetailedDump(false);
+        _connector = new ServerConnector(_server,1,1);
+        _connector.setIdleTimeout(10000);
+    }
+
+    @Test
+    public void testReadInput() throws Exception
+    {
+        startServer(_connector,new ReadHandler());
+        System.err.println(_threadPool.dump());
+        
+        Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort());
+        client.setSoTimeout(10000);
+
+        OutputStream os=client.getOutputStream();
+        InputStream is=client.getInputStream();
+
+        os.write((
+                "GET / HTTP/1.0\r\n"+
+                "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                "content-length: 10\r\n" +
+                "\r\n" +
+                "0123456789\r\n").getBytes("utf-8"));
+        os.flush();
+
+        String response = IO.toString(is);
+        assertEquals(-1, is.read());
+        assertThat(response,containsString("200 OK"));
+        assertThat(response,containsString("Read Input 10"));
+
+    }
+    
+    @Test
+    public void testEWYKStarvation() throws Exception
+    {
+        System.setProperty("org.eclipse.jetty.io.ManagedSelector$SelectorProducer.ExecutionStrategy","org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume");
+        startServer(_connector,new ReadHandler());
+        
+        Socket[] client = new Socket[3];
+        OutputStream[] os = new OutputStream[client.length];
+        InputStream[] is = new InputStream[client.length];
+        
+        for (int i=0;i<client.length;i++)
+        {
+            client[i]=newSocket(_serverURI.getHost(),_serverURI.getPort());
+            client[i].setSoTimeout(10000);
+
+            os[i]=client[i].getOutputStream();
+            is[i]=client[i].getInputStream();
+
+            os[i].write((
+                    "PUT / HTTP/1.0\r\n"+
+                            "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                            "content-length: 10\r\n" +
+                    "\r\n1").getBytes("utf-8"));
+            os[i].flush();
+        }
+        Thread.sleep(500);
+        System.err.println(_threadPool.dump());
+
+        for (int i=0;i<client.length;i++)
+        {
+            os[i].write(("234567890\r\n").getBytes("utf-8"));
+            os[i].flush();
+        }
+
+        Thread.sleep(500);
+        System.err.println(_threadPool.dump());
+
+        for (int i=0;i<client.length;i++)
+        {
+            String response = IO.toString(is[i]);
+            assertEquals(-1, is[i].read());
+            assertThat(response,containsString("200 OK"));
+            assertThat(response,containsString("Read Input 10"));
+        }
+        
+    }
+    
+
+    @Test
+    public void testPECStarvation() throws Exception
+    {
+        System.setProperty("org.eclipse.jetty.io.ManagedSelector$SelectorProducer.ExecutionStrategy","org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume");
+
+        startServer(_connector,new ReadHandler());
+        System.err.println(_threadPool.dump());
+        
+        Socket[] client = new Socket[3];
+        OutputStream[] os = new OutputStream[client.length];
+        InputStream[] is = new InputStream[client.length];
+        
+        for (int i=0;i<client.length;i++)
+        {
+            client[i]=newSocket(_serverURI.getHost(),_serverURI.getPort());
+            client[i].setSoTimeout(10000);
+
+            os[i]=client[i].getOutputStream();
+            is[i]=client[i].getInputStream();
+
+            os[i].write((
+                    "PUT / HTTP/1.0\r\n"+
+                            "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+
+                            "content-length: 10\r\n" +
+                    "\r\n1").getBytes("utf-8"));
+            os[i].flush();
+        }
+        Thread.sleep(500);
+        System.err.println(_threadPool.dump());
+
+        for (int i=0;i<client.length;i++)
+        {
+            os[i].write(("234567890\r\n").getBytes("utf-8"));
+            os[i].flush();
+        }
+
+        Thread.sleep(500);
+        System.err.println(_threadPool.dump());
+
+        for (int i=0;i<client.length;i++)
+        {
+            String response = IO.toString(is[i]);
+            assertEquals(-1, is[i].read());
+            assertThat(response,containsString("200 OK"));
+            assertThat(response,containsString("Read Input 10"));
+        }
+        
+    }
+    
+
+    protected static class ReadHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            response.setStatus(200);
+
+            int l = request.getContentLength();
+            int r = 0;
+            while (r<l)
+            {
+                if (request.getInputStream().read()>=0)
+                    r++;
+            }
+            
+            response.getOutputStream().write(("Read Input "+r+"\r\n").getBytes());
+        }
+    }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BadRequestLogHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BadRequestLogHandlerTest.java
index f068f9e..4219f7a 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BadRequestLogHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/BadRequestLogHandlerTest.java
@@ -18,8 +18,8 @@
 
 package org.eclipse.jetty.server.handler;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -74,7 +74,8 @@
         @Override
         public void log(Request request, Response response)
         {
-            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getUri().toString(),request.getProtocol(),response.getStatus()));
+            int status = response.getCommittedMetaData().getStatus();
+            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getHttpURI(),request.getProtocol(),status));
         }
     }
     
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
index bca8cf6..8a60de0 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
@@ -18,10 +18,12 @@
 
 package org.eclipse.jetty.server.handler;
 
+import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -83,12 +85,26 @@
             
             Files.createSymbolicLink(new File(docroot,"other").toPath(),new File("../transit").toPath());
             Files.createSymbolicLink(transit.toPath(),otherroot.toPath());
+            
+            // /web/logs -> /var/logs -> /media/internal/logs
+            // where /media/internal -> /media/internal-physical/
+            new File(docroot,"media/internal-physical/logs").mkdirs();
+            Files.createSymbolicLink(new File(docroot,"media/internal").toPath(),new File(docroot,"media/internal-physical").toPath());
+            new File(docroot,"var").mkdir();
+            Files.createSymbolicLink(new File(docroot,"var/logs").toPath(),new File(docroot,"media/internal/logs").toPath());
+            new File(docroot,"web").mkdir();
+            Files.createSymbolicLink(new File(docroot,"web/logs").toPath(),new File(docroot,"var/logs").toPath()); 
+            new File(docroot,"media/internal-physical/logs/file.log").createNewFile();
+            
+            System.err.println("docroot="+docroot);
         }
         
         OS_ALIAS_SUPPORTED = new File(sub, "TEXTFI~1.TXT").exists(); 
         
         server = new Server();
         context =new ContextHandler("/");
+        context.clearAliasChecks();
+        context.addAliasCheck(new ContextHandler.ApproveNonExistentDirectoryAliases());
         context.setBaseResource(Resource.newResource(docroot));
         context.addAliasCheck(new ContextHandler.AliasCheck()
         {
@@ -122,7 +138,7 @@
         try
         {
             context.getResource(path);
-            fail();
+            fail("Expected " + MalformedURLException.class);
         }
         catch(MalformedURLException e)
         {
@@ -131,7 +147,7 @@
         try
         {
             context.getServletContext().getResource(path);
-            fail();
+            fail("Expected " + MalformedURLException.class);
         }
         catch(MalformedURLException e)
         {
@@ -300,17 +316,20 @@
     @Test
     public void testSlashSlash() throws Exception
     {
+        File expected = new File(docroot, OS.separators("subdir/data.txt"));
+        URL expectedUrl = expected.toURI().toURL();
+        
         String path="//subdir/data.txt";
         Resource resource=context.getResource(path);
-        assertNull(resource);
+        assertThat("Resource: " + resource, resource.getFile(), is(expected));
         URL url=context.getServletContext().getResource(path);
-        assertNull(url);
+        assertThat("Resource: " + url, url, is(expectedUrl));
         
         path="/subdir//data.txt";
         resource=context.getResource(path);
-        assertNull(resource);
+        assertThat("Resource: " + resource, resource.getFile(), is(expected));
         url=context.getServletContext().getResource(path);
-        assertNull(url);
+        assertThat("Resource: " + url, url, is(expectedUrl));
     }
 
     @Test
@@ -353,8 +372,8 @@
     @Test
     public void testSymlinkKnown() throws Exception
     {
-        if (!OS.IS_UNIX)
-            return;
+        Assume.assumeTrue(OS.IS_UNIX);
+        
         try
         {
             allowSymlinks.set(true);
@@ -376,6 +395,29 @@
         } 
         
     }
+    
+    @Test
+    public void testSymlinkNested() throws Exception
+    {
+        Assume.assumeTrue(OS.IS_UNIX);
+        
+        try
+        {
+            allowSymlinks.set(true);
+
+            final String path="/web/logs/file.log";
+
+            Resource resource=context.getResource(path);
+            assertNotNull(resource);
+            assertEquals("file.log",resource.getFile().getName());
+            assertTrue(resource.exists());
+        }
+        finally
+        {
+            allowSymlinks.set(false);
+        } 
+        
+    }
 
     @Test
     public void testSymlinkUnknown() throws Exception
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/DebugHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/DebugHandlerTest.java
new file mode 100644
index 0000000..2f2766c
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/DebugHandlerTest.java
@@ -0,0 +1,181 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
+import java.util.concurrent.Executor;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManagerFactory;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.server.AbstractConnectionFactory;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.SimpleRequest;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.Scheduler;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DebugHandlerTest
+{
+    public final static HostnameVerifier __hostnameverifier = new HostnameVerifier()
+    {
+        public boolean verify(String hostname, SSLSession session)
+        {
+            return true;
+        }
+    };
+    
+    private SSLContext sslContext;
+    private Server server;
+    private URI serverURI;
+    private URI secureServerURI;
+    
+    @SuppressWarnings("deprecation")
+    private DebugHandler debugHandler;
+    private ByteArrayOutputStream capturedLog;
+    
+    @SuppressWarnings("deprecation")
+    @Before
+    public void startServer() throws Exception
+    {
+        server = new Server();
+        
+        ServerConnector httpConnector = new ServerConnector(server);
+        httpConnector.setPort(0);
+        server.addConnector(httpConnector);
+        
+        File keystorePath = MavenTestingUtils.getTestResourceFile("keystore");
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath(keystorePath.getAbsolutePath());
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setKeyManagerPassword("keypwd");
+        sslContextFactory.setTrustStorePath(keystorePath.getAbsolutePath());
+        sslContextFactory.setTrustStorePassword("storepwd");
+        ByteBufferPool pool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged());
+        ServerConnector sslConnector = new ServerConnector(server,
+                (Executor)null,
+                (Scheduler)null, pool, 1, 1, 
+                AbstractConnectionFactory.getFactories(sslContextFactory,new HttpConnectionFactory()));
+        
+        server.addConnector(sslConnector);
+        
+        debugHandler = new DebugHandler();
+        capturedLog = new ByteArrayOutputStream();
+        debugHandler.setOutputStream(capturedLog);
+        debugHandler.setHandler(new AbstractHandler()
+            {
+                @Override
+                public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+                {
+                    baseRequest.setHandled(true);
+                    response.setStatus(HttpStatus.OK_200);
+                }
+            });
+        server.setHandler(debugHandler);
+        server.start();
+        
+        String host = httpConnector.getHost();
+        if(host == null) host = "localhost";
+        
+        serverURI = URI.create(String.format("http://%s:%d/", host, httpConnector.getLocalPort()));
+        secureServerURI = URI.create(String.format("https://%s:%d/", host, sslConnector.getLocalPort()));
+        
+        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+        try (InputStream stream = sslContextFactory.getKeyStoreResource().getInputStream())
+        {
+            keystore.load(stream, "storepwd".toCharArray());
+        }
+        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        trustManagerFactory.init(keystore);
+        sslContext = SSLContext.getInstance("TLS");
+        sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
+
+        try
+        {
+            HttpsURLConnection.setDefaultHostnameVerifier(__hostnameverifier);
+            SSLContext sc = SSLContext.getInstance("TLS");
+            sc.init(null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom());
+            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+        }
+        catch(Exception e)
+        {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+    
+    @After
+    public void stopServer() throws Exception
+    {
+        server.stop();
+    }
+    
+    @Test
+    public void testThreadName() throws IOException
+    {
+        SimpleRequest req = new SimpleRequest(serverURI);
+        req.getString("/foo/bar?a=b");
+        
+        String log = capturedLog.toString(StandardCharsets.UTF_8.name());
+        String expectedThreadName = String.format("//%s:%s/foo/bar?a=b",serverURI.getHost(),serverURI.getPort());
+        assertThat("ThreadName", log, containsString(expectedThreadName));
+        // Look for bad/mangled/duplicated schemes
+        assertThat("ThreadName", log, not(containsString("http:"+expectedThreadName)));
+        assertThat("ThreadName", log, not(containsString("https:"+expectedThreadName)));
+    }
+    
+    @Test
+    public void testSecureThreadName() throws IOException
+    {
+        SimpleRequest req = new SimpleRequest(secureServerURI);
+        req.getString("/foo/bar?a=b");
+        
+        String log = capturedLog.toString(StandardCharsets.UTF_8.name());
+        String expectedThreadName = String.format("https://%s:%s/foo/bar?a=b",secureServerURI.getHost(),secureServerURI.getPort());
+        assertThat("ThreadName", log, containsString(expectedThreadName));
+        // Look for bad/mangled/duplicated schemes
+        assertThat("ThreadName", log, not(containsString("http:"+expectedThreadName)));
+        assertThat("ThreadName", log, not(containsString("https:"+expectedThreadName)));
+    }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogHandlerTest.java
index 0065c35..84d3329 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogHandlerTest.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.server.handler;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -41,6 +42,8 @@
 
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpChannelState;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.RequestLog;
 import org.eclipse.jetty.server.Response;
@@ -50,6 +53,7 @@
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.log.StdErrLog;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -75,7 +79,8 @@
         @Override
         public void log(Request request, Response response)
         {
-            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getRequestURI(),request.getProtocol(),response.getStatus()));
+            int status = response.getCommittedMetaData().getStatus();
+            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getRequestURI(),request.getProtocol(),status));
         }
     }
 
@@ -372,6 +377,7 @@
 
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection. all other configuration on server at defaults.
+     * @throws Exception if test failure
      */
     @Test(timeout = 4000)
     public void testLogHandlerCollection() throws Exception
@@ -433,8 +439,77 @@
         }
     }
 
+    @Test(timeout = 4000)
+    public void testMultipleLogHandlers() throws Exception
+    {
+        Server server = new Server();
+        ServerConnector connector = new ServerConnector(server);
+        connector.setPort(0);
+        server.setConnectors(new Connector[]{connector});
+
+        List<CaptureLog> captureLogs = new ArrayList<>();
+        List<Handler> handlerList = new ArrayList<>();
+        handlerList.add(testHandler);
+
+        for (int i = 0; i < 4; ++i) {
+            CaptureLog captureLog = new CaptureLog();
+            captureLogs.add(captureLog);
+            RequestLogHandler requestLog = new RequestLogHandler();
+            requestLog.setRequestLog(captureLog);
+            handlerList.add(requestLog);
+        }
+
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(handlerList.toArray(new Handler[0]));
+        server.setHandler(handlers);
+
+        try
+        {
+            server.start();
+
+            String host = connector.getHost();
+            if (host == null)
+            {
+                host = "localhost";
+            }
+            int port = connector.getLocalPort();
+
+            URI serverUri = new URI("http",null,host,port,requestPath,null,null);
+
+            // Make call to test handler
+            HttpURLConnection connection = (HttpURLConnection)serverUri.toURL().openConnection();
+            try
+            {
+                connection.setAllowUserInteraction(false);
+
+                // log response status code
+                int statusCode = connection.getResponseCode();
+                LOG.debug("Response Status Code: {}",statusCode);
+
+                if (statusCode == 200)
+                {
+                    // collect response message and log it
+                    String content = getResponseContent(connection);
+                    LOG.debug("Response Content: {}",content);
+                }
+            }
+            finally
+            {
+                connection.disconnect();
+            }
+
+            for (CaptureLog captureLog:captureLogs)
+                assertRequestLog(captureLog);
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection and also with the default ErrorHandler as server bean in place.
+     * @throws Exception if test failure
      */
     @Test(timeout = 4000)
     public void testLogHandlerCollection_ErrorHandler_ServerBean() throws Exception
@@ -501,6 +576,7 @@
 
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection and also with the ErrorHandler in place.
+     * @throws Exception if test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection_AltErrorHandler() throws Exception
@@ -574,6 +650,7 @@
     
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection and also with the ErrorHandler in place.
+     * @throws Exception if test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection_OKErrorHandler() throws Exception
@@ -647,6 +724,7 @@
     
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection and also with the ErrorHandler in place.
+     * @throws Exception if test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection_DispatchErrorHandler() throws Exception
@@ -660,9 +738,9 @@
         server.addBean(errorDispatcher);
         
         ContextHandlerCollection contexts = new ContextHandlerCollection();
-        ContextHandler errorContext = new ContextHandler("errorok");
+        ContextHandler errorContext = new ContextHandler("/errorok");
         errorContext.setHandler(new OKErrorHandler());
-        ContextHandler testContext = new ContextHandler("test");
+        ContextHandler testContext = new ContextHandler("/test");
         testContext.setHandler(testHandler);
         contexts.addHandler(errorContext);
         contexts.addHandler(testContext);
@@ -737,6 +815,8 @@
 
         try
         {
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
+            ((StdErrLog)Log.getLogger(HttpChannelState.class)).setHideStacks(true);
             server.start();
 
             String host = connector.getHost();
@@ -775,6 +855,8 @@
         finally
         {
             server.stop();
+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
+            ((StdErrLog)Log.getLogger(HttpChannelState.class)).setHideStacks(false);
         }
     }
 
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogTest.java
new file mode 100644
index 0000000..98461bf
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/RequestLogTest.java
@@ -0,0 +1,300 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.concurrent.Exchanger;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.AbstractNCSARequestLog;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RequestLogTest
+{
+    Exchanger<String> _log;
+    Server _server;
+    LocalConnector _connector;
+    
+
+    @Before
+    public void before() throws Exception
+    {
+        _log = new Exchanger<String>();
+        _server = new Server();
+        _connector = new LocalConnector(_server);
+        _server.addConnector(_connector);
+        _server.setRequestLog(new Log());
+        _server.setHandler(new TestHandler());
+        _server.start();
+    }
+    
+    @After
+    public void after() throws Exception
+    {
+
+        _server.stop();
+    }
+    
+    
+    @Test
+    public void testNotHandled() throws Exception
+    {
+        _connector.getResponses("GET /foo HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo HTTP/1.0\" 404 "));
+    }
+
+    @Test
+    public void testRequestLine() throws Exception
+    {
+        _connector.getResponses("GET /foo?data=1 HTTP/1.0\nhost: host:80\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        // TODO should be without host (https://bugs.eclipse.org/bugs/show_bug.cgi?id=480276)
+        // assertThat(log,containsString("GET /foo?data=1 HTTP/1.0\" 200 "));
+        assertThat(log,containsString("GET //host:80/foo?data=1 HTTP/1.0\" 200 "));
+        
+        _connector.getResponses("GET //host/foo?data=1 HTTP/1.0\n\n");
+        log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET //host/foo?data=1 HTTP/1.0\" 200 "));
+        
+        _connector.getResponses("GET //absolute:80/foo?data=1 HTTP/1.0\nhost: host:80\n\n");
+        log = _log.exchange(null,5,TimeUnit.SECONDS);
+        // TODO should it be with absolute? (https://bugs.eclipse.org/bugs/show_bug.cgi?id=480276)
+        // assertThat(log,containsString("GET //absolute:80/foo?data=1 HTTP/1.0\" 200 "));
+        assertThat(log,containsString("GET //host:80/foo?data=1 HTTP/1.0\" 200 "));
+        
+        _connector.getResponses("GET http://host:80/foo?data=1 HTTP/1.0\n\n");
+        log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET http://host:80/foo?data=1 HTTP/1.0\" 200 "));   
+    }
+    
+    @Test
+    public void testSmallData() throws Exception
+    {
+        _connector.getResponses("GET /foo?data=42 HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo?"));
+        assertThat(log,containsString(" 200 42 "));
+    }
+    
+    @Test
+    public void testBigData() throws Exception
+    {
+        _connector.getResponses("GET /foo?data=102400 HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo?"));
+        assertThat(log,containsString(" 200 102400 "));
+    }
+    
+    @Test
+    public void testStatus() throws Exception
+    {
+        _connector.getResponses("GET /foo?status=206 HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo?"));
+        assertThat(log,containsString(" 206 0 "));
+    }
+    
+    @Test
+    public void testStatusData() throws Exception
+    {
+        _connector.getResponses("GET /foo?status=206&data=42 HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo?"));
+        assertThat(log,containsString(" 206 42 "));
+    }
+    
+    @Test
+    public void testBadRequest() throws Exception
+    {
+        _connector.getResponses("XXXXXXXXXXXX\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("\"- - -\""));
+        assertThat(log,containsString(" 400 0 "));
+    }
+    
+    @Test
+    public void testBadCharacter() throws Exception
+    {
+        _connector.getResponses("METHOD /f\00o HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("\"- - -\""));
+        assertThat(log,containsString(" 400 0 "));
+    }
+    
+    @Test
+    public void testBadVersion() throws Exception
+    {
+        _connector.getResponses("METHOD /foo HTTP/9\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("\"- - -\""));
+        assertThat(log,containsString(" 400 0 "));
+    }
+    
+    @Test
+    public void testLongURI() throws Exception
+    {
+        char[] chars = new char[10000];
+        Arrays.fill(chars,'o');
+        String ooo = new String(chars);
+        _connector.getResponses("METHOD /f"+ooo+" HTTP/1.0\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("\"- - -\""));
+        assertThat(log,containsString(" 414 0 "));
+    }
+    
+    @Test
+    public void testLongHeader() throws Exception
+    {
+        char[] chars = new char[10000];
+        Arrays.fill(chars,'o');
+        String ooo = new String(chars);
+        _connector.getResponses("METHOD /foo HTTP/1.0\name: f+"+ooo+"\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("\"METHOD /foo HTTP/1.0\""));
+        assertThat(log,containsString(" 413 0 "));
+    }
+    
+    @Test
+    public void testBadRequestNoHost() throws Exception
+    {
+        _connector.getResponses("GET /foo HTTP/1.1\n\n");
+        String log = _log.exchange(null,5,TimeUnit.SECONDS);
+        assertThat(log,containsString("GET /foo "));
+        assertThat(log,containsString(" 400 0 "));
+    }
+    
+    private class Log extends AbstractNCSARequestLog
+    {
+        {
+            super.setExtended(true);
+        }
+
+        @Override
+        protected boolean isEnabled()
+        {
+            return true;
+        }
+
+        @Override
+        public void write(String requestEntry) throws IOException
+        {
+            try
+            {
+                _log.exchange(requestEntry);
+            }
+            catch(Exception e)
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private class TestHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            String q = request.getQueryString();
+            if (q==null)
+                return;
+            
+            baseRequest.setHandled(true);
+            for (String action : q.split("\\&"))
+            {
+                String[] param = action.split("=");
+                String name=param[0];
+                String value=param.length>1?param[1]:null;
+                switch(name)
+                {
+                    case "status":
+                    {
+                        response.setStatus(Integer.parseInt(value));
+                        break;
+                    }
+                        
+                    case "data":
+                    {
+                        int data = Integer.parseInt(value);
+                        PrintWriter out = response.getWriter();
+                        
+                        int w=0;
+                        while (w<data)
+                        {
+                            if ((data-w)>17)
+                            {
+                                w+=17;
+                                out.print("0123456789ABCDEF\n");
+                            }
+                            else
+                            {
+                                w++;
+                                out.print("\n");
+                            }
+                        }
+                        break;
+                    }
+
+                    case "throw":
+                    {
+                        try
+                        {
+                            throw (Throwable)(Class.forName(value).newInstance());
+                        }
+                        catch(ServletException | IOException | Error | RuntimeException e)
+                        {
+                            throw e;
+                        }
+                        catch(Throwable e)
+                        {
+                            throw new ServletException(e);
+                        }
+                    }
+                    case "flush":
+                    {
+                        response.flushBuffer();
+                        break;
+                    }
+                    
+                    case "read":
+                    {
+                        InputStream in = request.getInputStream();
+                        while (in.read()>=0);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java
index a6395ee..909df3a 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerTest.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.server.handler;
 
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -33,6 +36,7 @@
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.LocalConnector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@@ -58,6 +62,7 @@
     private static Server _server;
     private static HttpConfiguration _config;
     private static ServerConnector _connector;
+    private static LocalConnector _local;
     private static ContextHandler _contextHandler;
     private static ResourceHandler _resourceHandler;
 
@@ -111,7 +116,9 @@
         _config.setOutputBufferSize(2048);
         _connector = new ServerConnector(_server,new HttpConnectionFactory(_config));
 
-        _server.setConnectors(new Connector[] { _connector });
+        _local = new LocalConnector(_server);
+        
+        _server.setConnectors(new Connector[] { _connector, _local });
 
         _resourceHandler = new ResourceHandler();
         _resourceHandler.setMinAsyncContentLength(4096);
@@ -152,6 +159,18 @@
     }
 
     @Test
+    public void testHeaders() throws Exception
+    {
+        String response = _local.getResponses("GET /resource/simple.txt HTTP/1.0\r\n\r\n");
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(response,Matchers.containsString("Content-Type: text/plain"));
+        assertThat(response,Matchers.containsString("Last-Modified: "));
+        assertThat(response,Matchers.containsString("Content-Length: 11"));
+        assertThat(response,Matchers.containsString("Server: Jetty"));
+        assertThat(response,Matchers.containsString("simple text"));
+    }
+
+    @Test
     public void testBigFile() throws Exception
     {
         _config.setOutputBufferSize(2048);
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java
index 88b91f1..051d9ee 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ScopedHandlerTest.java
@@ -27,6 +27,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -82,6 +83,9 @@
     @Test
     public void testDouble() throws Exception
     {
+        Request request = new Request(null,null);
+        Response response = new Response(null,null);
+        
         TestHandler handler0 = new TestHandler("0");
         OtherHandler handlerA = new OtherHandler("A");
         TestHandler handler1 = new TestHandler("1");
@@ -90,7 +94,7 @@
         handlerA.setHandler(handler1);
         handler1.setHandler(handlerB);
         handler0.start();
-        handler0.handle("target",null,null,null);
+        handler0.handle("target",request,request,response);
         handler0.stop();
         String history=_history.toString();
         assertEquals(">S0>S1>W0>HA>W1>HB<HB<W1<HA<W0<S1<S0",history);
@@ -99,6 +103,9 @@
     @Test
     public void testTriple() throws Exception
     {
+        Request request = new Request(null,null);
+        Response response = new Response(null,null);
+        
         TestHandler handler0 = new TestHandler("0");
         OtherHandler handlerA = new OtherHandler("A");
         TestHandler handler1 = new TestHandler("1");
@@ -111,7 +118,7 @@
         handlerB.setHandler(handler2);
         handler2.setHandler(handlerC);
         handler0.start();
-        handler0.handle("target",null,null,null);
+        handler0.handle("target",request,request,response);
         handler0.stop();
         String history=_history.toString();
         assertEquals(">S0>S1>S2>W0>HA>W1>HB>W2>HC<HC<W2<HB<W1<HA<W0<S2<S1<S0",history);
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
index 3b51e59..328d4d5 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SecuredRedirectHandlerTest.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.server.handler;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java
index 193192b..e56e3de 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java
@@ -171,42 +171,68 @@
         assertEquals(0, _statsHandler.getAsyncDispatches());
         assertEquals(0, _statsHandler.getExpires());
         assertEquals(2, _statsHandler.getResponses2xx());
+    }
 
+
+    @Test
+    public void testTwoRequests() throws Exception
+    {
+        final CyclicBarrier barrier[] = {new CyclicBarrier(3), new CyclicBarrier(3)};
         _latchHandler.reset(2);
-        barrier[0] = new CyclicBarrier(3);
-        barrier[1] = new CyclicBarrier(3);
+        _statsHandler.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
+            {
+                request.setHandled(true);
+                try
+                {
+                    barrier[0].await();
+                    barrier[1].await();
+                }
+                catch (Exception x)
+                {
+                    Thread.currentThread().interrupt();
+                    throw (IOException)new IOException().initCause(x);
+                }
+            }
+        });
+        _server.start();
 
+        String request = "GET / HTTP/1.1\r\n" +
+                "Host: localhost\r\n" +
+                "\r\n";
+    
         _connector.executeRequest(request);
         _connector.executeRequest(request);
 
         barrier[0].await();
 
-        assertEquals(4, _statistics.getConnectionsOpen());
+        assertEquals(2, _statistics.getConnectionsOpen());
 
-        assertEquals(4, _statsHandler.getRequests());
+        assertEquals(2, _statsHandler.getRequests());
         assertEquals(2, _statsHandler.getRequestsActive());
         assertEquals(2, _statsHandler.getRequestsActiveMax());
 
-        assertEquals(4, _statsHandler.getDispatched());
+        assertEquals(2, _statsHandler.getDispatched());
         assertEquals(2, _statsHandler.getDispatchedActive());
         assertEquals(2, _statsHandler.getDispatchedActiveMax());
 
-
         barrier[1].await();
         assertTrue(_latchHandler.await());
 
-        assertEquals(4, _statsHandler.getRequests());
+        assertEquals(2, _statsHandler.getRequests());
         assertEquals(0, _statsHandler.getRequestsActive());
         assertEquals(2, _statsHandler.getRequestsActiveMax());
 
-        assertEquals(4, _statsHandler.getDispatched());
+        assertEquals(2, _statsHandler.getDispatched());
         assertEquals(0, _statsHandler.getDispatchedActive());
         assertEquals(2, _statsHandler.getDispatchedActiveMax());
 
         assertEquals(0, _statsHandler.getAsyncRequests());
         assertEquals(0, _statsHandler.getAsyncDispatches());
         assertEquals(0, _statsHandler.getExpires());
-        assertEquals(4, _statsHandler.getResponses2xx());
+        assertEquals(2, _statsHandler.getResponses2xx());
     }
 
     @Test
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
index 8634cd1..c1ad7da 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/HashSessionManagerTest.java
@@ -25,11 +25,7 @@
 import org.eclipse.jetty.toolchain.test.FS;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 
 public class HashSessionManagerTest
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java
index 3bb550c..497c78d 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java
@@ -31,24 +31,14 @@
 
 import org.eclipse.jetty.http.HttpCookie;
 import org.junit.Test;
+
 /**
  * SessionCookieTest
- *
- *
  */
 public class SessionCookieTest
 {
-
     public class MockSession extends AbstractSession
     {
-
-
-        /**
-         * @param abstractSessionManager
-         * @param created
-         * @param accessed
-         * @param clusterId
-         */
         protected MockSession(AbstractSessionManager abstractSessionManager, long created, long accessed, String clusterId)
         {
             super(abstractSessionManager, created, accessed, clusterId);
@@ -72,9 +62,6 @@
             return null;
         }
 
-        /** 
-         * @see javax.servlet.http.HttpSession#getValueNames()
-         */
         @Override
         public String[] getValueNames()
         {
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
index 7d11815..eb68ed4 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SelectChannelServerSslTest.java
@@ -128,7 +128,7 @@
         startServer(connector);
 
         KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
-        try (InputStream stream = new FileInputStream(sslContextFactory.getKeyStorePath()))
+        try (InputStream stream = sslContextFactory.getKeyStoreResource().getInputStream())
         {
             keystore.load(stream, "storepwd".toCharArray());
         }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java
new file mode 100644
index 0000000..5543ab7
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SniSslConnectionFactoryTest.java
@@ -0,0 +1,404 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.ssl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Queue;
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SocketCustomizationListener;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.Utf8StringBuilder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SniSslConnectionFactoryTest
+{
+    private Server _server;
+    private ServerConnector _connector;
+    private HttpConfiguration _https_config;
+    private int _port;
+
+    @Before
+    public void before() throws Exception
+    {
+        String keystorePath = "src/test/resources/snikeystore";
+        File keystoreFile = new File(keystorePath);
+        if (!keystoreFile.exists())
+            throw new FileNotFoundException(keystoreFile.getAbsolutePath());
+
+        _server = new Server();
+
+        HttpConfiguration http_config = new HttpConfiguration();
+        http_config.setSecureScheme("https");
+        http_config.setSecurePort(8443);
+        http_config.setOutputBufferSize(32768);
+        _https_config = new HttpConfiguration(http_config);
+        _https_config.addCustomizer(new SecureRequestCustomizer());
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
+        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
+        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
+
+        ServerConnector https = _connector = new ServerConnector(_server,
+                new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
+                new HttpConnectionFactory(_https_config));
+        _server.addConnector(https);
+
+        _server.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                response.setStatus(200);
+                response.setHeader("X-URL", request.getRequestURI());
+                response.setHeader("X-HOST", request.getServerName());
+            }
+        });
+
+        _server.start();
+        _port = https.getLocalPort();
+    }
+
+    @After
+    public void after() throws Exception
+    {
+        if (_server != null)
+            _server.stop();
+    }
+
+    @Test
+    public void testConnect() throws Exception
+    {
+        String response = getResponse("127.0.0.1", null);
+        Assert.assertThat(response, Matchers.containsString("X-HOST: 127.0.0.1"));
+    }
+
+    @Test
+    public void testSNIConnectNoWild() throws Exception
+    {
+        // Use the alternate keystore without wildcard certificates.
+        _server.stop();
+        _server.removeConnector(_connector);
+
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath("src/test/resources/snikeystore_nowild");
+        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
+        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
+
+        _connector = new ServerConnector(_server,
+                new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
+                new HttpConnectionFactory(_https_config));
+        _server.addConnector(_connector);
+        _server.start();
+        _port = _connector.getLocalPort();
+
+        // The first entry in the keystore is www.example.com, and it will
+        // be returned by default, so make sure that here we don't ask for it.
+        String response = getResponse("jetty.eclipse.org", "jetty.eclipse.org");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: jetty.eclipse.org"));
+    }
+
+    @Test
+    public void testSNIConnect() throws Exception
+    {
+        String response = getResponse("jetty.eclipse.org", "jetty.eclipse.org");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: jetty.eclipse.org"));
+
+        response = getResponse("www.example.com", "www.example.com");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: www.example.com"));
+
+        response = getResponse("foo.domain.com", "*.domain.com");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: foo.domain.com"));
+
+        response = getResponse("m.san.com", "san example");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: m.san.com"));
+
+        response = getResponse("www.san.com", "san example");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: www.san.com"));
+    }
+
+    @Test
+    public void testWildSNIConnect() throws Exception
+    {
+        String response = getResponse("domain.com", "www.domain.com", "*.domain.com");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: www.domain.com"));
+
+        response = getResponse("domain.com", "domain.com", "*.domain.com");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: domain.com"));
+
+        response = getResponse("www.domain.com", "www.domain.com", "*.domain.com");
+        Assert.assertThat(response, Matchers.containsString("X-HOST: www.domain.com"));
+    }
+
+    @Test
+    public void testBadSNIConnect() throws Exception
+    {
+        String response = getResponse("www.example.com", "some.other.com", "www.example.com");
+        Assert.assertThat(response, Matchers.containsString("HTTP/1.1 400 "));
+        Assert.assertThat(response, Matchers.containsString("Host does not match SNI"));
+    }
+
+    @Test
+    public void testSameConnectionRequestsForManyDomains() throws Exception
+    {
+        SslContextFactory clientContextFactory = new SslContextFactory(true);
+        clientContextFactory.start();
+        SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
+        try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
+        {
+            SNIHostName serverName = new SNIHostName("m.san.com");
+            SSLParameters params = sslSocket.getSSLParameters();
+            params.setServerNames(Collections.singletonList(serverName));
+            sslSocket.setSSLParameters(params);
+            sslSocket.startHandshake();
+
+            // The first request binds the socket to an alias.
+            String request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: m.san.com\r\n" +
+                    "\r\n";
+            OutputStream output = sslSocket.getOutputStream();
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            InputStream input = sslSocket.getInputStream();
+            String response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 200 "));
+
+            // Same socket, send a request for a different domain but same alias.
+            request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: www.san.com\r\n" +
+                    "\r\n";
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 200 "));
+
+            // Same socket, send a request for a different domain but different alias.
+            request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: www.example.com\r\n" +
+                    "\r\n";
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 400 "));
+            Assert.assertThat(response, Matchers.containsString("Host does not match SNI"));
+        }
+        finally
+        {
+            clientContextFactory.stop();
+        }
+    }
+
+    @Test
+    public void testSameConnectionRequestsForManyWildDomains() throws Exception
+    {
+        SslContextFactory clientContextFactory = new SslContextFactory(true);
+        clientContextFactory.start();
+        SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
+        try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
+        {
+            SNIHostName serverName = new SNIHostName("www.domain.com");
+            SSLParameters params = sslSocket.getSSLParameters();
+            params.setServerNames(Collections.singletonList(serverName));
+            sslSocket.setSSLParameters(params);
+            sslSocket.startHandshake();
+
+            String request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: www.domain.com\r\n" +
+                    "\r\n";
+            OutputStream output = sslSocket.getOutputStream();
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            InputStream input = sslSocket.getInputStream();
+            String response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 200 "));
+
+            // Now, on the same socket, send a request for a different valid domain.
+            request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: assets.domain.com\r\n" +
+                    "\r\n";
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 200 "));
+
+            // Now make a request for an invalid domain for this connection.
+            request = "" +
+                    "GET /ctx/path HTTP/1.1\r\n" +
+                    "Host: www.example.com\r\n" +
+                    "\r\n";
+            output.write(request.getBytes(StandardCharsets.UTF_8));
+            output.flush();
+
+            response = response(input);
+            Assert.assertTrue(response.startsWith("HTTP/1.1 400 "));
+            Assert.assertThat(response, Matchers.containsString("Host does not match SNI"));
+        }
+        finally
+        {
+            clientContextFactory.stop();
+        }
+    }
+
+    private String response(InputStream input) throws IOException
+    {
+        Utf8StringBuilder buffer = new Utf8StringBuilder();
+        int crlfs = 0;
+        while (true)
+        {
+            int read = input.read();
+            Assert.assertTrue(read >= 0);
+            buffer.append((byte)read);
+            crlfs = (read == '\r' || read == '\n') ? crlfs + 1 : 0;
+            if (crlfs == 4)
+                break;
+        }
+        return buffer.toString();
+    }
+
+    private String getResponse(String host, String cn) throws Exception
+    {
+        String response = getResponse(host, host, cn);
+        Assert.assertThat(response, Matchers.startsWith("HTTP/1.1 200 "));
+        Assert.assertThat(response, Matchers.containsString("X-URL: /ctx/path"));
+        return response;
+    }
+
+    private String getResponse(String sniHost, String reqHost, String cn) throws Exception
+    {
+        SslContextFactory clientContextFactory = new SslContextFactory(true);
+        clientContextFactory.start();
+        SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
+        try (SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port))
+        {
+            if (cn != null)
+            {
+                SNIHostName serverName = new SNIHostName(sniHost);
+                List<SNIServerName> serverNames = new ArrayList<>();
+                serverNames.add(serverName);
+
+                SSLParameters params = sslSocket.getSSLParameters();
+                params.setServerNames(serverNames);
+                sslSocket.setSSLParameters(params);
+            }
+            sslSocket.startHandshake();
+
+            if (cn != null)
+            {
+                X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
+                Assert.assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn=" + cn));
+            }
+
+            String response = "GET /ctx/path HTTP/1.0\r\nHost: " + reqHost + ":" + _port + "\r\n\r\n";
+            sslSocket.getOutputStream().write(response.getBytes(StandardCharsets.ISO_8859_1));
+            return IO.toString(sslSocket.getInputStream());
+        }
+        finally
+        {
+            clientContextFactory.stop();
+        }
+    }
+
+    @Test
+    public void testSocketCustomization() throws Exception
+    {
+        final Queue<String> history = new ConcurrentArrayQueue<>();
+
+        _connector.addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize connector " + connection + "," + ssl);
+            }
+        });
+
+        _connector.getBean(SslConnectionFactory.class).addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize ssl " + connection + "," + ssl);
+            }
+        });
+
+        _connector.getBean(HttpConnectionFactory.class).addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize http " + connection + "," + ssl);
+            }
+        });
+
+        String response = getResponse("127.0.0.1", null);
+        Assert.assertThat(response, Matchers.containsString("X-HOST: 127.0.0.1"));
+
+        Assert.assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
+        Assert.assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false", history.poll());
+        Assert.assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true", history.poll());
+        Assert.assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true", history.poll());
+        Assert.assertEquals(0, history.size());
+    }
+}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java
new file mode 100644
index 0000000..9f0e433
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java
@@ -0,0 +1,239 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.ssl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SocketCustomizationListener;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SslConnectionFactoryTest
+{        
+    Server _server;
+    ServerConnector _connector;
+    int _port;
+    
+    @Before
+    public void before() throws Exception
+    {
+        String keystorePath = "src/test/resources/keystore";
+        File keystoreFile = new File(keystorePath);
+        if (!keystoreFile.exists())
+        {
+            throw new FileNotFoundException(keystoreFile.getAbsolutePath());
+        }
+
+        _server = new Server();
+
+        HttpConfiguration http_config = new HttpConfiguration();
+        http_config.setSecureScheme("https");
+        http_config.setSecurePort(8443);
+        http_config.setOutputBufferSize(32768);
+        HttpConfiguration https_config = new HttpConfiguration(http_config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
+
+        
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
+        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
+        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
+
+        ServerConnector https = _connector = new ServerConnector(_server,
+            new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
+                new HttpConnectionFactory(https_config));
+        https.setPort(0);
+        https.setIdleTimeout(30000);
+
+        _server.addConnector(https);
+        
+        _server.setHandler(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                response.setStatus(200);
+                response.getWriter().write("url="+request.getRequestURI()+"\nhost="+request.getServerName());
+                response.flushBuffer();
+            }
+        });
+        
+        _server.start();
+        _port=https.getLocalPort();   
+    }
+    
+    @After
+    public void after() throws Exception
+    {
+        _server.stop();
+        _server=null;
+    }
+    
+    @Test
+    public void testConnect() throws Exception
+    {
+        String response= getResponse("127.0.0.1",null);        
+        Assert.assertThat(response,Matchers.containsString("host=127.0.0.1"));
+    }
+    
+    @Test
+    public void testSNIConnect() throws Exception
+    {
+        String response;
+        
+        response= getResponse("localhost","localhost","jetty.eclipse.org");
+        Assert.assertThat(response,Matchers.containsString("host=localhost"));
+    }
+
+
+    private String getResponse(String host,String cn) throws Exception
+    {
+        String response = getResponse(host,host,cn);
+        Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK"));
+        Assert.assertThat(response,Matchers.containsString("url=/ctx/path"));
+        return response;
+    }
+
+    @Test
+    public void testBadHandshake() throws Exception
+    {
+        try(Socket socket=new Socket("127.0.0.1", _port); OutputStream out = socket.getOutputStream())
+        {
+            out.write("Rubbish".getBytes());
+            out.flush();
+            
+            Assert.assertThat(socket.getInputStream().read(),Matchers.equalTo(-1));
+        }
+        
+    }
+    
+    private String getResponse(String sniHost,String reqHost, String cn) throws Exception
+    {
+        SslContextFactory clientContextFactory = new SslContextFactory(true);
+        clientContextFactory.start();
+        SSLSocketFactory factory = clientContextFactory.getSslContext().getSocketFactory();
+        
+        SSLSocket sslSocket = (SSLSocket)factory.createSocket("127.0.0.1", _port);
+
+        if (cn!=null)
+        {        
+            SNIHostName serverName = new SNIHostName(sniHost);
+            List<SNIServerName> serverNames = new ArrayList<>();
+            serverNames.add(serverName);
+
+            SSLParameters params = sslSocket.getSSLParameters();
+            params.setServerNames(serverNames);
+            sslSocket.setSSLParameters(params);
+        }
+        sslSocket.startHandshake();
+
+        
+        if (cn!=null)
+        {                                        
+            X509Certificate cert = ((X509Certificate)sslSocket.getSession().getPeerCertificates()[0]);
+            
+            Assert.assertThat(cert.getSubjectX500Principal().getName("CANONICAL"), Matchers.startsWith("cn="+cn));
+        }
+
+        sslSocket.getOutputStream().write(("GET /ctx/path HTTP/1.0\r\nHost: "+reqHost+":"+_port+"\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1));
+        String response = IO.toString(sslSocket.getInputStream());
+        
+        sslSocket.close();
+        clientContextFactory.stop();
+        return response;
+    }
+    
+
+    @Test
+    public void testSocketCustomization() throws Exception
+    {
+        final Queue<String> history = new ConcurrentArrayQueue<>();
+        
+        _connector.addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize connector "+connection+","+ssl);
+            }            
+        });
+
+        _connector.getBean(SslConnectionFactory.class).addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize ssl "+connection+","+ssl);
+            }            
+        });
+        
+        _connector.getBean(HttpConnectionFactory.class).addBean(new SocketCustomizationListener()
+        {
+            @Override
+            protected void customize(Socket socket, Class<? extends Connection> connection, boolean ssl)
+            {
+                history.add("customize http "+connection+","+ssl);
+            }            
+        });
+
+        String response= getResponse("127.0.0.1",null);        
+        Assert.assertThat(response,Matchers.containsString("host=127.0.0.1"));
+        
+        Assert.assertEquals("customize connector class org.eclipse.jetty.io.ssl.SslConnection,false",history.poll());
+        Assert.assertEquals("customize ssl class org.eclipse.jetty.io.ssl.SslConnection,false",history.poll());
+        Assert.assertEquals("customize connector class org.eclipse.jetty.server.HttpConnection,true",history.poll());
+        Assert.assertEquals("customize http class org.eclipse.jetty.server.HttpConnection,true",history.poll());
+        Assert.assertEquals(0,history.size());
+    }
+    
+}
diff --git a/jetty-server/src/test/resources/jetty-logging.properties b/jetty-server/src/test/resources/jetty-logging.properties
index adf68c7..f345cd6 100644
--- a/jetty-server/src/test/resources/jetty-logging.properties
+++ b/jetty-server/src/test/resources/jetty-logging.properties
@@ -1,3 +1,3 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.LEVEL=DEBUG
+org.eclipse.jetty.LEVEL=INFO
 #org.eclipse.jetty.server.LEVEL=DEBUG
diff --git a/jetty-server/src/test/resources/keystore b/jetty-server/src/test/resources/keystore
index b727bd0..d6592f9 100644
--- a/jetty-server/src/test/resources/keystore
+++ b/jetty-server/src/test/resources/keystore
Binary files differ
diff --git a/jetty-server/src/test/resources/snikeystore b/jetty-server/src/test/resources/snikeystore
new file mode 100644
index 0000000..3c69266
--- /dev/null
+++ b/jetty-server/src/test/resources/snikeystore
Binary files differ
diff --git a/jetty-server/src/test/resources/snikeystore_nowild b/jetty-server/src/test/resources/snikeystore_nowild
new file mode 100644
index 0000000..91c6166
--- /dev/null
+++ b/jetty-server/src/test/resources/snikeystore_nowild
Binary files differ
diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml
index ebae417..38ce527 100644
--- a/jetty-servlet/pom.xml
+++ b/jetty-servlet/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>jetty-project</artifactId>
     <groupId>org.eclipse.jetty</groupId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-servlet</artifactId>
@@ -16,34 +16,8 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.eclipse.jetty.jmx.*;version="9.1";resolution:=optional,*</Import-Package>
-                <_nouses>true</_nouses>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
         <executions>
           <execution>
             <id>tests</id>
@@ -54,23 +28,6 @@
         </executions>
       </plugin>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
@@ -96,5 +53,12 @@
       <artifactId>jetty-test-helper</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-http</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/BaseHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/BaseHolder.java
index f0525b1..5fda9d1 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/BaseHolder.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/BaseHolder.java
@@ -38,7 +38,7 @@
  * Base class for all servlet-related classes that may be lazily instantiated  (eg servlet, filter, 
  * listener), and/or require metadata to be held regarding their origin 
  * (web.xml, annotation, programmatic api etc).
- * 
+ * @param <T> the type of holder
  */
 public abstract class BaseHolder<T> extends AbstractLifeCycle implements Dumpable
 {
@@ -68,7 +68,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Do any setup necessary after starting
-     * @throws Exception
+     * @throws Exception if unable to initialize
      */
     public void initialize()
     throws Exception
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
index 3909259..ab958d3 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.servlet;
 
+import static org.eclipse.jetty.http.GzipHttpContent.ETAG_GZIP_QUOTE;
+import static org.eclipse.jetty.http.GzipHttpContent.removeGzipFromETag;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -39,18 +42,23 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.DateParser;
+import org.eclipse.jetty.http.GzipHttpContent;
 import org.eclipse.jetty.http.HttpContent;
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator.CachedHttpField;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpMethod;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.http.PathMap.MappedEntry;
+import org.eclipse.jetty.http.PreEncodedHttpField;
+import org.eclipse.jetty.http.ResourceHttpContent;
 import org.eclipse.jetty.io.WriterOutputStream;
 import org.eclipse.jetty.server.HttpOutput;
 import org.eclipse.jetty.server.InclusiveByteRange;
+import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.ResourceCache;
+import org.eclipse.jetty.server.ResourceContentFactory;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.BufferUtil;
@@ -66,16 +74,15 @@
 import org.eclipse.jetty.util.resource.ResourceFactory;
 
 
-
-/* ------------------------------------------------------------ */
-/** The default servlet.
- * 
+/** 
+ * The default servlet.
+ * <p>
  * This servlet, normally mapped to /, provides the handling for static
  * content, OPTION and TRACE methods for the context.
  * The following initParameters are supported, these can be set either
  * on the servlet itself or as ServletContext initParameters with a prefix
  * of org.eclipse.jetty.servlet.Default. :
- * <PRE>
+ * <pre>
  *  acceptRanges      If true, range requests and responses are
  *                    supported
  *
@@ -134,10 +141,7 @@
  *                    Other file extensions that signify that a file is gzip compressed. Eg ".svgz"
  *
  *
- * </PRE>
- *
- *
- *
+ * </pre>
  *
  */
 public class DefaultServlet extends HttpServlet implements ResourceFactory
@@ -146,7 +150,7 @@
 
     private static final long serialVersionUID = 4930458713846881193L;
     
-    private static final CachedHttpField ACCEPT_RANGES = new CachedHttpField(HttpHeader.ACCEPT_RANGES, "bytes");
+    private static final PreEncodedHttpField ACCEPT_RANGES = new PreEncodedHttpField(HttpHeader.ACCEPT_RANGES, "bytes");
     
     private ServletContext _servletContext;
     private ContextHandler _contextHandler;
@@ -162,6 +166,7 @@
 
     private Resource _resourceBase;
     private ResourceCache _cache;
+    private HttpContent.Factory _contentFactory;
 
     private MimeTypes _mimeTypes;
     private String[] _welcomes;
@@ -243,8 +248,8 @@
 
         String cc=getInitParameter("cacheControl");
         if (cc!=null)
-            _cacheControl=new CachedHttpField(HttpHeader.CACHE_CONTROL, cc);
-        
+            _cacheControl=new PreEncodedHttpField(HttpHeader.CACHE_CONTROL, cc);
+
         String resourceCache = getInitParameter("resourceCache");
         int max_cache_size=getInitInt("maxCacheSize", -2);
         int max_cached_file_size=getInitInt("maxCachedFileSize", -2);
@@ -258,23 +263,23 @@
             _cache=(ResourceCache)_servletContext.getAttribute(resourceCache);
 
             if (LOG.isDebugEnabled())
-                LOG.debug("Cache {}={}",resourceCache,_cache);
+                LOG.debug("Cache {}={}",resourceCache,_contentFactory);
         }
 
         _etags = getInitBoolean("etags",_etags);
-        
+
         try
         {
             if (_cache==null && (max_cached_files!=-2 || max_cache_size!=-2 || max_cached_file_size!=-2))
             {
-                _cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer,_etags);
-
+                _cache = new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer,_etags,_gzip);
                 if (max_cache_size>=0)
                     _cache.setMaxCacheSize(max_cache_size);
                 if (max_cached_file_size>=-1)
                     _cache.setMaxCachedFileSize(max_cached_file_size);
                 if (max_cached_files>=-1)
                     _cache.setMaxCachedFiles(max_cached_files);
+                _servletContext.setAttribute(resourceCache==null?"resourceCache":resourceCache,_cache);
             }
         }
         catch (Exception e)
@@ -282,37 +287,45 @@
             LOG.warn(Log.EXCEPTION,e);
             throw new UnavailableException(e.toString());
         }
+
+        if (_cache!=null)
+            _contentFactory=_cache;
+        else
+        {
+            _contentFactory=new ResourceContentFactory(this,_mimeTypes,_gzip);
+            if (resourceCache!=null)
+                _servletContext.setAttribute(resourceCache,_contentFactory);
+        }
         
-       _gzipEquivalentFileExtensions = new ArrayList<String>();
-       String otherGzipExtensions = getInitParameter("otherGzipFileExtensions");
-       if (otherGzipExtensions != null)
-       {
-           //comma separated list
-           StringTokenizer tok = new StringTokenizer(otherGzipExtensions,",",false);
-           while (tok.hasMoreTokens())
-           {
-               String s = tok.nextToken().trim();
-               _gzipEquivalentFileExtensions.add((s.charAt(0)=='.'?s:"."+s));
-           }
-       }
-       else
-       {
-           //.svgz files are gzipped svg files and must be served with Content-Encoding:gzip
-           _gzipEquivalentFileExtensions.add(".svgz");   
-       }
+        _gzipEquivalentFileExtensions = new ArrayList<String>();
+        String otherGzipExtensions = getInitParameter("otherGzipFileExtensions");
+        if (otherGzipExtensions != null)
+        {
+            //comma separated list
+            StringTokenizer tok = new StringTokenizer(otherGzipExtensions,",",false);
+            while (tok.hasMoreTokens())
+            {
+                String s = tok.nextToken().trim();
+                _gzipEquivalentFileExtensions.add((s.charAt(0)=='.'?s:"."+s));
+            }
+        }
+        else
+        {
+            //.svgz files are gzipped svg files and must be served with Content-Encoding:gzip
+            _gzipEquivalentFileExtensions.add(".svgz");   
+        }
 
-       _servletHandler= _contextHandler.getChildHandlerByClass(ServletHandler.class);
-       for (ServletHolder h :_servletHandler.getServlets())
-           if (h.getServletInstance()==this)
-               _defaultHolder=h;
+        _servletHandler= _contextHandler.getChildHandlerByClass(ServletHandler.class);
+        for (ServletHolder h :_servletHandler.getServlets())
+            if (h.getServletInstance()==this)
+                _defaultHolder=h;
 
-
-       if (LOG.isDebugEnabled())
-           LOG.debug("resource base = "+_resourceBase);
+        if (LOG.isDebugEnabled())
+            LOG.debug("resource base = "+_resourceBase);
     }
 
     /**
-     * Compute the field _contextHandler.<br/>
+     * Compute the field _contextHandler.<br>
      * In the case where the DefaultServlet is deployed on the HttpService it is likely that
      * this method needs to be overwritten to unwrap the ServletContext facade until we reach
      * the original jetty's ContextHandler.
@@ -423,8 +436,8 @@
         String servletPath=null;
         String pathInfo=null;
         Enumeration<String> reqRanges = null;
-        Boolean included =request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI)!=null;
-        if (included!=null && included.booleanValue())
+        boolean included =request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI)!=null;
+        if (included)
         {
             servletPath=(String)request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
             pathInfo=(String)request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
@@ -436,7 +449,6 @@
         }
         else
         {
-            included = Boolean.FALSE;
             servletPath = _pathInfoOnly?"/":request.getServletPath();
             pathInfo = request.getPathInfo();
 
@@ -448,155 +460,72 @@
 
         String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
         boolean endsWithSlash=(pathInfo==null?request.getServletPath():pathInfo).endsWith(URIUtil.SLASH);
-
-
-        // Find the resource and content
-        Resource resource=null;
+        boolean gzippable=_gzip && !endsWithSlash && !included && reqRanges==null;
+        
         HttpContent content=null;
-        boolean close_content=true;
+        boolean release_content=true;
         try
         {
-            // is gzip enabled?
-            String pathInContextGz=null;
-            boolean gzip=false;
-            if (!included.booleanValue() && _gzip && reqRanges==null && !endsWithSlash )
-            {
-                // Look for a gzip resource
-                pathInContextGz=pathInContext+".gz";
-                if (_cache==null)
-                    resource=getResource(pathInContextGz);
-                else
-                {
-                    content=_cache.lookup(pathInContextGz);
-                    resource=(content==null)?null:content.getResource();
-                }
-
-                // Does a gzip resource exist?
-                if (resource!=null && resource.exists() && !resource.isDirectory())
-                {
-                    // Tell caches that response may vary by accept-encoding
-                    response.addHeader(HttpHeader.VARY.asString(),HttpHeader.ACCEPT_ENCODING.asString());
-                    
-                    // Does the client accept gzip?
-                    String accept=request.getHeader(HttpHeader.ACCEPT_ENCODING.asString());
-                    if (accept!=null && accept.indexOf("gzip")>=0)
-                        gzip=true;
-                }
-            }
-
-            // find resource
-            if (!gzip)
-            {
-                if (_cache==null)
-                    resource=getResource(pathInContext);
-                else
-                {
-                    content=_cache.lookup(pathInContext);
-                    resource=content==null?null:content.getResource();
-                }
-            }
-
+            // Find the content
+            content=_contentFactory.getContent(pathInContext,response.getBufferSize());
             if (LOG.isDebugEnabled())
-                LOG.debug(String.format("uri=%s, resource=%s, content=%s",request.getRequestURI(),resource,content));
-
-            // Handle resource
-            if (resource==null || !resource.exists())
+                LOG.info("content={}",content);
+            
+            // Not found?
+            if (content==null || !content.getResource().exists())
             {
                 if (included)
                     throw new FileNotFoundException("!" + pathInContext);
                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
+                return;
             }
-            else if (!resource.isDirectory())
+            
+            // Directory?
+            if (content.getResource().isDirectory())
             {
-                if (endsWithSlash && pathInContext.length()>1)
-                {
-                    String q=request.getQueryString();
-                    pathInContext=pathInContext.substring(0,pathInContext.length()-1);
-                    if (q!=null&&q.length()!=0)
-                        pathInContext+="?"+q;
-                    response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(_servletContext.getContextPath(),pathInContext)));
-                }
-                else
-                {
-                    // ensure we have content
-                    if (content==null)
-                        content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize(),_etags);
-
-                    if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
-                    {
-                        if (gzip || isGzippedContent(pathInContext))
-                        {
-                            response.setHeader(HttpHeader.CONTENT_ENCODING.asString(),"gzip");
-                            String mt=_servletContext.getMimeType(pathInContext);
-                            if (mt!=null)
-                                response.setContentType(mt);
-                        }
-                        close_content=sendData(request,response,included.booleanValue(),resource,content,reqRanges);
-                    }
-                }
+                sendWelcome(content,pathInContext,endsWithSlash,included,request,response);
+                return;
             }
-            else
+            
+            // Strip slash?
+            if (endsWithSlash && pathInContext.length()>1)
             {
-                String welcome=null;
-
-                if (!endsWithSlash || (pathInContext.length()==1 && request.getAttribute("org.eclipse.jetty.server.nullPathInfo")!=null))
-                {
-                    StringBuffer buf=request.getRequestURL();
-                    synchronized(buf)
-                    {
-                        int param=buf.lastIndexOf(";");
-                        if (param<0)
-                            buf.append('/');
-                        else
-                            buf.insert(param,'/');
-                        String q=request.getQueryString();
-                        if (q!=null&&q.length()!=0)
-                        {
-                            buf.append('?');
-                            buf.append(q);
-                        }
-                        response.setContentLength(0);
-                        response.sendRedirect(response.encodeRedirectURL(buf.toString()));
-                    }
-                }
-                // else look for a welcome file
-                else if (null!=(welcome=getWelcomeFile(pathInContext)))
+                String q=request.getQueryString();
+                pathInContext=pathInContext.substring(0,pathInContext.length()-1);
+                if (q!=null&&q.length()!=0)
+                    pathInContext+="?"+q;
+                response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(_servletContext.getContextPath(),pathInContext)));
+                return;
+            }
+            
+            // Conditional response?
+            if (!included && !passConditionalHeaders(request,response,content))
+                return;
+                
+            // Gzip?
+            HttpContent gzip_content = gzippable?content.getGzipContent():null;
+            if (gzip_content!=null)
+            {
+                // Tell caches that response may vary by accept-encoding
+                response.addHeader(HttpHeader.VARY.asString(),HttpHeader.ACCEPT_ENCODING.asString());
+                
+                // Does the client accept gzip?
+                String accept=request.getHeader(HttpHeader.ACCEPT_ENCODING.asString());
+                if (accept!=null && accept.indexOf("gzip")>=0)
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("welcome={}",welcome);
-                    if (_redirectWelcome)
-                    {
-                        // Redirect to the index
-                        response.setContentLength(0);
-                        String q=request.getQueryString();
-                        if (q!=null&&q.length()!=0)
-                            response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)+"?"+q));
-                        else
-                            response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)));
-                    }
-                    else
-                    {
-                        // Forward to the index
-                        RequestDispatcher dispatcher=request.getRequestDispatcher(welcome);
-                        if (dispatcher!=null)
-                        {
-                            if (included.booleanValue())
-                                dispatcher.include(request,response);
-                            else
-                            {
-                                request.setAttribute("org.eclipse.jetty.server.welcome",welcome);
-                                dispatcher.forward(request,response);
-                            }
-                        }
-                    }
-                }
-                else
-                {
-                    content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),_etags);
-                    if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
-                        sendDirectory(request,response,resource,pathInContext);
+                        LOG.debug("gzip={}",gzip_content);
+                    content=gzip_content;
                 }
             }
+
+            // TODO this should be done by HttpContent#getContentEncoding
+            if (isGzippedContent(pathInContext))
+                response.setHeader(HttpHeader.CONTENT_ENCODING.asString(),"gzip");
+                
+            // Send the data
+            release_content=sendData(request,response,included,content,reqRanges);
+            
         }
         catch(IllegalArgumentException e)
         {
@@ -606,21 +535,80 @@
         }
         finally
         {
-            if (close_content)
+            if (release_content)
             {
                 if (content!=null)
                     content.release();
-                else if (resource!=null)
-                    resource.close();
             }
         }
 
     }
 
-    /**
-     * @param resource
-     * @return
-     */
+    protected void sendWelcome(HttpContent content, String pathInContext, boolean endsWithSlash, boolean included, HttpServletRequest request, HttpServletResponse response)
+        throws ServletException, IOException
+    {                
+        // Redirect to directory
+        if (!endsWithSlash || (pathInContext.length()==1 && request.getAttribute("org.eclipse.jetty.server.nullPathInfo")!=null))
+        {
+            StringBuffer buf=request.getRequestURL();
+            synchronized(buf)
+            {
+                int param=buf.lastIndexOf(";");
+                if (param<0)
+                    buf.append('/');
+                else
+                    buf.insert(param,'/');
+                String q=request.getQueryString();
+                if (q!=null&&q.length()!=0)
+                {
+                    buf.append('?');
+                    buf.append(q);
+                }
+                response.setContentLength(0);
+                response.sendRedirect(response.encodeRedirectURL(buf.toString()));
+            }
+            return;
+        }
+        
+        // look for a welcome file
+        String welcome=getWelcomeFile(pathInContext);
+        if (welcome!=null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("welcome={}",welcome);
+            if (_redirectWelcome)
+            {
+                // Redirect to the index
+                response.setContentLength(0);
+                String q=request.getQueryString();
+                if (q!=null&&q.length()!=0)
+                    response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)+"?"+q));
+                else
+                    response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)));
+            }
+            else
+            {
+                // Forward to the index
+                RequestDispatcher dispatcher=request.getRequestDispatcher(welcome);
+                if (dispatcher!=null)
+                {
+                    if (included)
+                        dispatcher.include(request,response);
+                    else
+                    {
+                        request.setAttribute("org.eclipse.jetty.server.welcome",welcome);
+                        dispatcher.forward(request,response);
+                    }
+                }
+            }
+            return;
+        }
+         
+        if (included || passConditionalHeaders(request,response, content))
+            sendDirectory(request,response,content.getResource(),pathInContext);
+    }
+
+    /* ------------------------------------------------------------ */
     protected boolean isGzippedContent(String path)
     {
         if (path == null) return false;
@@ -704,26 +692,67 @@
     /* ------------------------------------------------------------ */
     /* Check modification date headers.
      */
-    protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, Resource resource, HttpContent content)
+    protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, HttpContent content)
     throws IOException
     {
         try
         {
+            String ifm=null;
+            String ifnm=null;
+            String ifms=null;
+            long ifums=-1;
+            
+            if (request instanceof Request)
+            {
+                // Find multiple fields by iteration as an optimization 
+                HttpFields fields = ((Request)request).getHttpFields();
+                for (int i=fields.size();i-->0;)
+                {
+                    HttpField field=fields.getField(i);
+                    if (field.getHeader() != null)
+                    {
+                        switch (field.getHeader())
+                        {
+                            case IF_MATCH:
+                                ifm=field.getValue();
+                                break;
+                            case IF_NONE_MATCH:
+                                ifnm=field.getValue();
+                                break;
+                            case IF_MODIFIED_SINCE:
+                                ifms=field.getValue();
+                                break;
+                            case IF_UNMODIFIED_SINCE:
+                                ifums=DateParser.parseDate(field.getValue());
+                                break;
+                            default:
+                        }
+                    }
+                }
+            }
+            else
+            {
+                ifm=request.getHeader(HttpHeader.IF_MATCH.asString());
+                ifnm=request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
+                ifms=request.getHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
+                ifums=request.getDateHeader(HttpHeader.IF_UNMODIFIED_SINCE.asString());
+            }
+            
             if (!HttpMethod.HEAD.is(request.getMethod()))
             {
                 if (_etags)
                 {
-                    String ifm=request.getHeader(HttpHeader.IF_MATCH.asString());
+                    String etag=content.getETagValue();
                     if (ifm!=null)
                     {
                         boolean match=false;
-                        if (content.getETag()!=null)
+                        if (etag!=null)
                         {
                             QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifm,", ",false,true);
                             while (!match && quoted.hasMoreTokens())
                             {
                                 String tag = quoted.nextToken();
-                                if (content.getETag().equals(tag))
+                                if (etag.equals(tag) || tag.endsWith(ETAG_GZIP_QUOTE) && etag.equals(removeGzipFromETag(tag)))
                                     match=true;
                             }
                         }
@@ -735,34 +764,25 @@
                         }
                     }
                     
-                    String if_non_match_etag=request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
-                    if (if_non_match_etag!=null && content.getETag()!=null)
+                    if (ifnm!=null && etag!=null)
                     {
-                        // Look for GzipFiltered version of etag
-                        if (content.getETag().equals(request.getAttribute("o.e.j.s.GzipFilter.ETag")))
+                        // Handle special case of exact match OR gzip exact match
+                        if (etag.equals(ifnm) || ifnm.endsWith(ETAG_GZIP_QUOTE) && ifnm.indexOf(',')<0 && etag.equals(removeGzipFromETag(etag)))
                         {
                             response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-                            response.setHeader(HttpHeader.ETAG.asString(),if_non_match_etag);
+                            response.setHeader(HttpHeader.ETAG.asString(),ifnm);
                             return false;
                         }
                         
-                        // Handle special case of exact match.
-                        if (content.getETag().equals(if_non_match_etag))
-                        {
-                            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-                            response.setHeader(HttpHeader.ETAG.asString(),content.getETag());
-                            return false;
-                        }
-
                         // Handle list of tags
-                        QuotedStringTokenizer quoted = new QuotedStringTokenizer(if_non_match_etag,", ",false,true);
+                        QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifnm,", ",false,true);
                         while (quoted.hasMoreTokens())
                         {
                             String tag = quoted.nextToken();
-                            if (content.getETag().equals(tag))
+                            if (etag.equals(tag) || tag.endsWith(ETAG_GZIP_QUOTE) && etag.equals(removeGzipFromETag(tag))) 
                             {
                                 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
-                                response.setHeader(HttpHeader.ETAG.asString(),content.getETag());
+                                response.setHeader(HttpHeader.ETAG.asString(),tag);
                                 return false;
                             }
                         }
@@ -773,34 +793,32 @@
                 }
                 
                 // Handle if modified since
-                String ifms=request.getHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
                 if (ifms!=null)
                 {
                     //Get jetty's Response impl
-                    String mdlm=content.getLastModified();
+                    String mdlm=content.getLastModifiedValue();
                     if (mdlm!=null && ifms.equals(mdlm))
                     {
                         response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                         if (_etags)
-                            response.setHeader(HttpHeader.ETAG.asString(),content.getETag());
+                            response.setHeader(HttpHeader.ETAG.asString(),content.getETagValue());
                         response.flushBuffer();
                         return false;
                     }
 
                     long ifmsl=request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
-                    if (ifmsl!=-1 && resource.lastModified()/1000 <= ifmsl/1000)
+                    if (ifmsl!=-1 && content.getResource().lastModified()/1000 <= ifmsl/1000)
                     { 
                         response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                         if (_etags)
-                            response.setHeader(HttpHeader.ETAG.asString(),content.getETag());
+                            response.setHeader(HttpHeader.ETAG.asString(),content.getETagValue());
                         response.flushBuffer();
                         return false;
                     }
                 }
 
                 // Parse the if[un]modified dates and compare to resource
-                long date=request.getDateHeader(HttpHeader.IF_UNMODIFIED_SINCE.asString());
-                if (date!=-1 && resource.lastModified()/1000 > date/1000)
+                if (ifums!=-1 && content.getResource().lastModified()/1000 > ifums/1000)
                 {
                     response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
                     return false;
@@ -853,8 +871,8 @@
             return;
         }
 
-        data=dir.getBytes("UTF-8");
-        response.setContentType("text/html; charset=UTF-8");
+        data=dir.getBytes("utf-8");
+        response.setContentType("text/html;charset=utf-8");
         response.setContentLength(data.length);
         response.getOutputStream().write(data);
     }
@@ -863,12 +881,11 @@
     protected boolean sendData(HttpServletRequest request,
             HttpServletResponse response,
             boolean include,
-            Resource resource,
             final HttpContent content,
             Enumeration<String> reqRanges)
     throws IOException
     {
-        final long content_length = (content==null)?resource.length():content.getContentLength();
+        final long content_length = content.getContentLengthValue();
         
         // Get the output stream (or writer)
         OutputStream out =null;
@@ -877,7 +894,7 @@
         {
             out = response.getOutputStream();
 
-            // has a filter already written to the response?
+            // has something already written to the response?
             written = out instanceof HttpOutput
                 ? ((HttpOutput)out).isWritten()
                 : true;
@@ -896,31 +913,25 @@
             //  if there were no ranges, send entire entity
             if (include)
             {
-                resource.writeTo(out,0,content_length);
+                // write without headers
+                content.getResource().writeTo(out,0,content_length);
             }
             // else if we can't do a bypass write because of wrapping
-            else if (content==null || written || !(out instanceof HttpOutput))
+            else if (written || !(out instanceof HttpOutput))
             {
                 // write normally
-                writeHeaders(response,content,written?-1:content_length);
-                ByteBuffer buffer = (content==null)?null:content.getIndirectBuffer();
+                putHeaders(response,content,written?-1:0);
+                ByteBuffer buffer = content.getIndirectBuffer();
                 if (buffer!=null)
                     BufferUtil.writeTo(buffer,out);
                 else
-                    resource.writeTo(out,0,content_length);
+                    content.getResource().writeTo(out,0,content_length);
             }
             // else do a bypass write
             else
             {
                 // write the headers
-                if (response instanceof Response)
-                {
-                    Response r = (Response)response;
-                    writeOptionHeaders(r.getHttpFields());
-                    r.setHeaders(content);
-                }
-                else
-                    writeHeaders(response,content,content_length);
+                putHeaders(response,content,0);
 
                 // write the content asynchronously if supported
                 if (request.isAsyncSupported())
@@ -958,7 +969,6 @@
                 }
                 // otherwise write content blocking
                 ((HttpOutput)out).sendContent(content);
-                
             }
         }
         else
@@ -969,11 +979,11 @@
             //  if there are no satisfiable ranges, send 416 response
             if (ranges==null || ranges.size()==0)
             {
-                writeHeaders(response, content, content_length);
+                putHeaders(response,content,0);
                 response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                 response.setHeader(HttpHeader.CONTENT_RANGE.asString(),
                         InclusiveByteRange.to416HeaderRangeString(content_length));
-                resource.writeTo(out,0,content_length);
+                content.getResource().writeTo(out,0,content_length);
                 return true;
             }
 
@@ -983,13 +993,13 @@
             {
                 InclusiveByteRange singleSatisfiableRange = ranges.get(0);
                 long singleLength = singleSatisfiableRange.getSize(content_length);
-                writeHeaders(response,content,singleLength                     );
+                putHeaders(response,content,singleLength);
                 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                 if (!response.containsHeader(HttpHeader.DATE.asString()))
                     response.addDateHeader(HttpHeader.DATE.asString(),System.currentTimeMillis());
                 response.setHeader(HttpHeader.CONTENT_RANGE.asString(),
                         singleSatisfiableRange.toHeaderRangeString(content_length));
-                resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
+                content.getResource().writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
                 return true;
             }
 
@@ -997,8 +1007,8 @@
             //  216 response which does not require an overall
             //  content-length header
             //
-            writeHeaders(response,content,-1);
-            String mimetype=(content==null?null:content.getContentType());
+            putHeaders(response,content,-1);
+            String mimetype=(content==null?null:content.getContentTypeValue());
             if (mimetype==null)
                 LOG.warn("Unknown mimetype for "+request.getRequestURI());
             MultiPartOutputStream multi = new MultiPartOutputStream(out);
@@ -1016,7 +1026,7 @@
                 ctp = "multipart/byteranges; boundary=";
             response.setContentType(ctp+multi.getBoundary());
 
-            InputStream in=resource.getInputStream();
+            InputStream in=content.getResource().getInputStream();
             long pos=0;
 
             // calculate the content-length
@@ -1050,7 +1060,7 @@
                     if (start<pos)
                     {
                         in.close();
-                        in=resource.getInputStream();
+                        in=content.getResource().getInputStream();
                         pos=0;
                     }
                     if (pos<start)
@@ -1064,7 +1074,7 @@
                 }
                 else
                     // Handle cached resource
-                    (resource).writeTo(multi,start,size);
+                    content.getResource().writeTo(multi,start,size);
             }
             if (in!=null)
                 in.close();
@@ -1074,83 +1084,31 @@
     }
 
     /* ------------------------------------------------------------ */
-    protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
+    protected void putHeaders(HttpServletResponse response,HttpContent content, long contentLength)
     {
-        if (content == null)
-        {
-            // No content, then no headers to process
-            // This is possible during bypass write because of wrapping
-            // See .sendData() for more details.
-            return;
-        }
-        
-        if (content.getContentType()!=null && response.getContentType()==null)
-            response.setContentType(content.getContentType().toString());
-
         if (response instanceof Response)
         {
-            Response r=(Response)response;
-            HttpFields fields = r.getHttpFields();
+            Response r = (Response)response;
+            r.putHeaders(content,contentLength,_etags);
+            HttpFields f = r.getHttpFields();
+            if (_acceptRanges)
+                f.put(ACCEPT_RANGES);
 
-            if (content.getLastModified()!=null)
-                fields.put(HttpHeader.LAST_MODIFIED,content.getLastModified());
-            else if (content.getResource()!=null)
-            {
-                long lml=content.getResource().lastModified();
-                if (lml!=-1)
-                    fields.putDateField(HttpHeader.LAST_MODIFIED,lml);
-            }
-
-            if (count != -1)
-                r.setLongContentLength(count);
-
-            writeOptionHeaders(fields);
-            
-            if (_etags)
-                fields.put(HttpHeader.ETAG,content.getETag());
+            if (_cacheControl!=null)
+                f.put(_cacheControl);
         }
         else
         {
-            long lml=content.getResource().lastModified();
-            if (lml>=0)
-                response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),lml);
+            Response.putHeaders(response,content,contentLength,_etags);
+            if (_acceptRanges)
+                response.setHeader(ACCEPT_RANGES.getName(),ACCEPT_RANGES.getValue());
 
-            if (count != -1)
-            {
-                if (count<Integer.MAX_VALUE)
-                    response.setContentLength((int)count);
-                else
-                    response.setHeader(HttpHeader.CONTENT_LENGTH.asString(),Long.toString(count));
-            }
-
-            writeOptionHeaders(response);
-
-            if (_etags)
-                response.setHeader(HttpHeader.ETAG.asString(),content.getETag());
+            if (_cacheControl!=null)
+                response.setHeader(_cacheControl.getName(),_cacheControl.getValue());
         }
     }
 
     /* ------------------------------------------------------------ */
-    protected void writeOptionHeaders(HttpFields fields)
-    {
-        if (_acceptRanges)
-            fields.put(ACCEPT_RANGES);
-
-        if (_cacheControl!=null)
-            fields.put(_cacheControl);
-    }
-
-    /* ------------------------------------------------------------ */
-    protected void writeOptionHeaders(HttpServletResponse response)
-    {
-        if (_acceptRanges)
-            response.setHeader(HttpHeader.ACCEPT_RANGES.asString(),"bytes");
-
-        if (_cacheControl!=null)
-            response.setHeader(HttpHeader.CACHE_CONTROL.asString(),_cacheControl.getValue());
-    }
-
-    /* ------------------------------------------------------------ */
     /*
      * @see javax.servlet.Servlet#destroy()
      */
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java
index cb6210c..179e66d 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java
@@ -37,10 +37,6 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* --------------------------------------------------------------------- */
-/**
- *
- */
 public class FilterHolder extends Holder<Filter>
 {
     private static final Logger LOG = Log.getLogger(FilterHolder.class);
@@ -61,6 +57,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor
+     * @param source the holder source
      */
     public FilterHolder(Holder.Source source)
     {
@@ -69,6 +66,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor
+     * @param filter the filter class
      */
     public FilterHolder(Class<? extends Filter> filter)
     {
@@ -78,6 +76,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor for existing filter.
+     * @param filter the filter
      */
     public FilterHolder(Filter filter)
     {
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java
index 749928c..c6cedcb 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java
@@ -45,6 +45,8 @@
 
     /* ------------------------------------------------------------ */
     /** Dispatch type from name
+     * @param type the type name
+     * @return the dispatcher type
      */
     public static DispatcherType dispatch(String type)
     {
@@ -63,6 +65,8 @@
 
     /* ------------------------------------------------------------ */
     /** Dispatch type from name
+     * @param type the dispatcher type
+     * @return the type constant ({@link #REQUEST}, {@link #ASYNC}, {@link #FORWARD}, {@link #INCLUDE}, or {@link #ERROR})
      */
     public static int dispatch(DispatcherType type)
     {
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java
index 2c8fa7b..2f6cfe0 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java
@@ -42,7 +42,7 @@
  * 
  * Specialization of AbstractHolder for servlet-related classes that 
  * have init-params etc
- * 
+ * @param <T> the type of holder
  */
 @ManagedObject("Holder - a container for servlets and the like")
 public class Holder<T> extends BaseHolder<T>
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java
index 52d9bea..605c30d 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Invoker.java
@@ -34,7 +34,6 @@
 
 import org.eclipse.jetty.server.Dispatcher;
 import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
@@ -227,7 +226,7 @@
 
         if (holder!=null)
         {
-            final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
+            final Request baseRequest=Request.getBaseRequest(request);
             holder.handle(baseRequest,
                     new InvokedRequest(request,included,servlet,servlet_path,path_info),
                           response);
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
index 013ab5c..c5ffbd3 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java
@@ -35,6 +35,7 @@
 import javax.servlet.FilterRegistration;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.ServletException;
@@ -57,21 +58,25 @@
 import org.eclipse.jetty.server.handler.ErrorHandler;
 import org.eclipse.jetty.server.handler.HandlerCollection;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
 import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.BaseHolder.Source;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.DeprecationWarning;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.LifeCycle;
 
-
-/* ------------------------------------------------------------ */
-/** Servlet Context.
+/** 
+ * Servlet Context.
+ * <p>
  * This extension to the ContextHandler allows for
  * simple construction of a context with ServletHandler and optionally
- * session and security handlers, et.<pre>
+ * session and security handlers, et.
+ * <pre>
  *   new ServletContext("/context",Context.SESSIONS|Context.NO_SECURITY);
  * </pre>
- * <p/>
+ * <p>
  * This class should have been called ServletContext, but this would have
  * cause confusion with {@link ServletContext}.
  */
@@ -80,16 +85,18 @@
 {
     public final static int SESSIONS=1;
     public final static int SECURITY=2;
+    public final static int GZIP=4;
     public final static int NO_SESSIONS=0;
     public final static int NO_SECURITY=0;
     
     public interface ServletContainerInitializerCaller extends LifeCycle {};
 
-    protected final List<Decorator> _decorators= new ArrayList<>();
+    protected final DecoratedObjectFactory _objFactory;
     protected Class<? extends SecurityHandler> _defaultSecurityHandlerClass=org.eclipse.jetty.security.ConstraintSecurityHandler.class;
     protected SessionHandler _sessionHandler;
     protected SecurityHandler _securityHandler;
     protected ServletHandler _servletHandler;
+    protected GzipHandler _gzipHandler;
     protected int _options;
     protected JspConfigDescriptor _jspConfig;
 
@@ -135,6 +142,7 @@
         this(parent,contextPath,sessionHandler,securityHandler,servletHandler,errorHandler,0);
     }
     
+    /* ------------------------------------------------------------ */
     public ServletContextHandler(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler,int options)
     {
         super((ContextHandler.Context)null);
@@ -143,6 +151,9 @@
         _sessionHandler = sessionHandler;
         _securityHandler = securityHandler;
         _servletHandler = servletHandler;
+        
+        _objFactory = new DecoratedObjectFactory();
+        _objFactory.addDecorator(new DeprecationWarning());
 
         if (contextPath!=null)
             setContextPath(contextPath);
@@ -166,43 +177,90 @@
     {
         HandlerWrapper handler=this;
         
-        // Skip any injected handlers
-        while (handler.getHandler() instanceof HandlerWrapper)
-        {
-            HandlerWrapper wrapper = (HandlerWrapper)handler.getHandler();
-            if (wrapper instanceof SessionHandler ||
-                wrapper instanceof SecurityHandler ||
-                wrapper instanceof ServletHandler)
-                break;
-            handler=wrapper;
-        }
-        
+        // link session handler
         if (getSessionHandler()!=null)
         {
-            if (handler==this)
-                super.setHandler(_sessionHandler);
-            else
-                handler.setHandler(_sessionHandler);
+            
+            while (!(handler.getHandler() instanceof SessionHandler) && 
+                   !(handler.getHandler() instanceof SecurityHandler) && 
+                   !(handler.getHandler() instanceof GzipHandler) && 
+                   !(handler.getHandler() instanceof ServletHandler) && 
+                   handler.getHandler() instanceof HandlerWrapper)
+                handler=(HandlerWrapper)handler.getHandler();
+            
+            if (handler.getHandler()!=_sessionHandler)
+            {
+                if (handler== this)
+                    super.setHandler(_sessionHandler);
+                else
+                    handler.setHandler(_sessionHandler);
+            }
             handler=_sessionHandler;
         }
-
+        
+        // link security handler
         if (getSecurityHandler()!=null)
         {
-            if (handler==this)
-                super.setHandler(_securityHandler);
-            else
-                handler.setHandler(_securityHandler);
+            while (!(handler.getHandler() instanceof SecurityHandler) && 
+                   !(handler.getHandler() instanceof GzipHandler) && 
+                   !(handler.getHandler() instanceof ServletHandler) && 
+                   handler.getHandler() instanceof HandlerWrapper)
+                handler=(HandlerWrapper)handler.getHandler();
+
+            if (handler.getHandler()!=_securityHandler)
+            {
+                if (handler== this)
+                    super.setHandler(_securityHandler);
+                else
+                    handler.setHandler(_securityHandler);
+            }
             handler=_securityHandler;
         }
 
+        // link gzip handler
+        if (getGzipHandler()!=null)
+        {
+            while (!(handler.getHandler() instanceof GzipHandler) && 
+                   !(handler.getHandler() instanceof ServletHandler) && 
+                   handler.getHandler() instanceof HandlerWrapper)
+                handler=(HandlerWrapper)handler.getHandler();
+
+            if (handler.getHandler()!=_gzipHandler)
+            {
+                if (handler== this)
+                    super.setHandler(_gzipHandler);
+                else
+                    handler.setHandler(_gzipHandler);
+            }
+            handler=_gzipHandler;
+        }
+
+        
+        // link servlet handler
         if (getServletHandler()!=null)
         {
-            if (handler==this)
-                super.setHandler(_servletHandler);
-            else
-                handler.setHandler(_servletHandler);
+            while (!(handler.getHandler() instanceof ServletHandler) && 
+                   handler.getHandler() instanceof HandlerWrapper)
+                handler=(HandlerWrapper)handler.getHandler();
+
+            if (handler.getHandler()!=_servletHandler)
+            {
+                if (handler== this)
+                    super.setHandler(_servletHandler);
+                else
+                    handler.setHandler(_servletHandler);
+            }
             handler=_servletHandler;
-        } 
+        }
+        
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void doStart() throws Exception
+    {
+        getServletContext().setAttribute(DecoratedObjectFactory.ATTR, _objFactory);
+        super.doStart();
     }
     
     /* ------------------------------------------------------------ */
@@ -213,8 +271,7 @@
     protected void doStop() throws Exception
     {
         super.doStop();
-        if (_decorators != null)
-            _decorators.clear();
+        _objFactory.clear();
     }
 
     /* ------------------------------------------------------------ */
@@ -275,18 +332,13 @@
 
         if (_servletHandler != null)
         {
-            //Call decorators on all holders, and also on any EventListeners before
-            //decorators are called on any other classes (like servlets and filters)
-            for (int i=_decorators.size()-1;i>=0; i--)
+            // Call decorators on all holders, and also on any EventListeners before
+            // decorators are called on any other classes (like servlets and filters)
+            if(_servletHandler.getListeners() != null)
             {
-                Decorator decorator = _decorators.get(i);
-                //Do any decorations on the ListenerHolders AND the listener instances first up
-                if (_servletHandler.getListeners()!=null)
-                {
-                    for (ListenerHolder holder:_servletHandler.getListeners())
-                    {             
-                        decorator.decorate(holder.getListener());
-                    }
+                for (ListenerHolder holder:_servletHandler.getListeners())
+                {             
+                    _objFactory.decorate(holder.getListener());
                 }
             }
         }
@@ -297,6 +349,13 @@
         if (_servletHandler != null)
             _servletHandler.initialize();
     }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void stopContext() throws Exception
+    {
+        super.stopContext();
+    }
 
     /* ------------------------------------------------------------ */
     /**
@@ -336,7 +395,22 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a servlet.
+    /**
+     * @return Returns the gzipHandler.
+     */
+    @ManagedAttribute(value="context gzip handler", readonly=true)
+    public GzipHandler getGzipHandler()
+    {
+        if (_gzipHandler==null && (_options&GZIP)!=0 && !isStarted())
+            _gzipHandler=new GzipHandler();
+        return _gzipHandler;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Convenience method to add a servlet.
+     * @param className the servlet class name
+     * @param pathSpec the path spec to map servlet to
+     * @return the ServletHolder for the added servlet
      */
     public ServletHolder addServlet(String className,String pathSpec)
     {
@@ -344,7 +418,10 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a servlet.
+    /** Convenience method to add a servlet.
+     * @param servlet the servlet class
+     * @param pathSpec the path spec to map servlet to
+     * @return the ServletHolder for the added servlet
      */
     public ServletHolder addServlet(Class<? extends Servlet> servlet,String pathSpec)
     {
@@ -352,7 +429,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a servlet.
+    /** Convenience method to add a servlet.
+     * @param servlet the servlet holder
+     * @param pathSpec the path spec
      */
     public void addServlet(ServletHolder servlet,String pathSpec)
     {
@@ -360,7 +439,10 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a filter
+    /** Convenience method to add a filter
+     * @param holder the filter holder
+     * @param pathSpec the path spec
+     * @param dispatches the dispatcher types for this filter
      */
     public void addFilter(FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
@@ -368,7 +450,11 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** convenience method to add a filter
+    /** Convenience method to add a filter
+     * @param filterClass the filter class
+     * @param pathSpec the path spec
+     * @param dispatches the dispatcher types for this filter
+     * @return the FilterHolder that was created
      */
     public FilterHolder addFilter(Class<? extends Filter> filterClass,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
@@ -376,7 +462,11 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** convenience method to add a filter
+    /** Convenience method to add a filter
+     * @param filterClass the filter class name 
+     * @param pathSpec the path spec
+     * @param dispatches the dispatcher types for this filter
+     * @return the FilterHolder that was created
      */
     public FilterHolder addFilter(String filterClass,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
@@ -457,6 +547,23 @@
         super.callContextDestroyed(l, e);
     }
 
+    private boolean replaceHandler(Handler handler,Handler replace)
+    {
+        HandlerWrapper wrapper=this;
+        while(true)
+        {
+            if (wrapper.getHandler()==handler)
+            {
+                wrapper.setHandler(replace);
+                return true;
+            }
+            
+            if (!(wrapper.getHandler() instanceof HandlerWrapper))
+                return false;
+            wrapper = (HandlerWrapper)wrapper.getHandler();
+        }
+    }
+    
     /* ------------------------------------------------------------ */
     /**
      * @param sessionHandler The sessionHandler to set.
@@ -466,10 +573,17 @@
         if (isStarted())
             throw new IllegalStateException("STARTED");
 
+        Handler next=null;
         if (_sessionHandler!=null)
+        {
+            next=_sessionHandler.getHandler();
             _sessionHandler.setHandler(null);
+            replaceHandler(_sessionHandler,sessionHandler);
+        }
 
         _sessionHandler = sessionHandler;
+        if (next!=null && _sessionHandler.getHandler()==null)
+            _sessionHandler.setHandler(next);
         relinkHandlers();
     }
 
@@ -482,12 +596,44 @@
         if (isStarted())
             throw new IllegalStateException("STARTED");
 
+        Handler next=null;
         if (_securityHandler!=null)
+        {
+            next=_securityHandler.getHandler();
             _securityHandler.setHandler(null);
+            replaceHandler(_securityHandler,securityHandler);
+        }
+        
         _securityHandler = securityHandler;
+        if (next!=null && _securityHandler.getHandler()==null)
+            _securityHandler.setHandler(next);
         relinkHandlers();
     }
 
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param gzipHandler The {@link GzipHandler} to set on this context.
+     */
+    public void setGzipHandler(GzipHandler gzipHandler)
+    {
+        if (isStarted())
+            throw new IllegalStateException("STARTED");
+
+        Handler next=null;
+        if (_gzipHandler!=null)
+        {
+            next=_gzipHandler.getHandler();
+            _gzipHandler.setHandler(null);
+            replaceHandler(_gzipHandler,gzipHandler);
+        }
+        
+        _gzipHandler = gzipHandler;
+        if (next!=null && _gzipHandler.getHandler()==null)
+            _gzipHandler.setHandler(next);
+        relinkHandlers();
+    }
+    
     /* ------------------------------------------------------------ */
     /**
      * @param servletHandler The servletHandler to set.
@@ -502,29 +648,12 @@
         {
             next=_servletHandler.getHandler();
             _servletHandler.setHandler(null);
+            replaceHandler(_servletHandler,servletHandler);
         }
         _servletHandler = servletHandler;
+        if (next!=null && _servletHandler.getHandler()==null)
+            _servletHandler.setHandler(next);
         relinkHandlers();
-        _servletHandler.setHandler(next);
-    }
-    
-    /* ------------------------------------------------------------ */
-    @Override
-    public void setHandler(Handler handler)
-    {
-        if (handler instanceof ServletHandler)
-            setServletHandler((ServletHandler) handler);
-        else if (handler instanceof SessionHandler)
-            setSessionHandler((SessionHandler) handler);
-        else if (handler instanceof SecurityHandler)
-            setSecurityHandler((SecurityHandler)handler);
-        else if (handler == null || handler instanceof HandlerWrapper)
-        {
-            super.setHandler(handler);
-            relinkHandlers();
-        }
-        else
-            throw new IllegalArgumentException();
     }
     
     
@@ -551,47 +680,66 @@
         h.setHandler(handler);
         relinkHandlers();
     }
-
+    
     /* ------------------------------------------------------------ */
     /**
-     * @return The decorator list used to resource inject new Filters, Servlets and EventListeners
+     * The DecoratedObjectFactory for use by IoC containers (weld / spring / etc)
+     * 
+     * @return The DecoratedObjectFactory
      */
-    public List<Decorator> getDecorators()
+    public DecoratedObjectFactory getObjectFactory()
     {
-        return Collections.unmodifiableList(_decorators);
+        return _objFactory;
     }
 
     /* ------------------------------------------------------------ */
     /**
-     * @param decorators The lis of {@link Decorator}s
+     * @return The decorator list used to resource inject new Filters, Servlets and EventListeners
+     * @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
      */
+    @Deprecated
+    public List<Decorator> getDecorators()
+    {
+        List<Decorator> ret = new ArrayList<ServletContextHandler.Decorator>();
+        for (org.eclipse.jetty.util.Decorator decorator : _objFactory)
+        {
+            ret.add(new LegacyDecorator(decorator));
+        }
+        return Collections.unmodifiableList(ret);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param decorators The list of {@link Decorator}s
+     * @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
+     */
+    @Deprecated
     public void setDecorators(List<Decorator> decorators)
     {
-        _decorators.clear();
-        _decorators.addAll(decorators);
+        _objFactory.setDecorators(decorators);
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @param decorator The decorator to add
+     * @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
      */
+    @Deprecated
     public void addDecorator(Decorator decorator)
     {
-        _decorators.add(decorator);
+        _objFactory.addDecorator(decorator);
     }
-
+    
     /* ------------------------------------------------------------ */
     void destroyServlet(Servlet servlet)
     {
-        for (Decorator decorator : _decorators)
-            decorator.destroy(servlet);
+        _objFactory.destroy(servlet);
     }
 
     /* ------------------------------------------------------------ */
     void destroyFilter(Filter filter)
     {
-        for (Decorator decorator : _decorators)
-            decorator.destroy(filter);
+        _objFactory.destroy(filter);
     }
 
     /* ------------------------------------------------------------ */
@@ -1144,11 +1292,7 @@
             try
             {
                 T f = createInstance(c);
-                for (int i=_decorators.size()-1; i>=0; i--)
-                {
-                    Decorator decorator = _decorators.get(i);
-                    f=decorator.decorate(f);
-                }
+                f = _objFactory.decorate(f);
                 return f;
             }
             catch (Exception e)
@@ -1164,11 +1308,7 @@
             try
             {
                 T s = createInstance(c);
-                for (int i=_decorators.size()-1; i>=0; i--)
-                {
-                    Decorator decorator = _decorators.get(i);
-                    s=decorator.decorate(s);
-                }
+                s = _objFactory.decorate(s);
                 return s;
             }
             catch (Exception e)
@@ -1311,11 +1451,7 @@
             try
             {
                 T l = createInstance(clazz);
-                for (int i=_decorators.size()-1; i>=0; i--)
-                {
-                    Decorator decorator = _decorators.get(i);
-                    l=decorator.decorate(l);
-                }
+                l = _objFactory.decorate(l);
                 return l;
             }            
             catch (Exception e)
@@ -1355,11 +1491,39 @@
 
 
     /* ------------------------------------------------------------ */
-    /** Interface to decorate loaded classes.
+    /** 
+     * Legacy Interface to decorate loaded classes.
+     * <p>
+     * Left for backwards compatibility with Weld / CDI
+     * @deprecated use new {@link org.eclipse.jetty.util.Decorator} 
      */
-    public interface Decorator
+    @Deprecated
+    public interface Decorator extends org.eclipse.jetty.util.Decorator
     {
-        <T> T decorate (T o);
-        void destroy (Object o);
+    }
+    
+    /**
+     * Implementation of the legacy interface to decorate loaded classes.
+     */
+    private static class LegacyDecorator implements Decorator
+    {
+        private org.eclipse.jetty.util.Decorator decorator;
+        
+        public LegacyDecorator(org.eclipse.jetty.util.Decorator decorator)
+        {
+            this.decorator = decorator;
+        }
+
+        @Override
+        public <T> T decorate(T o)
+        {
+            return decorator.decorate(o);
+        }
+
+        @Override
+        public void destroy(Object o)
+        {
+            decorator.destroy(o);
+        }
     }
 }
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
index d5b2add..4210aea 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java
@@ -57,7 +57,6 @@
 import org.eclipse.jetty.io.RuntimeIOException;
 import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.SecurityHandler;
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.QuietServletException;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.ServletRequestHttpWrapper;
@@ -77,8 +76,9 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* --------------------------------------------------------------------- */
-/** Servlet HttpHandler.
+/** 
+ * Servlet HttpHandler.
+ * <p>
  * This handler maps requests to servlets that implement the
  * javax.servlet.http.HttpServlet API.
  * <P>
@@ -89,10 +89,6 @@
  * Unless run as part of a {@link ServletContextHandler} or derivative, the {@link #initialize()}
  * method must be called manually after start().
  */
-
-/* ------------------------------------------------------------ */
-/**
- */
 @ManagedObject("Servlet Handler")
 public class ServletHandler extends ScopedHandler
 {
@@ -146,7 +142,7 @@
         throws Exception
     {
         ContextHandler.Context context=ContextHandler.getCurrentContext();
-        _servletContext=context==null?new ContextHandler.NoContext():context;
+        _servletContext=context==null?new ContextHandler.StaticContext():context;
         _contextHandler=(ServletContextHandler)(context==null?null:context.getContextHandler());
 
         if (_contextHandler!=null)
@@ -410,8 +406,8 @@
     /**
      * Get the ServletMapping matching the path
      * 
-     * @param pathSpec
-     * @return
+     * @param pathSpec the path spec
+     * @return the servlet mapping for the path spec (or null if not found)
      */
     public ServletMapping getServletMapping(String pathSpec)
     {
@@ -593,11 +589,18 @@
         }
         catch(RuntimeIOException e)
         {
+            if (e.getCause() instanceof IOException)
+            {
+                LOG.debug(e);
+                throw (IOException)e.getCause();
+            }
             throw e;
         }
         catch(Exception e)
         {
-            if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
+            //TODO, can we let all error handling fall through to HttpChannel?
+            
+            if (baseRequest.isAsyncStarted() || !(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
             {
                 if (e instanceof IOException)
                     throw (IOException)e;
@@ -835,6 +838,7 @@
 
     /* ------------------------------------------------------------ */
     /** Initialize filters and load-on-startup servlets.
+     * @throws Exception if unable to initialize
      */
     public void initialize()
         throws Exception
@@ -909,7 +913,7 @@
     
     /* ------------------------------------------------------------ */
     /** Add a holder for a listener
-     * @param filter
+     * @param listener the listener for the holder
      */
     public void addListener (ListenerHolder listener)
     {
@@ -943,7 +947,9 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * see also newServletHolder(Class)
+     * Add a new servlet holder
+     * @param source the holder source
+     * @return the servlet holder
      */
     public ServletHolder newServletHolder(Holder.Source source)
     {
@@ -952,6 +958,8 @@
 
     /* ------------------------------------------------------------ */
     /** Convenience method to add a servlet.
+     * @param className the class name
+     * @param pathSpec the path spec
      * @return The servlet holder.
      */
     public ServletHolder addServletWithMapping (String className,String pathSpec)
@@ -963,7 +971,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a servlet.
+    /** Convenience method to add a servlet.
+     * @param servlet the servlet class
+     * @param pathSpec the path spec
      * @return The servlet holder.
      */
     public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
@@ -976,7 +986,7 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** conveniance method to add a servlet.
+    /** Convenience method to add a servlet.
      * @param servlet servlet holder to add
      * @param pathSpec servlet mappings for the servletHolder
      */
@@ -1006,8 +1016,9 @@
 
 
     /* ------------------------------------------------------------ */
-    /**Convenience method to add a pre-constructed ServletHolder.
-     * @param holder
+    /**
+     * Convenience method to add a pre-constructed ServletHolder.
+     * @param holder the servlet holder
      */
     public void addServlet(ServletHolder holder)
     {
@@ -1015,8 +1026,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convenience method to add a pre-constructed ServletMapping.
-     * @param mapping
+    /** 
+     * Convenience method to add a pre-constructed ServletMapping.
+     * @param mapping the servlet mapping
      */
     public void addServletMapping (ServletMapping mapping)
     {
@@ -1182,13 +1194,15 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convenience method to add a filter with a mapping
-     * @param className
-     * @param pathSpec
-     * @param dispatches
+    /** 
+     * Convenience method to add a filter with a mapping
+     * @param className the filter class name
+     * @param pathSpec the path spec
+     * @param dispatches the dispatcher types for this filter
      * @return the filter holder created
      * @deprecated use {@link #addFilterWithMapping(Class, String, EnumSet)} instead
      */
+    @Deprecated
     public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
     {
         return addFilterWithMapping(className, pathSpec, dispatches);
@@ -1196,9 +1210,9 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * convenience method to add a filter and mapping
-     * @param filter
-     * @param filterMapping
+     * Convenience method to add a filter and mapping
+     * @param filter the filter holder
+     * @param filterMapping the filter mapping
      */
     public void addFilter (FilterHolder filter, FilterMapping filterMapping)
     {
@@ -1209,8 +1223,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convenience method to add a preconstructed FilterHolder
-     * @param filter
+    /** 
+     * Convenience method to add a preconstructed FilterHolder
+     * @param filter the filter holder
      */
     public void addFilter (FilterHolder filter)
     {
@@ -1219,8 +1234,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convenience method to add a preconstructed FilterMapping
-     * @param mapping
+    /** 
+     * Convenience method to add a preconstructed FilterMapping
+     * @param mapping the filter mapping
      */
     public void addFilterMapping (FilterMapping mapping)
     {
@@ -1263,15 +1279,15 @@
     
 
     /* ------------------------------------------------------------ */
-    /** Convenience method to add a preconstructed FilterMapping
-     * @param mapping
+    /** 
+     * Convenience method to add a preconstructed FilterMapping
+     * @param mapping the filter mapping
      */
     public void prependFilterMapping (FilterMapping mapping)
     {
         if (mapping != null)
         {
-            Source source = mapping.getFilterHolder().getSource();
-            
+            Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
             FilterMapping[] mappings = getFilterMappings();
             if (mappings==null || mappings.length==0)
             {
@@ -1322,7 +1338,7 @@
      * @param mapping the FilterMapping to add
      * @param pos the position in the existing arry at which to add it
      * @param before if true, insert before  pos, if false insert after it
-     * @return
+     * @return the new FilterMappings post-insert
      */
     protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
     {
@@ -1632,7 +1648,7 @@
         public void doFilter(ServletRequest request, ServletResponse response)
             throws IOException, ServletException
         {
-            final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
+            final Request baseRequest=Request.getBaseRequest(request);
 
             // pass to next filter
             if (_filterHolder!=null)
@@ -1734,7 +1750,7 @@
             // Call servlet
             HttpServletRequest srequest = (HttpServletRequest)request;
             if (_servletHolder == null)
-                notFound((request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(), srequest, (HttpServletResponse)response);
+                notFound(Request.getBaseRequest(request), srequest, (HttpServletResponse)response);
             else
             {
                 if (LOG.isDebugEnabled())
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
index 73e1ccf..bfcb271 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
@@ -33,6 +33,7 @@
 import java.util.Stack;
 
 import javax.servlet.MultipartConfigElement;
+import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
@@ -46,6 +47,7 @@
 
 import org.eclipse.jetty.security.IdentityService;
 import org.eclipse.jetty.security.RunAsToken;
+import org.eclipse.jetty.server.MultiPartCleanerListener;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
@@ -55,17 +57,13 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-
-
-
-/* --------------------------------------------------------------------- */
-/** Servlet Instance and Context Holder.
+/**
+ * Servlet Instance and Context Holder.
+ * <p>
  * Holds the name, params and some state of a javax.servlet.Servlet
  * instance. It implements the ServletConfig interface.
  * This class will organise the loading of the servlet when needed or
  * requested.
- *
- *
  */
 @ManagedObject("Servlet Holder")
 public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope, Comparable<ServletHolder>
@@ -90,11 +88,11 @@
     private transient boolean _enabled = true;
     private transient UnavailableException _unavailableEx;
 
-    public static final String GLASSFISH_SENTINEL_CLASS = "org.glassfish.jsp.api.ResourceInjector";
+
     public static final String APACHE_SENTINEL_CLASS = "org.apache.tomcat.InstanceManager";
     public static final  String JSP_GENERATED_PACKAGE_NAME = "org.eclipse.jetty.servlet.jspPackagePrefix";
     public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap();
-    public static enum JspContainer {GLASSFISH, APACHE, OTHER}; 
+    public static enum JspContainer {APACHE, OTHER};
 
     /* ---------------------------------------------------------------- */
     /** Constructor .
@@ -106,6 +104,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor .
+     * @param creator the holder source
      */
     public ServletHolder(Holder.Source creator)
     {
@@ -114,6 +113,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor for existing servlet.
+     * @param servlet the servlet
      */
     public ServletHolder(Servlet servlet)
     {
@@ -123,6 +123,8 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor for servlet class.
+     * @param name the name of the servlet
+     * @param servlet the servlet class
      */
     public ServletHolder(String name, Class<? extends Servlet> servlet)
     {
@@ -133,6 +135,8 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor for servlet class.
+     * @param name the servlet name
+     * @param servlet the servlet
      */
     public ServletHolder(String name, Servlet servlet)
     {
@@ -143,6 +147,7 @@
 
     /* ---------------------------------------------------------------- */
     /** Constructor for servlet class.
+     * @param servlet the servlet class
      */
     public ServletHolder(Class<? extends Servlet> servlet)
     {
@@ -180,10 +185,13 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Set the initialize order.
-     * Holders with order<0, are initialized on use. Those with
-     * order>=0 are initialized in increasing order when the handler
+    /**
+     * Set the initialize order.
+     * <p>
+     * Holders with order&lt;0, are initialized on use. Those with
+     * order&gt;=0 are initialized in increasing order when the handler
      * is started.
+     * @param order the servlet init order
      */
     public void setInitOrder(int order)
     {
@@ -192,22 +200,37 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Comparitor by init order.
+    /**
+     * Comparator by init order.
      */
     @Override
     public int compareTo(ServletHolder sh)
     {
         if (sh==this)
             return 0;
+
         if (sh._initOrder<_initOrder)
             return 1;
+
         if (sh._initOrder>_initOrder)
             return -1;
 
-        int c=(_className!=null && sh._className!=null)?_className.compareTo(sh._className):0;
+        // consider _className, need to position properly when one is configured but not the other
+        int c;
+        if (_className==null && sh._className==null)
+            c=0;
+        else if (_className==null)
+            c=-1;
+        else if (sh._className==null)
+            c=1;
+        else
+            c=_className.compareTo(sh._className);
+
+        // if _initOrder and _className are the same, consider the _name
         if (c==0)
             c=_name.compareTo(sh._name);
-            return c;
+
+        return c;
     }
 
     /* ------------------------------------------------------------ */
@@ -280,7 +303,7 @@
         _enabled = enabled;
     }
 
-    
+
     /* ------------------------------------------------------------ */
     public void doStart()
         throws Exception
@@ -288,7 +311,7 @@
         _unavailable=0;
         if (!_enabled)
             return;
-        
+
         // Handle JSP file forced paths
         if (_forcedPath != null)
         {
@@ -305,7 +328,7 @@
                 setClassName(jsp.getClassName());
             }
             else
-            { 
+            {
                 if (getClassName() == null)
                 {
                     // Look for normal JSP servlet
@@ -326,12 +349,12 @@
                         //container does not support startup precompilation, it will be compiled at runtime when handling a request for this jsp.
                         //See also adaptForcedPathToJspContainer
                         setInitParameter("jspFile", _forcedPath);
-                    }                       
+                    }
                 }
             }
         }
-        
-        
+
+
         //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup.
         try
         {
@@ -380,8 +403,8 @@
             _servlet = new SingleThreadedWrapper();
 
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     @Override
     public void initialize ()
@@ -406,8 +429,8 @@
         }
         _initialized = true;
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     public void doStop()
         throws Exception
@@ -455,6 +478,7 @@
     /* ------------------------------------------------------------ */
     /** Get the servlet.
      * @return The servlet
+     * @throws ServletException if unable to init the servlet on first use
      */
     public synchronized Servlet getServlet()
         throws ServletException
@@ -485,7 +509,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Check to ensure class of servlet is acceptable.
-     * @throws UnavailableException
+     * @throws UnavailableException if Servlet class is not of type {@link javax.servlet.Servlet}
      */
     public void checkServletType ()
         throws UnavailableException
@@ -515,22 +539,22 @@
 
         return isStarted()&& _unavailable==0;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * Check if there is a javax.servlet.annotation.ServletSecurity
      * annotation on the servlet class. If there is, then we force
-     * it to be loaded on startup, because all of the security 
+     * it to be loaded on startup, because all of the security
      * constraints must be calculated as the container starts.
-     * 
+     *
      */
     private void checkInitOnStartup()
     {
         if (_class==null)
             return;
-        
+
         if ((_class.getAnnotation(javax.servlet.annotation.ServletSecurity.class) != null) && !_initOnStartup)
-            setInitOrder(Integer.MAX_VALUE);    
+            setInitOrder(Integer.MAX_VALUE);
     }
 
     /* ------------------------------------------------------------ */
@@ -588,8 +612,8 @@
                 _servlet=newInstance();
             if (_config==null)
                 _config=new Config();
-            
-          
+
+
 
             // Handle run as
             if (_identityService!=null)
@@ -647,18 +671,15 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @throws Exception
+     * @throws Exception if unable to init the JSP Servlet
      */
     protected void initJspServlet () throws Exception
     {
         ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
-            
+
         /* Set the webapp's classpath for Jasper */
         ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
 
-        /* Set the system classpath for Jasper */
-        setInitParameter("com.sun.appserv.jsp.classpath", Loader.getClassPath(ch.getClassLoader().getParent()));
-
         /* Set up other classpath attribute */
         if ("?".equals(getInitParameter("classpath")))
         {
@@ -668,7 +689,7 @@
             if (classpath != null)
                 setInitParameter("classpath", classpath);
         }
-        
+
         /* ensure scratch dir */
         File scratch = null;
         if (getInitParameter("scratchdir") == null)
@@ -677,7 +698,7 @@
             scratch = new File(tmp, "jsp");
             setInitParameter("scratchdir", scratch.getAbsolutePath());
         }
-     
+
         scratch = new File (getInitParameter("scratchdir"));
         if (!scratch.exists()) scratch.mkdir();
     }
@@ -686,8 +707,8 @@
     /**
      * Register a ServletRequestListener that will ensure tmp multipart
      * files are deleted when the request goes out of scope.
-     * 
-     * @throws Exception
+     *
+     * @throws Exception if unable to init the multipart
      */
     protected void initMultiPart () throws Exception
     {
@@ -699,7 +720,7 @@
             //servlet calling Request.getPart() or Request.getParts()
 
             ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
-            ch.addEventListener(new Request.MultiPartCleanerListener());
+            ch.addEventListener(MultiPartCleanerListener.INSTANCE);
         }
     }
 
@@ -735,16 +756,16 @@
     {
         _runAsRole = role;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * Prepare to service a request.
-     * 
-     * @param baseRequest
-     * @param request
-     * @param response
-     * @throws ServletException
-     * @throws UnavailableException
+     *
+     * @param baseRequest the base request
+     * @param request the request
+     * @param response the response
+     * @throws ServletException if unable to prepare the servlet
+     * @throws UnavailableException if not available
      */
     protected void prepare (Request baseRequest, ServletRequest request, ServletResponse response)
     throws ServletException, UnavailableException
@@ -754,7 +775,7 @@
         if (mpce != null)
             baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
     }
-    
+
     public synchronized Servlet ensureInstance()
     throws ServletException, UnavailableException
     {
@@ -766,19 +787,21 @@
         if (_unavailable!=0 || (!_initOnStartup && servlet==null))
             servlet=getServlet();
         if (servlet==null)
-            throw new UnavailableException("Could not instantiate "+_class);    
-        
+            throw new UnavailableException("Could not instantiate "+_class);
+
         return servlet;
     }
 
     /* ------------------------------------------------------------ */
-    /** Service a request with this servlet.
-     * @param baseRequest
-     * @param request
-     * @param response
-     * @throws ServletException
-     * @throws UnavailableException
-     * @throws IOException
+    /**
+     * Service a request with this servlet.
+     *
+     * @param baseRequest the base request
+     * @param request the request
+     * @param response the response
+     * @throws ServletException if unable to process the servlet
+     * @throws UnavailableException if servlet is unavailable
+     * @throws IOException if unable to process the request or response
      */
     public void handle(Request baseRequest,
                        ServletRequest request,
@@ -827,7 +850,7 @@
 
             // Handle error params.
             if (servlet_error)
-                request.setAttribute("javax.servlet.error.servlet_name",getName());
+                request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME,getName());
         }
     }
 
@@ -862,13 +885,7 @@
     /* ------------------------------------------------------------ */
     private void adaptForcedPathToJspContainer (ServletRequest request)
     {
-        if (_forcedPath != null && _jspContainer != null && JspContainer.GLASSFISH.equals(_jspContainer))
-        {
-            //if container is glassfish, set the request attribute org.apache.catalina.jsp_file to
-            //ensure the delegate jsp will be compiled
-
-            request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
-        }
+        //no-op for apache jsp
     }
 
     /* ------------------------------------------------------------ */
@@ -876,29 +893,17 @@
     {
         if (_jspContainer == null)
         {
-            //check for glassfish
             try
             {
-                //if container is glassfish, set the request attribute org.apache.catalina.jsp_file to
-                //ensure the delegate jsp will be compiled
-                Loader.loadClass(Holder.class, GLASSFISH_SENTINEL_CLASS);
-                if (LOG.isDebugEnabled())LOG.debug("Glassfish jasper detected");
-                _jspContainer = JspContainer.GLASSFISH;
+                //check for apache
+                Loader.loadClass(Holder.class, APACHE_SENTINEL_CLASS);
+                if (LOG.isDebugEnabled())LOG.debug("Apache jasper detected");
+                _jspContainer = JspContainer.APACHE;
             }
-            catch (ClassNotFoundException e)
+            catch (ClassNotFoundException x)
             {
-                try
-                {
-                    //check for apache
-                    Loader.loadClass(Holder.class, APACHE_SENTINEL_CLASS);
-                    if (LOG.isDebugEnabled())LOG.debug("Apache jasper detected");
-                    _jspContainer = JspContainer.APACHE;
-                }
-                catch (ClassNotFoundException x)
-                {
-                    if (LOG.isDebugEnabled())LOG.debug("Other jasper detected");
-                    _jspContainer = JspContainer.OTHER;
-                }
+                if (LOG.isDebugEnabled())LOG.debug("Other jasper detected");
+                _jspContainer = JspContainer.OTHER;
             }
         }
     }
@@ -908,7 +913,7 @@
     {
         if (jsp == null)
             return "";
-        
+
         int i = jsp.lastIndexOf('/') + 1;
         jsp = jsp.substring(i);
         try
@@ -926,14 +931,14 @@
             return tmp;
         }
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     private String getPackageOfJspClass (String jsp)
     {
         if (jsp == null)
             return "";
-        
+
         int i = jsp.lastIndexOf('/');
         if (i <= 0)
             return "";
@@ -942,7 +947,7 @@
             Class<?> jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
             Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class);
             return (String)makeJavaPackage.invoke(null, jsp.substring(0,i));
-        } 
+        }
         catch (Exception e)
         {
             String tmp = jsp.substring(1).replace('/','.');
@@ -952,25 +957,25 @@
             return tmp;
         }
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     private String getJspPackagePrefix ()
     {
         String jspPackageName = (String)getServletHandler().getServletContext().getInitParameter(JSP_GENERATED_PACKAGE_NAME );
         if (jspPackageName == null)
             jspPackageName = "org.apache.jsp";
-        
+
         return jspPackageName;
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     private String getClassNameForJsp (String jsp)
     {
         if (jsp == null)
-            return null; 
-        
+            return null;
+
         return getJspPackagePrefix() + "." +getPackageOfJspClass(jsp) + "." + getNameOfJspClass(jsp);
     }
 
@@ -1194,9 +1199,9 @@
     /* ------------------------------------------------------------ */
     /**
      * @return the newly created Servlet instance
-     * @throws ServletException
-     * @throws IllegalAccessException
-     * @throws InstantiationException
+     * @throws ServletException if unable to create a new instance
+     * @throws IllegalAccessException if not allowed to create a new instance
+     * @throws InstantiationException if creating new instance resulted in error
      */
     protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException
     {
@@ -1217,7 +1222,7 @@
             throw se;
         }
     }
-    
+
 
     /* ------------------------------------------------------------ */
     @Override
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java
index 4d132a6..875a071 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletMapping.java
@@ -65,6 +65,25 @@
     {
         _pathSpecs = pathSpecs;
     }
+    
+    
+    /* ------------------------------------------------------------ */
+    /** Test if the list of path specs contains a particular one.
+     * @param pathSpec
+     * @return
+     */
+    public boolean containsPathSpec (String pathSpec)
+    {
+        if (_pathSpecs == null || _pathSpecs.length == 0)
+            return false;
+        
+        for (String p:_pathSpecs)
+        {
+            if (p.equals(pathSpec))
+                return true;
+        }
+        return false;
+    }
 
     /* ------------------------------------------------------------ */
     /**
@@ -86,9 +105,6 @@
     
     
     /* ------------------------------------------------------------ */
-    /**
-     * @return
-     */
     @ManagedAttribute(value="default", readonly=true)
     public boolean isDefault()
     {
@@ -97,9 +113,6 @@
     
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param fromDefault
-     */
     public void setDefault(boolean fromDefault)
     {
         _default = fromDefault;
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletTester.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletTester.java
deleted file mode 100644
index 4ad1fd9..0000000
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletTester.java
+++ /dev/null
@@ -1,259 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlet;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.Servlet;
-
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.LocalConnector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.util.Attributes;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.resource.Resource;
-
-public class ServletTester extends ContainerLifeCycle
-{
-    private static final Logger LOG = Log.getLogger(ServletTester.class);
-    
-    private final Server _server=new Server();
-    private final LocalConnector _connector=new LocalConnector(_server);
-    private final ServletContextHandler _context;
-    
-    public Server getServer()
-    {
-        return _server;
-    }
-    
-    public LocalConnector getConnector()
-    {
-        return _connector;
-    }
-    
-    public void setVirtualHosts(String[] vhosts)
-    {
-        _context.setVirtualHosts(vhosts);
-    }
-
-    public void addVirtualHosts(String[] virtualHosts)
-    {
-        _context.addVirtualHosts(virtualHosts);
-    }
-
-    public ServletHolder addServlet(String className, String pathSpec)
-    {
-        return _context.addServlet(className,pathSpec);
-    }
-
-    public ServletHolder addServlet(Class<? extends Servlet> servlet, String pathSpec)
-    {
-        return _context.addServlet(servlet,pathSpec);
-    }
-
-    public void addServlet(ServletHolder servlet, String pathSpec)
-    {
-        _context.addServlet(servlet,pathSpec);
-    }
-
-    public void addFilter(FilterHolder holder, String pathSpec, EnumSet<DispatcherType> dispatches)
-    {
-        _context.addFilter(holder,pathSpec,dispatches);
-    }
-
-    public FilterHolder addFilter(Class<? extends Filter> filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
-    {
-        return _context.addFilter(filterClass,pathSpec,dispatches);
-    }
-
-    public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
-    {
-        return _context.addFilter(filterClass,pathSpec,dispatches);
-    }
-
-    public Object getAttribute(String name)
-    {
-        return _context.getAttribute(name);
-    }
-
-    public Enumeration<String> getAttributeNames()
-    {
-        return _context.getAttributeNames();
-    }
-
-    public Attributes getAttributes()
-    {
-        return _context.getAttributes();
-    }
-
-    public String getContextPath()
-    {
-        return _context.getContextPath();
-    }
-
-    public String getInitParameter(String name)
-    {
-        return _context.getInitParameter(name);
-    }
-
-    public String setInitParameter(String name, String value)
-    {
-        return _context.setInitParameter(name,value);
-    }
-
-    public Enumeration<String> getInitParameterNames()
-    {
-        return _context.getInitParameterNames();
-    }
-
-    public Map<String, String> getInitParams()
-    {
-        return _context.getInitParams();
-    }
-
-    public void removeAttribute(String name)
-    {
-        _context.removeAttribute(name);
-    }
-
-    public void setAttribute(String name, Object value)
-    {
-        _context.setAttribute(name,value);
-    }
-
-    public void setContextPath(String contextPath)
-    {
-        _context.setContextPath(contextPath);
-    }
-
-    public Resource getBaseResource()
-    {
-        return _context.getBaseResource();
-    }
-
-    public String getResourceBase()
-    {
-        return _context.getResourceBase();
-    }
-
-    public void setResourceBase(String resourceBase)
-    {
-        _context.setResourceBase(resourceBase);
-    }
-
-    public ServletTester()
-    {
-        this("/",ServletContextHandler.SECURITY|ServletContextHandler.SESSIONS);
-    }
-
-    public ServletTester(String ctxPath)
-    {
-        this(ctxPath,ServletContextHandler.SECURITY|ServletContextHandler.SESSIONS);
-    }
-
-    public ServletTester(String contextPath,int options)
-    {
-        _context=new ServletContextHandler(_server,contextPath,options);
-        _server.setConnectors(new Connector[]{_connector});
-        addBean(_server);
-    }
-
-    public ServletContextHandler getContext()
-    {
-        return _context;
-    }
-
-    public String getResponses(String request) throws Exception
-    {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug("Request: {}",request);
-        }
-        return _connector.getResponses(request);
-    }
-    
-    public String getResponses(String request, long idleFor,TimeUnit units) throws Exception
-    {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug("Request: {}",request);
-        }
-        return _connector.getResponses(request, idleFor, units);
-    }
-    
-    public ByteBuffer getResponses(ByteBuffer request) throws Exception
-    {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug("Request (Buffer): {}",BufferUtil.toUTF8String(request));
-        }
-        return _connector.getResponses(request);
-    }
-    
-    public ByteBuffer getResponses(ByteBuffer requestsBuffer,long idleFor,TimeUnit units) throws Exception
-    {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug("Requests (Buffer): {}",BufferUtil.toUTF8String(requestsBuffer));
-        }
-        return _connector.getResponses(requestsBuffer, idleFor, units);
-    }
-
-    /** Create a port based connector.
-     * This methods adds a port connector to the server
-     * @return A URL to access the server via the connector.
-     * @throws Exception
-     */
-    public String createConnector(boolean localhost) throws Exception
-    {
-        ServerConnector connector = new ServerConnector(_server);
-        if (localhost)
-            connector.setHost("127.0.0.1");
-        _server.addConnector(connector);
-        if (_server.isStarted())
-            connector.start();
-        else
-            connector.open();
-
-        return "http://"+(localhost?"127.0.0.1":
-            InetAddress.getLocalHost().getHostAddress()
-        )+":"+connector.getLocalPort();
-    }
-
-    public LocalConnector createLocalConnector()
-    {
-        LocalConnector connector = new LocalConnector(_server);
-        _server.addConnector(connector);
-        return connector;
-    }
-
-
-
-}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java
index 4af441a..6f1dca6 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextDispatchWithQueryStrings.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.servlet;
 
+import static org.hamcrest.Matchers.startsWith;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
 
@@ -43,69 +44,77 @@
  * This tests verifies that merging of queryStrings works when dispatching
  * Requests via {@link AsyncContext} multiple times.
  */
-public class AsyncContextDispatchWithQueryStrings {
+public class AsyncContextDispatchWithQueryStrings 
+{
+    private Server _server = new Server();
+    private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+    private LocalConnector _connector = new LocalConnector(_server);
 
-        private Server _server = new Server();
-        private ServletContextHandler _contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
-        private LocalConnector _connector = new LocalConnector(_server);
+    @Before
+    public void setUp() throws Exception 
+    {
+        _connector.setIdleTimeout(30000);
+        _server.setConnectors(new Connector[] { _connector });
 
-        @Before
-        public void setUp() throws Exception {
-                _connector.setIdleTimeout(30000);
-                _server.setConnectors(new Connector[] { _connector });
+        _contextHandler.setContextPath("/");
+        _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/initialCall");
+        _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/firstDispatchWithNewQueryString");
+        _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/secondDispatchNewValueForExistingQueryString");
 
-                _contextHandler.setContextPath("/");
-                _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/initialCall");
-                _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/firstDispatchWithNewQueryString");
-                _contextHandler.addServlet(new ServletHolder(new TestServlet()), "/secondDispatchNewValueForExistingQueryString");
+        HandlerList handlers = new HandlerList();
+        handlers.setHandlers(new Handler[] { _contextHandler, new DefaultHandler() });
 
-                HandlerList handlers = new HandlerList();
-                handlers.setHandlers(new Handler[] { _contextHandler, new DefaultHandler() });
+        _server.setHandler(handlers);
+        _server.start();
+    }
 
-                _server.setHandler(handlers);
-                _server.start();
+    @Test
+    public void testMultipleDispatchesWithNewQueryStrings() throws Exception 
+    {
+        String request = 
+                "GET /initialCall?initialParam=right HTTP/1.1\r\n" + 
+                        "Host: localhost\r\n" + 
+                        "Content-Type: application/x-www-form-urlencoded\r\n" +
+                        "Connection: close\r\n" + "\r\n";
+        String responseString = _connector.getResponses(request);
+        assertThat(responseString,startsWith("HTTP/1.1 200"));
+    }
+
+    @After
+    public void tearDown() throws Exception 
+    {
+        _server.stop();
+        _server.join();
+    }
+
+    private class TestServlet extends HttpServlet 
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
+        {
+            String uri = request.getRequestURI();
+            String queryString = request.getQueryString();
+            if ("/initialCall".equals(uri)) 
+            {
+                AsyncContext async = request.startAsync();
+                async.dispatch("/firstDispatchWithNewQueryString?newQueryString=initialValue");
+                assertEquals("initialParam=right", queryString);
+            } 
+            else if ("/firstDispatchWithNewQueryString".equals(uri)) 
+            {
+                AsyncContext async = request.startAsync();
+                async.dispatch("/secondDispatchNewValueForExistingQueryString?newQueryString=newValue");
+                assertEquals("newQueryString=initialValue&initialParam=right", queryString);
+            } 
+            else 
+            {
+                response.setContentType("text/html");
+                response.setStatus(HttpServletResponse.SC_OK);
+                response.getWriter().println("<h1>woohhooooo</h1>");
+                assertEquals("newQueryString=newValue&initialParam=right", queryString);
+            }
         }
-
-        @Test
-        public void testMultipleDispatchesWithNewQueryStrings() throws Exception {
-                String request = "GET /initialCall?initialParam=right HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
-                                + "Connection: close\r\n" + "\r\n";
-                String responseString = _connector.getResponses(request);
-                assertTrue("Not the expected response. Check STDOUT for details.", responseString.startsWith("HTTP/1.1 200"));
-        }
-
-        @After
-        public void tearDown() throws Exception {
-                _server.stop();
-                _server.join();
-        }
-
-        private class TestServlet extends HttpServlet {
-                private static final long serialVersionUID = 1L;
-
-                @Override
-                protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-                        String path = request.getRequestURI();
-                        String queryString = request.getQueryString();
-                        if ("/initialCall".equals(path)) 
-                        {
-                            AsyncContext async = request.startAsync();
-                            async.dispatch("/firstDispatchWithNewQueryString?newQueryString=initialValue");
-                            assertEquals("initialParam=right", queryString);
-                        } 
-                        else if ("/firstDispatchWithNewQueryString".equals(path)) 
-                        {
-                            AsyncContext async = request.startAsync();
-                            async.dispatch("/secondDispatchNewValueForExistingQueryString?newQueryString=newValue");
-                            assertEquals("newQueryString=initialValue&initialParam=right", queryString);
-                        } 
-                        else 
-                        {
-                            response.setContentType("text/html");
-                            response.setStatus(HttpServletResponse.SC_OK);
-                            response.getWriter().println("<h1>woohhooooo</h1>");
-                            assertEquals("newQueryString=newValue&initialParam=right", queryString);
-                        }
-                }
-        }
+    }
 }
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextListenersTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextListenersTest.java
index 8a79431..f8aebd2 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextListenersTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextListenersTest.java
@@ -24,7 +24,10 @@
 import java.io.OutputStream;
 import java.net.Socket;
 import java.nio.charset.StandardCharsets;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
@@ -68,7 +71,7 @@
     @Test
     public void testListenerClearedOnSecondRequest() throws Exception
     {
-        final AtomicInteger completes = new AtomicInteger();
+        final AtomicReference<CountDownLatch> completes = new AtomicReference<>(new CountDownLatch(1));
         String path = "/path";
         prepare(path, new HttpServlet()
         {
@@ -86,7 +89,7 @@
                     @Override
                     public void onComplete(AsyncEvent event) throws IOException
                     {
-                        completes.incrementAndGet();
+                        completes.get().countDown();
                     }
 
                     @Override
@@ -118,23 +121,23 @@
             SimpleHttpParser parser = new SimpleHttpParser();
             SimpleHttpResponse response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
 
             // Send a second request
-            completes.set(0);
+            completes.set(new CountDownLatch(1));
             output.write(request.getBytes(StandardCharsets.UTF_8));
             output.flush();
 
             response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
         }
     }
 
     @Test
     public void testListenerAddedFromListener() throws Exception
     {
-        final AtomicInteger completes = new AtomicInteger();
+        final AtomicReference<CountDownLatch> completes = new AtomicReference<>(new CountDownLatch(1));
         String path = "/path";
         prepare(path, new HttpServlet()
         {
@@ -157,7 +160,7 @@
                     @Override
                     public void onComplete(AsyncEvent event) throws IOException
                     {
-                        completes.incrementAndGet();
+                        completes.get().countDown();
                     }
 
                     @Override
@@ -189,22 +192,22 @@
             SimpleHttpParser parser = new SimpleHttpParser();
             SimpleHttpResponse response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
 
             // Send a second request
-            completes.set(0);
+            completes.set(new CountDownLatch(1));
             output.write(request.getBytes(StandardCharsets.UTF_8));
             output.flush();
 
             response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
         }
     }
     @Test
     public void testAsyncDispatchAsyncCompletePreservesListener() throws Exception
     {
-        final AtomicInteger completes = new AtomicInteger();
+        final AtomicReference<CountDownLatch> completes = new AtomicReference<>(new CountDownLatch(1));
         final String path = "/path";
         prepare(path + "/*", new HttpServlet()
         {
@@ -226,7 +229,7 @@
                         @Override
                         public void onComplete(AsyncEvent event) throws IOException
                         {
-                            completes.incrementAndGet();
+                            completes.get().countDown();
                         }
 
                         @Override
@@ -267,16 +270,16 @@
             SimpleHttpParser parser = new SimpleHttpParser();
             SimpleHttpResponse response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
 
             // Send a second request
-            completes.set(0);
+            completes.set(new CountDownLatch(1));
             output.write(request.getBytes(StandardCharsets.UTF_8));
             output.flush();
 
             response = parser.readResponse(reader);
             Assert.assertEquals("200", response.getCode());
-            Assert.assertEquals(1, completes.get());
+            completes.get().await(10,TimeUnit.SECONDS);
         }
     }
 }
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
index 9a9ae5c..d375134 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java
@@ -410,7 +410,7 @@
         
         BufferedReader br = new BufferedReader(new StringReader(responseString));
 
-        assertEquals("HTTP/1.1 500 Async Exception",br.readLine());
+        assertEquals("HTTP/1.1 500 Server Error",br.readLine());
         br.readLine();// connection close
         br.readLine();// server
         br.readLine();// empty
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java
index 5d70474..539fd39 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java
@@ -18,6 +18,13 @@
 
 package org.eclipse.jetty.servlet;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -30,6 +37,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
 import javax.servlet.ReadListener;
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
@@ -39,33 +47,36 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandler.Context;
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
 import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser;
 import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse;
 import org.eclipse.jetty.util.IO;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
+@RunWith (AdvancedRunner.class)
 public class AsyncIOServletTest
 {
     private Server server;
     private ServerConnector connector;
     private ServletContextHandler context;
     private String path = "/path";
+    private static final ThreadLocal<String> scope = new ThreadLocal<>();
 
     public void startServer(HttpServlet servlet) throws Exception
     {
         server = new Server();
         connector = new ServerConnector(server);
+        connector.setIdleTimeout(30000);
+        connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setDelayDispatchUntilContent(false);
         server.addConnector(connector);
 
         context = new ServletContextHandler(server, "/", false, false);
@@ -73,9 +84,34 @@
         holder.setAsyncSupported(true);
         context.addServlet(holder, path);
 
+        context.addEventListener(new ContextHandler.ContextScopeListener()
+        {
+            @Override
+            public void enterScope(Context context, Request request, Object reason)
+            {
+                if (scope.get()!=null)
+                    throw new IllegalStateException();
+                scope.set("SCOPPED");
+                
+            }
+            @Override
+            public void exitScope(Context context, Request request)
+            {
+                if (scope.get()==null)
+                    throw new IllegalStateException();
+                scope.set(null);
+            } 
+        });
+        
         server.start();
     }
 
+    private static void assertScope()
+    {
+        if (scope.get()==null)
+            Assert.fail("Not in scope");
+    }
+    
     @After
     public void stopServer() throws Exception
     {
@@ -102,12 +138,14 @@
             @Override
             protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 final AsyncContext asyncContext = request.startAsync(request, response);
                 request.getInputStream().setReadListener(new ReadListener()
                 {
                     @Override
                     public void onDataAvailable() throws IOException
                     {
+                        assertScope();
                         if (throwable instanceof RuntimeException)
                             throw (RuntimeException)throwable;
                         if (throwable instanceof Error)
@@ -118,15 +156,18 @@
                     @Override
                     public void onAllDataRead() throws IOException
                     {
+                        assertScope();
                     }
 
                     @Override
                     public void onError(Throwable t)
                     {
+                        assertScope();
                         Assert.assertThat("onError type",t,instanceOf(throwable.getClass()));
                         Assert.assertThat("onError message",t.getMessage(),is(throwable.getMessage()));
                         latch.countDown();
                         response.setStatus(500);
+                        
                         asyncContext.complete();
                     }
                 });
@@ -142,15 +183,21 @@
 
         try (Socket client = new Socket("localhost", connector.getLocalPort()))
         {
+            client.setSoTimeout(5000);
             OutputStream output = client.getOutputStream();
             output.write(request.getBytes("UTF-8"));
             output.flush();
 
-            SimpleHttpParser parser = new SimpleHttpParser();
-            SimpleHttpResponse response = parser.readResponse(new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")));
-
+            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
+            String line=in.readLine();
+            assertThat(line, containsString("500 Server Error"));
+            while (line.length()>0)
+            {
+                line=in.readLine();
+            }
+            line=in.readLine();
+            
             Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-            Assert.assertEquals("500", response.getCode());
         }
     }
 
@@ -163,6 +210,7 @@
             @Override
             protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 final AsyncContext asyncContext = request.startAsync(request, response);
                 asyncContext.setTimeout(0);
                 final ServletInputStream inputStream = request.getInputStream();
@@ -171,6 +219,7 @@
                     @Override
                     public void onDataAvailable() throws IOException
                     {
+                        assertScope();
                         while (inputStream.isReady() && !inputStream.isFinished())
                             inputStream.read();
                     }
@@ -178,11 +227,13 @@
                     @Override
                     public void onAllDataRead() throws IOException
                     {
+                        assertScope();
                     }
 
                     @Override
                     public void onError(Throwable t)
                     {
+                        assertScope();
                         response.setStatus(status);
                         // Do not put Connection: close header here, the test
                         // verifies that the server closes no matter what.
@@ -207,6 +258,7 @@
 
         try (Socket client = new Socket("localhost", connector.getLocalPort()))
         {
+            client.setSoTimeout(5000);
             OutputStream output = client.getOutputStream();
             output.write(request.getBytes("UTF-8"));
             output.flush();
@@ -230,25 +282,35 @@
             @Override
             protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
+                if (request.getDispatcherType()==DispatcherType.ERROR)
+                {
+                    response.flushBuffer();
+                    return;
+                }
+                
                 final AsyncContext asyncContext = request.startAsync(request, response);
                 request.getInputStream().setReadListener(new ReadListener()
                 {
                     @Override
                     public void onDataAvailable() throws IOException
                     {
+                        assertScope();
                         throw new NullPointerException("explicitly_thrown_by_test_1");
                     }
 
                     @Override
                     public void onAllDataRead() throws IOException
                     {
+                        assertScope();
                     }
 
                     @Override
-                    public void onError(Throwable t)
+                    public void onError(final Throwable t)
                     {
+                        assertScope();
                         errors.incrementAndGet();
-                        throw new NullPointerException("explicitly_thrown_by_test_2");
+                        throw new NullPointerException("explicitly_thrown_by_test_2"){{this.initCause(t);}};
                     }
                 });
             }
@@ -295,12 +357,14 @@
             @Override
             protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 final AsyncContext asyncContext = request.startAsync(request, response);
                 response.getOutputStream().setWriteListener(new WriteListener()
                 {
                     @Override
                     public void onWritePossible() throws IOException
                     {
+                        assertScope();
                         if (throwable instanceof RuntimeException)
                             throw (RuntimeException)throwable;
                         if (throwable instanceof Error)
@@ -311,6 +375,7 @@
                     @Override
                     public void onError(Throwable t)
                     {
+                        assertScope();
                         latch.countDown();
                         response.setStatus(500);
                         asyncContext.complete();
@@ -353,6 +418,7 @@
             @Override
             protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 response.flushBuffer();
                 
                 final AsyncContext async = request.startAsync();
@@ -362,6 +428,7 @@
                     @Override
                     public void onWritePossible() throws IOException
                     {
+                        assertScope();
                         while (out.isReady())
                         {
                             try
@@ -383,6 +450,7 @@
                     @Override
                     public void onError(Throwable t)
                     {
+                        assertScope();
                         async.complete();
                         latch.countDown();
                     }
@@ -417,9 +485,9 @@
     
 
     @Test
-    public void testIsNotReadyAtEOF() throws Exception
+    public void testIsReadyAtEOF() throws Exception
     {
-        String text = "Test\n";
+        String text = "TEST\n";
         final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1);
         
         startServer(new HttpServlet()
@@ -427,6 +495,7 @@
             @Override
             protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 response.flushBuffer();
                 
                 final AsyncContext async = request.startAsync();
@@ -442,6 +511,7 @@
                     @Override
                     public void onError(Throwable t)
                     {
+                        assertScope();
                         t.printStackTrace();
                         async.complete();
                     }
@@ -449,6 +519,7 @@
                     @Override
                     public void onDataAvailable() throws IOException
                     {
+                        assertScope();
                         while(in.isReady() && !in.isFinished())
                         {
                             int b = in.read();
@@ -465,6 +536,7 @@
                     @Override
                     public void onAllDataRead() throws IOException
                     {
+                        assertScope();
                         out.write(String.format("i=%d eof=%b finished=%b",_i,_minusOne,_finished).getBytes(StandardCharsets.ISO_8859_1));
                         async.complete();                        
                     }
@@ -483,6 +555,7 @@
         {
             OutputStream output = client.getOutputStream();
             output.write(request.getBytes("UTF-8"));
+            output.flush();
             output.write(data);
             output.flush();
 
@@ -492,7 +565,282 @@
             while (line.length()>0)
                 line=in.readLine();
             line=in.readLine();
-            assertThat(line, containsString("i="+data.length+" eof=false finished=true"));
+            assertThat(line, containsString("i="+data.length+" eof=true finished=true"));
+        }
+    }
+    
+
+    @Test
+    public void testOnAllDataRead() throws Exception
+    {
+        String text = "X";
+        final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1);
+        
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+            {
+                assertScope();
+                response.flushBuffer();
+                
+                final AsyncContext async = request.startAsync();
+                async.setTimeout(5000);
+                final ServletInputStream in = request.getInputStream();
+                final ServletOutputStream out = response.getOutputStream();
+                
+                in.setReadListener(new ReadListener()
+                {
+                    @Override
+                    public void onError(Throwable t)
+                    {
+                        assertScope();
+                        t.printStackTrace();
+                        async.complete();
+                    }
+                    
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        assertScope();
+                        try
+                        {
+                            Thread.sleep(1000);
+                            if (!in.isReady())
+                                throw new IllegalStateException();
+                            if (in.read()!='X')
+                                throw new IllegalStateException();
+                            if (!in.isReady())
+                                throw new IllegalStateException();
+                            if (in.read()!=-1)
+                                throw new IllegalStateException();
+                        }
+                        catch(Exception e)
+                        {
+                            e.printStackTrace();
+                        }
+                    }
+                    
+                    @Override
+                    public void onAllDataRead() throws IOException
+                    {
+                        assertScope();
+                        out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1));
+                        async.complete();                        
+                    }
+                });
+            }
+        });
+
+        String request = "GET " + path + " HTTP/1.1\r\n" +
+                "Host: localhost:" + connector.getLocalPort() + "\r\n" +
+                "Content-Type: text/plain\r\n"+
+                "Content-Length: "+data.length+"\r\n" +
+                "Connection: close\r\n" +
+                "\r\n";
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            client.setSoTimeout(5000);
+            OutputStream output = client.getOutputStream();
+            output.write(request.getBytes("UTF-8"));
+            output.flush();
+            Thread.sleep(100);
+            output.write(data);
+            output.flush();
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
+            String line=in.readLine();
+            assertThat(line, containsString("200 OK"));
+            while (line.length()>0)
+                line=in.readLine();
+            line=in.readLine();
+            assertThat(line, containsString("OK"));
+        }
+    }
+    
+    @Test
+    public void testOtherThreadOnAllDataRead() throws Exception
+    {
+        String text = "X";
+        final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1);
+        
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+            {
+                assertScope();
+                response.flushBuffer();
+                
+                final AsyncContext async = request.startAsync();
+                async.setTimeout(500000);
+                final ServletInputStream in = request.getInputStream();
+                final ServletOutputStream out = response.getOutputStream();
+                
+                if (request.getDispatcherType()==DispatcherType.ERROR)
+                    throw new IllegalStateException();
+                
+                in.setReadListener(new ReadListener()
+                {
+                    @Override
+                    public void onError(Throwable t)
+                    {
+                        assertScope();
+                        t.printStackTrace();
+                        async.complete();
+                    }
+                    
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        assertScope();
+                        async.start(
+                        new Runnable()
+                        {
+                            public void run()
+                            {
+                                assertScope();
+                                try
+                                {
+                                    Thread.sleep(1000);
+                                    if (!in.isReady())
+                                        throw new IllegalStateException();
+                                    if (in.read()!='X')
+                                        throw new IllegalStateException();
+                                    if (!in.isReady())
+                                        throw new IllegalStateException();
+                                    if (in.read()!=-1)
+                                        throw new IllegalStateException();
+                                }
+                                catch(Exception e)
+                                {
+                                    e.printStackTrace();
+                                }
+                            }
+                        });
+                    }
+                    
+                    @Override
+                    public void onAllDataRead() throws IOException
+                    {
+                        out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1));
+                        async.complete();                        
+                    }
+                });
+            }
+        });
+
+        String request = "GET " + path + " HTTP/1.1\r\n" +
+                "Host: localhost:" + connector.getLocalPort() + "\r\n" +
+                "Content-Type: text/plain\r\n"+
+                "Content-Length: "+data.length+"\r\n" +
+                "Connection: close\r\n" +
+                "\r\n";
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            client.setSoTimeout(500000);
+            OutputStream output = client.getOutputStream();
+            output.write(request.getBytes("UTF-8"));
+            output.flush();
+            Thread.sleep(100);
+            output.write(data);
+            output.flush();
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
+            String line=in.readLine();
+            assertThat(line, containsString("200 OK"));
+            while (line.length()>0)
+                line=in.readLine();
+            line=in.readLine();
+            assertThat(line, containsString("OK"));
+        }
+    }
+    
+
+    @Test
+    public void testCompleteBeforeOnAllDataRead() throws Exception
+    {
+        String text = "XYZ";
+        final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1);
+        final AtomicBoolean allDataRead = new AtomicBoolean(false);
+        
+        startServer(new HttpServlet()
+        {
+            @Override
+            protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+            {
+                assertScope();
+                response.flushBuffer();
+                
+                final AsyncContext async = request.startAsync();
+                final ServletInputStream in = request.getInputStream();
+                final ServletOutputStream out = response.getOutputStream();
+                
+                in.setReadListener(new ReadListener()
+                {
+                    @Override
+                    public void onError(Throwable t)
+                    {
+                        assertScope();
+                        t.printStackTrace();
+                    }
+                    
+                    @Override
+                    public void onDataAvailable() throws IOException
+                    {
+                        assertScope();
+                        while (in.isReady())
+                        {
+                            int b = in.read();
+                            if (b<0)
+                            {
+                                out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1));
+                                async.complete();
+                                return;
+                            } 
+                        }
+                    }
+                    
+                    @Override
+                    public void onAllDataRead() throws IOException
+                    {
+                        assertScope();
+                        out.write("BAD!!!\n".getBytes(StandardCharsets.ISO_8859_1));
+                        allDataRead.set(true);
+                        throw new IllegalStateException();     
+                    }
+                });
+            }
+        });
+
+        String request = "GET " + path + " HTTP/1.1\r\n" +
+                "Host: localhost:" + connector.getLocalPort() + "\r\n" +
+                "Content-Type: text/plain\r\n"+
+                "Content-Length: "+data.length+"\r\n" +
+                "Connection: close\r\n" +
+                "\r\n";
+
+        try (Socket client = new Socket("localhost", connector.getLocalPort()))
+        {
+            OutputStream output = client.getOutputStream();
+            output.write(request.getBytes("UTF-8"));
+            output.flush();
+            Thread.sleep(100);
+            output.write(data);
+            output.flush();
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
+            String line=in.readLine();
+            assertThat(line, containsString("200 OK"));
+            while (line.length()>0)
+            {
+                line=in.readLine();
+            }
+            line=in.readLine();
+            assertThat(line, containsString("OK"));
+            Assert.assertFalse(allDataRead.get());
         }
     }
     
@@ -508,6 +856,7 @@
             @Override
             protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
             {
+                assertScope();
                 final AsyncContext asyncContext = request.startAsync(request, response);
                 response.setStatus(200);
                 response.getOutputStream().close();
@@ -516,12 +865,14 @@
                     @Override
                     public void onDataAvailable() throws IOException 
                     {
+                        assertScope();
                         oda.set(true);
                     }
 
                     @Override
                     public void onAllDataRead() throws IOException 
                     {
+                        assertScope();
                         asyncContext.complete();
                         latch.countDown();
                     }
@@ -529,6 +880,7 @@
                     @Override
                     public void onError(Throwable t) 
                     {
+                        assertScope();
                         t.printStackTrace();
                         asyncContext.complete();
                     }        
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java
new file mode 100644
index 0000000..d992d3e
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncListenerTest.java
@@ -0,0 +1,648 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.junit.Ignore;
+import org.junit.Test;
+
+@Ignore("Not handling Exceptions during Async very well")
+public class AsyncListenerTest
+{
+    // Unique named RuntimeException to help during debugging / assertions
+    @SuppressWarnings("serial")
+    public static class FooRuntimeException extends RuntimeException
+    {
+    }
+
+    // Unique named Exception to help during debugging / assertions
+    @SuppressWarnings("serial")
+    public static class FooException extends Exception
+    {
+    }
+
+    // Unique named Throwable to help during debugging / assertions
+    @SuppressWarnings("serial")
+    public static class FooThrowable extends Throwable
+    {
+    }
+
+    // Unique named Error to help during debugging / assertions
+    @SuppressWarnings("serial")
+    public static class FooError extends Error
+    {
+    }
+
+    /**
+     * Basic AsyncListener adapter that simply logs (and makes testcase writing easier) 
+     */
+    public static class AsyncListenerAdapter implements AsyncListener
+    {
+        private static final Logger LOG = Log.getLogger(AsyncListenerTest.AsyncListenerAdapter.class);
+
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            LOG.info("onComplete({})",event);
+        }
+
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {
+            LOG.info("onTimeout({})",event);
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            LOG.info("onError({})",event);
+        }
+
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+            LOG.info("onStartAsync({})",event);
+        }
+    }
+
+    /**
+     * Common ErrorContext for normal and async error handling
+     */
+    public static class ErrorContext implements AsyncListener
+    {
+        private static final Logger LOG = Log.getLogger(AsyncListenerTest.ErrorContext.class);
+
+        public void report(Throwable t, ServletRequest req, ServletResponse resp) throws IOException
+        {
+            if (resp instanceof HttpServletResponse)
+            {
+                ((HttpServletResponse)resp).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            }
+            resp.setContentType("text/plain");
+            resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
+            PrintWriter out = resp.getWriter();
+            t.printStackTrace(out);
+        }
+
+        private void reportThrowable(AsyncEvent event) throws IOException
+        {
+            Throwable t = event.getThrowable();
+            if (t == null)
+            {
+                return;
+            }
+            ServletRequest req = event.getAsyncContext().getRequest();
+            ServletResponse resp = event.getAsyncContext().getResponse();
+            report(t,req,resp);
+        }
+
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException
+        {
+            LOG.info("onComplete({})",event);
+            reportThrowable(event);
+        }
+
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException
+        {
+            LOG.info("onTimeout({})",event);
+            reportThrowable(event);
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException
+        {
+            LOG.info("onError({})",event);
+            reportThrowable(event);
+        }
+
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException
+        {
+            LOG.info("onStartAsync({})",event);
+            reportThrowable(event);
+        }
+    }
+
+    /**
+     * Common filter for all test cases that should handle Errors in a consistent way
+     * regardless of how the exception / error occurred in the servlets in the chain.
+     */
+    public static class ErrorFilter implements Filter
+    {
+        private final List<ErrorContext> tracking;
+
+        public ErrorFilter(List<ErrorContext> tracking)
+        {
+            this.tracking = tracking;
+        }
+
+        @Override
+        public void destroy()
+        {
+        }
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+        {
+            ErrorContext err = new ErrorContext();
+            tracking.add(err);
+            try
+            {
+                chain.doFilter(request,response);
+            }
+            catch (Throwable t)
+            {
+                err.report(t,request,response);
+            }
+            finally
+            {
+                if (request.isAsyncStarted())
+                {
+                    request.getAsyncContext().addListener(err);
+                }
+            }
+        }
+
+        @Override
+        public void init(FilterConfig filterConfig) throws ServletException
+        {
+        }
+    }
+
+    /**
+     * Normal non-async testcase of error handling from a filter
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorNoAsync() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                throw new FooRuntimeException();
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, then application Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_Exception() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                req.startAsync();
+                // before listeners are added, toss Exception
+                throw new FooRuntimeException();
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, add listener that does nothing, then application Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_AddEmptyListener_Exception() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.addListener(new AsyncListenerAdapter());
+                throw new FooRuntimeException();
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, add listener that completes only, then application Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_AddListener_Exception() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.addListener(new AsyncListenerAdapter()
+                {
+                    @Override
+                    public void onError(AsyncEvent event) throws IOException
+                    {
+                        System.err.println("### ONERROR");
+                        event.getThrowable().printStackTrace(System.err);
+                        event.getAsyncContext().complete();
+                    }
+                });
+                throw new FooRuntimeException();
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, add listener, in onStartAsync throw Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_AddListener_ExceptionDuringOnStart() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.addListener(new AsyncListenerAdapter()
+                {
+                    @Override
+                    public void onStartAsync(AsyncEvent event) throws IOException
+                    {
+                        throw new FooRuntimeException();
+                    }
+                });
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+    
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, add listener, in onComplete throw Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_AddListener_ExceptionDuringOnComplete() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.addListener(new AsyncListenerAdapter()
+                {
+                    @Override
+                    public void onComplete(AsyncEvent event) throws IOException
+                    {
+                        throw new FooRuntimeException();
+                    }
+                });
+                ctx.complete();
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, add listener, in onTimeout throw Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_AddListener_ExceptionDuringOnTimeout() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.setTimeout(1000);
+                ctx.addListener(new AsyncListenerAdapter()
+                {
+                    @Override
+                    public void onTimeout(AsyncEvent event) throws IOException
+                    {
+                        throw new FooRuntimeException();
+                    }
+                });
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+    /**
+     * async testcase of error handling from a filter.
+     * 
+     * Async Started, no listener, in start() throw Exception
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testFilterErrorAsyncStart_NoListener_ExceptionDuringStart() throws Exception
+    {
+        Server server = new Server();
+        LocalConnector conn = new LocalConnector(server);
+        conn.setIdleTimeout(10000);
+        server.addConnector(conn);
+
+        ServletContextHandler context = new ServletContextHandler();
+        context.setContextPath("/");
+        @SuppressWarnings("serial")
+        HttpServlet servlet = new HttpServlet()
+        {
+            public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+            {
+                AsyncContext ctx = req.startAsync();
+                ctx.setTimeout(1000);
+                ctx.start(new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        throw new FooRuntimeException();
+                    }
+                });
+            }
+        };
+        ServletHolder holder = new ServletHolder(servlet);
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/err/*");
+        List<ErrorContext> tracking = new LinkedList<ErrorContext>();
+        ErrorFilter filter = new ErrorFilter(tracking);
+        context.addFilter(new FilterHolder(filter),"/*",EnumSet.allOf(DispatcherType.class));
+
+        server.setHandler(context);
+
+        try
+        {
+            server.start();
+            String resp = conn.getResponses("GET /err/ HTTP/1.1\n" + "Host: localhost\n" + "Connection: close\n" + "\n");
+            assertThat("Response status",resp,containsString("HTTP/1.1 500 Server Error"));
+            assertThat("Response",resp,containsString(FooRuntimeException.class.getName()));
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
index 53b5efc..66e03ec 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletIOTest.java
@@ -18,6 +18,10 @@
 
 package org.eclipse.jetty.servlet;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -46,6 +50,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.DebugListener;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.Server;
@@ -57,10 +62,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.assertEquals;
-
-// TODO need  these on SPDY as well!
+// TODO need  these on HTTP2 as well!
 public class AsyncServletIOTest 
 {    
     private static final Logger LOG = Log.getLogger(AsyncServletIOTest.class);
@@ -82,6 +84,7 @@
         _server.setConnectors(new Connector[]{ _connector });
         ServletContextHandler context = new ServletContextHandler();
         context.setContextPath("/ctx");
+        context.addEventListener(new DebugListener());
         _server.setHandler(context);
         _servletHandler=context.getServletHandler();
         
@@ -223,7 +226,8 @@
         .append("Host: localhost\r\n")
         .append("Content-Type: text/plain\r\n")
         .append("Content-Length: 10\r\n")
-        .append("\r\n");
+        .append("\r\n")
+        .append("0");
         
         int port=_port;
         try (Socket socket = new Socket("localhost",port))
@@ -403,19 +407,18 @@
                         if (!onDataAvailable.compareAndSet(false,true))
                             throw new IllegalStateException();
                         
-                        // System.err.println("ODA");
+                        //System.err.println("ODA");
                         while (in.isReady() && !in.isFinished())
                         {
                             _oda.incrementAndGet();
                             int len=in.read(_buf);
-                            // System.err.println("read "+len);
+                            //System.err.println("read "+len);
                             if (len>0)
                                 _read.addAndGet(len);
                         }
 
                         if (!onDataAvailable.compareAndSet(true,false))
                             throw new IllegalStateException();
-                        
                     }
                     
                     @Override
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
index b5ded58..da9b9f9 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.servlet;
 
-import static org.junit.Assert.assertEquals;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.Socket;
@@ -28,6 +26,9 @@
 import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
@@ -43,6 +44,8 @@
 import javax.servlet.http.HttpServletResponseWrapper;
 
 import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.DebugListener;
+import org.eclipse.jetty.server.QuietServletException;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.RequestLog;
 import org.eclipse.jetty.server.Response;
@@ -60,6 +63,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+
 
 @RunWith(AdvancedRunner.class)
 public class AsyncServletTest
@@ -73,13 +82,15 @@
     protected List<String> _log;
     protected int _expectedLogs;
     protected String _expectedCode;
+    protected static List<String> __history=new CopyOnWriteArrayList<>();
+    protected static CountDownLatch __latch;
 
     @Before
     public void setUp() throws Exception
     {
         _connector = new ServerConnector(_server);
         _server.setConnectors(new Connector[]{ _connector });
-        
+
         _log=new ArrayList<>();
         RequestLog log=new Log();
         RequestLogHandler logHandler = new RequestLogHandler();
@@ -91,7 +102,8 @@
         ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
         context.setContextPath("/ctx");
         logHandler.setHandler(context);
-        
+        context.addEventListener(new DebugListener());
+
         _servletHandler=context.getServletHandler();
         ServletHolder holder=new ServletHolder(_servlet);
         holder.setAsyncSupported(true);
@@ -102,289 +114,383 @@
         _servletHandler.addServletWithMapping(new ServletHolder(new FwdServlet()),"/fwd/*");
         _server.start();
         _port=_connector.getLocalPort();
+        __history.clear();
+        __latch=new CountDownLatch(1);
     }
 
     @After
     public void tearDown() throws Exception
     {
+        _server.stop();
         assertEquals(_expectedLogs,_log.size());
         Assert.assertThat(_log.get(0), Matchers.containsString(_expectedCode));
-        _server.stop();
     }
 
     @Test
     public void testNormal() throws Exception
     {
         String response=process(null,null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-                "history: REQUEST /ctx/path/info\r\n"+
-                "history: initial\r\n",response);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+                "REQUEST /ctx/path/info",
+                "initial"));
         assertContains("NORMAL",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: onComplete",response);
+        assertFalse(__history.contains("onTimeout"));
+        assertFalse(__history.contains("onComplete"));
     }
 
     @Test
     public void testSleep() throws Exception
     {
         String response=process("sleep=200",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-                "history: REQUEST /ctx/path/info\r\n"+
-                "history: initial\r\n",response);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+                "REQUEST /ctx/path/info",
+                "initial"));
         assertContains("SLEPT",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: onComplete",response);
+        assertFalse(__history.contains("onTimeout"));
+        assertFalse(__history.contains("onComplete"));
     }
 
     @Test
-    public void testSuspend() throws Exception
+    public void testNonAsync() throws Exception
+    {
+        String response=process("",null);
+        Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial"));
+
+        assertContains("NORMAL",response);
+    }
+    
+    @Test
+    public void testStart() throws Exception
     {
         _expectedCode="500 ";
-        String response=process("suspend=200",null);
+        String response=process("start=200",null);
+        Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 500 Async Timeout"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onComplete"));
+
+        assertContains("ERROR DISPATCH: /ctx/path/info",response);
+    }
+
+    @Test
+    public void testStartOnTimeoutDispatch() throws Exception
+    {
+        String response=process("start=200&timeout=dispatch",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
+
+        assertContains("DISPATCHED",response);
+    }
+
+    @Test
+    public void testStartOnTimeoutError() throws Exception
+    {
+        _expectedCode="500 ";
+        String response=process("start=200&timeout=error",null);
+        assertThat(response,startsWith("HTTP/1.1 500 Server Error"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "error",
+            "onError",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onComplete"));
+
+        assertContains("ERROR DISPATCH",response);
+    }
+
+    @Test
+    public void testStartOnTimeoutErrorComplete() throws Exception
+    {
+        String response=process("start=200&timeout=error&error=complete",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "error",
+            "onError",
+            "complete",
+            "onComplete"));
+
+        assertContains("COMPLETED",response);
+    }
+
+    @Test
+    public void testStartOnTimeoutErrorDispatch() throws Exception
+    {
+        String response=process("start=200&timeout=error&error=dispatch",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "error",
+            "onError",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
+
+        assertContains("DISPATCHED",response);
+    }
+
+    @Test
+    public void testStartOnTimeoutComplete() throws Exception
+    {
+        String response=process("start=200&timeout=complete",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "complete",
+            "onComplete"));
+
+        assertContains("COMPLETED",response);
+    }
+
+    @Test
+    public void testStartWaitDispatch() throws Exception
+    {
+        String response=process("start=200&dispatch=10",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
+        assertFalse(__history.contains("onTimeout"));
+    }
+
+    @Test
+    public void testStartDispatch() throws Exception
+    {
+        String response=process("start=200&dispatch=0",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
+    }
+
+    @Test
+    public void testStartError() throws Exception
+    {
+        _expectedCode="500 ";
+        String response=process("start=200&throw=1",null);
+        assertThat(response,startsWith("HTTP/1.1 500 Server Error"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onError",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onComplete"));
+        assertContains("ERROR DISPATCH: /ctx/path/info",response);
+    }
+
+    @Test
+    public void testStartWaitComplete() throws Exception
+    {
+        String response=process("start=200&complete=50",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "complete",
+            "onComplete"));
+        assertContains("COMPLETED",response);
+        assertFalse(__history.contains("onTimeout"));
+        assertFalse(__history.contains("!initial"));
+    }
+
+    @Test
+    public void testStartComplete() throws Exception
+    {
+        String response=process("start=200&complete=0",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "complete",
+            "onComplete"));
+        assertContains("COMPLETED",response);
+        assertFalse(__history.contains("onTimeout"));
+        assertFalse(__history.contains("!initial"));
+    }
+
+    @Test
+    public void testStartWaitDispatchStartWaitDispatch() throws Exception
+    {
+        String response=process("start=1000&dispatch=10&start2=1000&dispatch2=10",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
+        assertContains("DISPATCHED",response);
+    }
+
+    @Test
+    public void testStartWaitDispatchStartComplete() throws Exception
+    {
+        String response=process("start=1000&dispatch=10&start2=1000&complete2=10",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "complete",
+            "onComplete"));
+        assertContains("COMPLETED",response);
+    }
+
+    @Test
+    public void testStartWaitDispatchStart() throws Exception
+    {
+        _expectedCode="500 ";
+        String response=process("start=1000&dispatch=10&start2=10",null);
         assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-
-        assertContains("ERROR: /ctx/path/info",response);
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onComplete"));
+        assertContains("ERROR DISPATCH: /ctx/path/info",response);
     }
 
     @Test
-    public void testSuspendOnTimeoutDispatch() throws Exception
+    public void testStartTimeoutStartDispatch() throws Exception
     {
-        String response=process("suspend=200&timeout=dispatch",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: dispatch\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-
+        String response=process("start=10&start2=1000&dispatch2=10",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
 
     @Test
-    public void testSuspendOnTimeoutComplete() throws Exception
+    public void testStartTimeoutStartComplete() throws Exception
     {
-        String response=process("suspend=200&timeout=complete",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: complete\r\n"+
-            "history: onComplete\r\n",response);
-
+        String response=process("start=10&start2=1000&complete2=10",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "complete",
+            "onComplete"));
         assertContains("COMPLETED",response);
     }
 
     @Test
-    public void testSuspendWaitResume() throws Exception
-    {
-        String response=process("suspend=200&resume=10",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertNotContains("history: onTimeout",response);
-    }
-
-    @Test
-    public void testSuspendResume() throws Exception
-    {
-        String response=process("suspend=200&resume=0",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("history: onComplete",response);
-    }
-
-    @Test
-    public void testSuspendWaitComplete() throws Exception
-    {
-        String response=process("suspend=200&complete=50",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: complete\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("COMPLETED",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: !initial",response);
-    }
-
-    @Test
-    public void testSuspendComplete() throws Exception
-    {
-        String response=process("suspend=200&complete=0",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: complete\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("COMPLETED",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: !initial",response);
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspendWaitResume() throws Exception
-    {
-        String response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("DISPATCHED",response);
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspendComplete() throws Exception
-    {
-        String response=process("suspend=1000&resume=10&suspend2=1000&complete2=10",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: complete\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("COMPLETED",response);
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspend() throws Exception
+    public void testStartTimeoutStart() throws Exception
     {
         _expectedCode="500 ";
-        String response=process("suspend=1000&resume=10&suspend2=10",null);
-        assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("ERROR: /ctx/path/info",response);
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspendResume() throws Exception
-    {
-        String response=process("suspend=10&suspend2=1000&resume2=10",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("DISPATCHED",response);
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspendComplete() throws Exception
-    {
-        String response=process("suspend=10&suspend2=1000&complete2=10",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: complete\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("COMPLETED",response);
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspend() throws Exception
-    {
-        _expectedCode="500 ";
-        String response=process("suspend=10&suspend2=10",null);
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: suspend\r\n"+
-            "history: onTimeout\r\n"+
-            "history: ERROR /ctx/path/info\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
-        assertContains("ERROR: /ctx/path/info",response);
+        String response=process("start=10&start2=10",null);
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onStartAsync",
+            "start",
+            "onTimeout",
+            "ERROR /ctx/path/info",
+            "!initial",
+            "onComplete"));
+        assertContains("ERROR DISPATCH: /ctx/path/info",response);
     }
 
     @Test
     public void testWrapStartDispatch() throws Exception
     {
-        String response=process("wrap=true&suspend=200&resume=20",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path/info\r\n"+
-            "history: wrapped REQ RSP\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("wrap=true&start=200&dispatch=20",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path/info",
+            "wrapped REQ RSP",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
 
@@ -392,127 +498,122 @@
     @Test
     public void testStartDispatchEncodedPath() throws Exception
     {
-        String response=process("suspend=200&resume=20&path=/p%20th3",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: REQUEST /ctx/path/info\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/p%20th3\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("start=200&dispatch=20&path=/p%20th3",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "REQUEST /ctx/path/info",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/p%20th3",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
-    
-    
+
+
     @Test
     public void testFwdStartDispatch() throws Exception
     {
-        String response=process("fwd","suspend=200&resume=20",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: FWD REQUEST /ctx/fwd/info\r\n"+
-            "history: FORWARD /ctx/path1\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: FWD ASYNC /ctx/fwd/info\r\n"+
-            "history: FORWARD /ctx/path1\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("fwd","start=200&dispatch=20",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "FWD REQUEST /ctx/fwd/info",
+            "FORWARD /ctx/path1",
+            "initial",
+            "start",
+            "dispatch",
+            "FWD ASYNC /ctx/fwd/info",
+            "FORWARD /ctx/path1",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
-    
+
     @Test
     public void testFwdStartDispatchPath() throws Exception
     {
-        String response=process("fwd","suspend=200&resume=20&path=/path2",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: FWD REQUEST /ctx/fwd/info\r\n"+
-            "history: FORWARD /ctx/path1\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path2\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("fwd","start=200&dispatch=20&path=/path2",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "FWD REQUEST /ctx/fwd/info",
+            "FORWARD /ctx/path1",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path2",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
 
     @Test
     public void testFwdWrapStartDispatch() throws Exception
     {
-        String response=process("fwd","wrap=true&suspend=200&resume=20",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: FWD REQUEST /ctx/fwd/info\r\n"+
-            "history: FORWARD /ctx/path1\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path1\r\n"+
-            "history: wrapped REQ RSP\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("fwd","wrap=true&start=200&dispatch=20",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "FWD REQUEST /ctx/fwd/info",
+            "FORWARD /ctx/path1",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path1",
+            "wrapped REQ RSP",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
-    
+
     @Test
     public void testFwdWrapStartDispatchPath() throws Exception
     {
-        String response=process("fwd","wrap=true&suspend=200&resume=20&path=/path2",null);
-        assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-        assertContains(
-            "history: FWD REQUEST /ctx/fwd/info\r\n"+
-            "history: FORWARD /ctx/path1\r\n"+
-            "history: initial\r\n"+
-            "history: suspend\r\n"+
-            "history: resume\r\n"+
-            "history: ASYNC /ctx/path2\r\n"+
-            "history: wrapped REQ RSP\r\n"+
-            "history: !initial\r\n"+
-            "history: onComplete\r\n",response);
+        String response=process("fwd","wrap=true&start=200&dispatch=20&path=/path2",null);
+        assertThat(response,startsWith("HTTP/1.1 200 OK"));
+        assertThat(__history,contains(
+            "FWD REQUEST /ctx/fwd/info",
+            "FORWARD /ctx/path1",
+            "initial",
+            "start",
+            "dispatch",
+            "ASYNC /ctx/path2",
+            "wrapped REQ RSP",
+            "!initial",
+            "onComplete"));
         assertContains("DISPATCHED",response);
     }
-    
-    
+
+
     @Test
     public void testAsyncRead() throws Exception
     {
-        _expectedLogs=2;
-        String header="GET /ctx/path/info?suspend=2000&resume=1500 HTTP/1.1\r\n"+
+        String header="GET /ctx/path/info?start=2000&dispatch=1500 HTTP/1.1\r\n"+
             "Host: localhost\r\n"+
             "Content-Length: 10\r\n"+
-            "\r\n";
-        String body="12345678\r\n";
-        String close="GET /ctx/path/info HTTP/1.1\r\n"+
-            "Host: localhost\r\n"+
             "Connection: close\r\n"+
             "\r\n";
+        String body="12345678\r\n";
 
         try (Socket socket = new Socket("localhost",_port))
         {
             socket.setSoTimeout(10000);
             socket.getOutputStream().write(header.getBytes(StandardCharsets.ISO_8859_1));
-            Thread.sleep(500);
             socket.getOutputStream().write(body.getBytes(StandardCharsets.ISO_8859_1),0,2);
             Thread.sleep(500);
             socket.getOutputStream().write(body.getBytes(StandardCharsets.ISO_8859_1),2,8);
-            socket.getOutputStream().write(close.getBytes(StandardCharsets.ISO_8859_1));
 
             String response = IO.toString(socket.getInputStream());
-            assertEquals("HTTP/1.1 200 OK",response.substring(0,15));
-            assertContains(
-                "history: REQUEST /ctx/path/info\r\n"+
-                "history: initial\r\n"+
-                "history: suspend\r\n"+
-                "history: async-read=10\r\n"+
-                "history: resume\r\n"+
-                "history: ASYNC /ctx/path/info\r\n"+
-                "history: !initial\r\n"+
-                "history: onComplete\r\n",response);
+            __latch.await(1,TimeUnit.SECONDS);
+            assertThat(response,startsWith("HTTP/1.1 200 OK"));
+            assertThat(__history,contains(
+                "REQUEST /ctx/path/info",
+                "initial",
+                "start",
+                "async-read=10",
+                "dispatch",
+                "ASYNC /ctx/path/info",
+                "!initial",
+                "onComplete"));
         }
     }
 
@@ -520,7 +621,7 @@
     {
         return process("path",query,content);
     }
-    
+
     public synchronized String process(String path,String query,String content) throws Exception
     {
         String request = "GET /ctx/"+path+"/info";
@@ -543,7 +644,10 @@
         {
             socket.setSoTimeout(1000000);
             socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
-            return IO.toString(socket.getInputStream());
+            socket.getOutputStream().flush();
+            String response = IO.toString(socket.getInputStream());
+            __latch.await(1,TimeUnit.SECONDS);
+            return response;
         }
         catch(Exception e)
         {
@@ -551,6 +655,7 @@
             e.printStackTrace();
             throw e;
         }
+        
     }
 
     protected void assertContains(String content,String response)
@@ -568,13 +673,13 @@
         @Override
         public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
         {
-            response.addHeader("history","FWD "+request.getDispatcherType()+" "+request.getRequestURI());
+            __history.add("FWD "+request.getDispatcherType()+" "+request.getRequestURI());
             if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
-                response.addHeader("history","wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":""));
+                __history.add("wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":""));
             request.getServletContext().getRequestDispatcher("/path1").forward(request,response);
         }
     }
-    
+
     private static class AsyncServlet extends HttpServlet
     {
         private static final long serialVersionUID = -8161977157098646562L;
@@ -593,36 +698,36 @@
             {
                 // ignored
             }
-            
+
             // System.err.println(request.getDispatcherType()+" "+request.getRequestURI());
-            response.addHeader("history",request.getDispatcherType()+" "+request.getRequestURI());
+            __history.add(request.getDispatcherType()+" "+request.getRequestURI());
             if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
-                response.addHeader("history","wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":""));
-                
+                __history.add("wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":""));
+
             boolean wrap="true".equals(request.getParameter("wrap"));
             int read_before=0;
             long sleep_for=-1;
-            long suspend_for=-1;
-            long suspend2_for=-1;
-            long resume_after=-1;
-            long resume2_after=-1;
+            long start_for=-1;
+            long start2_for=-1;
+            long dispatch_after=-1;
+            long dispatch2_after=-1;
             long complete_after=-1;
             long complete2_after=-1;
 
-            
+
             if (request.getParameter("read")!=null)
                 read_before=Integer.parseInt(request.getParameter("read"));
             if (request.getParameter("sleep")!=null)
                 sleep_for=Integer.parseInt(request.getParameter("sleep"));
-            if (request.getParameter("suspend")!=null)
-                suspend_for=Integer.parseInt(request.getParameter("suspend"));
-            if (request.getParameter("suspend2")!=null)
-                suspend2_for=Integer.parseInt(request.getParameter("suspend2"));
-            if (request.getParameter("resume")!=null)
-                resume_after=Integer.parseInt(request.getParameter("resume"));
+            if (request.getParameter("start")!=null)
+                start_for=Integer.parseInt(request.getParameter("start"));
+            if (request.getParameter("start2")!=null)
+                start2_for=Integer.parseInt(request.getParameter("start2"));
+            if (request.getParameter("dispatch")!=null)
+                dispatch_after=Integer.parseInt(request.getParameter("dispatch"));
             final String path=request.getParameter("path");
-            if (request.getParameter("resume2")!=null)
-                resume2_after=Integer.parseInt(request.getParameter("resume2"));
+            if (request.getParameter("dispatch2")!=null)
+                dispatch2_after=Integer.parseInt(request.getParameter("dispatch2"));
             if (request.getParameter("complete")!=null)
                 complete_after=Integer.parseInt(request.getParameter("complete"));
             if (request.getParameter("complete2")!=null)
@@ -631,7 +736,7 @@
             if (request.getAttribute("State")==null)
             {
                 request.setAttribute("State",new Integer(1));
-                response.addHeader("history","initial");
+                __history.add("initial");
                 if (read_before>0)
                 {
                     byte[] buf=new byte[read_before];
@@ -659,7 +764,7 @@
                                 while(b!=-1)
                                     if((b=in.read())>=0)
                                         c++;
-                                response.addHeader("history","async-read="+c);
+                                __history.add("async-read="+c);
                             }
                             catch(Exception e)
                             {
@@ -669,13 +774,16 @@
                     }.start();
                 }
 
-                if (suspend_for>=0)
+                if (start_for>=0)
                 {
                     final AsyncContext async=wrap?request.startAsync(new HttpServletRequestWrapper(request),new HttpServletResponseWrapper(response)):request.startAsync();
-                    if (suspend_for>0)
-                        async.setTimeout(suspend_for);
+                    if (start_for>0)
+                        async.setTimeout(start_for);
                     async.addListener(__listener);
-                    response.addHeader("history","suspend");
+                    __history.add("start");
+
+                    if ("1".equals(request.getParameter("throw")))
+                        throw new QuietServletException(new Exception("test throw in async 1"));
 
                     if (complete_after>0)
                     {
@@ -688,7 +796,7 @@
                                 {
                                     response.setStatus(200);
                                     response.getOutputStream().println("COMPLETED\n");
-                                    response.addHeader("history","complete");
+                                    __history.add("complete");
                                     async.complete();
                                 }
                                 catch(Exception e)
@@ -706,18 +814,18 @@
                     {
                         response.setStatus(200);
                         response.getOutputStream().println("COMPLETED\n");
-                        response.addHeader("history","complete");
+                        __history.add("complete");
                         async.complete();
                     }
-                    else if (resume_after>0)
+                    else if (dispatch_after>0)
                     {
-                        TimerTask resume = new TimerTask()
+                        TimerTask dispatch = new TimerTask()
                         {
                             @Override
                             public void run()
                             {
-                                ((HttpServletResponse)async.getResponse()).addHeader("history","resume");
-                                if (path!=null)             
+                                __history.add("dispatch");
+                                if (path!=null)
                                 {
                                     int q=path.indexOf('?');
                                     String uriInContext=(q>=0)
@@ -731,13 +839,13 @@
                         };
                         synchronized (_timer)
                         {
-                            _timer.schedule(resume,resume_after);
+                            _timer.schedule(dispatch,dispatch_after);
                         }
                     }
-                    else if (resume_after==0)
+                    else if (dispatch_after==0)
                     {
-                        ((HttpServletResponse)async.getResponse()).addHeader("history","resume");
-                        if (path!=null)             
+                        __history.add("dispatch");
+                        if (path!=null)
                             async.dispatch(path);
                         else
                             async.dispatch();
@@ -765,20 +873,22 @@
             }
             else
             {
-                response.addHeader("history","!initial");
+                __history.add("!initial");
 
-                if (suspend2_for>=0 && request.getAttribute("2nd")==null)
+                if (start2_for>=0 && request.getAttribute("2nd")==null)
                 {
                     final AsyncContext async=wrap?request.startAsync(new HttpServletRequestWrapper(request),new HttpServletResponseWrapper(response)):request.startAsync();
                     async.addListener(__listener);
                     request.setAttribute("2nd","cycle");
 
-                    if (suspend2_for>0)
+                    if (start2_for>0)
                     {
-                        async.setTimeout(suspend2_for);
+                        async.setTimeout(start2_for);
                     }
-                    // continuation.addContinuationListener(__listener);
-                    response.addHeader("history","suspend");
+                    __history.add("start");
+
+                    if ("2".equals(request.getParameter("throw")))
+                        throw new QuietServletException(new Exception("test throw in async 2"));
 
                     if (complete2_after>0)
                     {
@@ -791,7 +901,7 @@
                                 {
                                     response.setStatus(200);
                                     response.getOutputStream().println("COMPLETED\n");
-                                    response.addHeader("history","complete");
+                                    __history.add("complete");
                                     async.complete();
                                 }
                                 catch(Exception e)
@@ -809,34 +919,34 @@
                     {
                         response.setStatus(200);
                         response.getOutputStream().println("COMPLETED\n");
-                        response.addHeader("history","complete");
+                        __history.add("complete");
                         async.complete();
                     }
-                    else if (resume2_after>0)
+                    else if (dispatch2_after>0)
                     {
-                        TimerTask resume = new TimerTask()
+                        TimerTask dispatch = new TimerTask()
                         {
                             @Override
                             public void run()
                             {
-                                response.addHeader("history","resume");
+                                __history.add("dispatch");
                                 async.dispatch();
                             }
                         };
                         synchronized (_timer)
                         {
-                            _timer.schedule(resume,resume2_after);
+                            _timer.schedule(dispatch,dispatch2_after);
                         }
                     }
-                    else if (resume2_after==0)
+                    else if (dispatch2_after==0)
                     {
-                        response.addHeader("history","dispatch");
+                        __history.add("dispatch");
                         async.dispatch();
                     }
                 }
                 else if(request.getDispatcherType()==DispatcherType.ERROR)
                 {
-                    response.getOutputStream().println("ERROR: "+request.getContextPath()+request.getServletPath()+request.getPathInfo());
+                    response.getOutputStream().println("ERROR DISPATCH: "+request.getContextPath()+request.getServletPath()+request.getPathInfo());
                 }
                 else
                 {
@@ -853,17 +963,25 @@
         @Override
         public void onTimeout(AsyncEvent event) throws IOException
         {
-            ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onTimeout");
+            __history.add("onTimeout");
             String action=event.getSuppliedRequest().getParameter("timeout");
             if (action!=null)
             {
-                ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history",action);
-                if ("dispatch".equals(action))
-                    event.getAsyncContext().dispatch();
-                if ("complete".equals(action))
+                __history.add(action);
+
+                switch(action)
                 {
-                    event.getSuppliedResponse().getOutputStream().println("COMPLETED\n");
-                    event.getAsyncContext().complete();
+                    case "dispatch":
+                        event.getAsyncContext().dispatch();
+                        break;
+
+                    case "complete":
+                        event.getSuppliedResponse().getOutputStream().println("COMPLETED\n");
+                        event.getAsyncContext().complete();
+                        break;
+
+                    case "error":
+                        throw new RuntimeException("error in onTimeout");
                 }
             }
         }
@@ -871,17 +989,37 @@
         @Override
         public void onStartAsync(AsyncEvent event) throws IOException
         {
+            __history.add("onStartAsync");
         }
 
         @Override
         public void onError(AsyncEvent event) throws IOException
         {
+            __history.add("onError");
+            String action=event.getSuppliedRequest().getParameter("error");
+            if (action!=null)
+            {
+                __history.add(action);
+
+                switch(action)
+                {
+                    case "dispatch":
+                        event.getAsyncContext().dispatch();
+                        break;
+
+                    case "complete":
+                        event.getSuppliedResponse().getOutputStream().println("COMPLETED\n");
+                        event.getAsyncContext().complete();
+                        break;
+                }
+            }
         }
 
         @Override
         public void onComplete(AsyncEvent event) throws IOException
         {
-            ((HttpServletResponse)event.getSuppliedResponse()).addHeader("history","onComplete");
+            __history.add("onComplete");
+            __latch.countDown();
         }
     };
 
@@ -889,8 +1027,10 @@
     {
         @Override
         public void log(Request request, Response response)
-        {            
-            _log.add(response.getStatus()+" "+response.getContentCount()+" "+request.getRequestURI());
+        {
+            int status = response.getCommittedMetaData().getStatus();
+            long written = response.getHttpChannel().getBytesWritten();
+            _log.add(status+" "+written+" "+request.getRequestURI());
         }
     }
 }
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
index 978988a..7ec130b 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
@@ -23,8 +23,10 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.EnumSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -38,15 +40,18 @@
 import javax.servlet.ServletResponse;
 
 import org.eclipse.jetty.http.DateGenerator;
+import org.eclipse.jetty.http.HttpContent;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.ResourceContentFactory;
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
 import org.eclipse.jetty.toolchain.test.FS;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.toolchain.test.OS;
 import org.eclipse.jetty.toolchain.test.TestingDir;
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.resource.Resource;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
@@ -99,7 +104,7 @@
         testdir.ensureEmpty();
 
         /* create some content in the docroot */
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         assertTrue(resBase.mkdirs());
         assertTrue(new File(resBase, "one").mkdir());
         assertTrue(new File(resBase, "two").mkdir());
@@ -131,7 +136,7 @@
         testdir.ensureEmpty();
 
         /* create some content in the docroot */
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         assertTrue(new File(resBase, "one").mkdir());
         assertTrue(new File(resBase, "two").mkdir());
@@ -154,14 +159,6 @@
 
         String response = connector.getResponses(req1.toString());
 
-        assertResponseContains("/one/", response);
-        assertResponseContains("/two/", response);
-        assertResponseContains("/three/", response);
-        if (!OS.IS_WINDOWS)
-        {
-            assertResponseContains("/f%3F%3Fr", response);
-        }
-
         assertResponseNotContains("<script>", response);
     }
 
@@ -176,7 +173,7 @@
         testdir.ensureEmpty();
 
         /* create some content in the docroot */
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         assertTrue(resBase.mkdirs());
         File wackyDir = new File(resBase, "dir;"); // this should not be double-encoded.
         assertTrue(wackyDir.mkdirs());
@@ -228,7 +225,7 @@
         testdir.ensureEmpty();
 
         /* create some content in the docroot */
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         assertTrue(resBase.mkdirs());
 
         File index = new File(resBase, "index.html");
@@ -328,7 +325,7 @@
     public void testWelcome() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File inde = new File(resBase, "index.htm");
         File index = new File(resBase, "index.html");
@@ -372,7 +369,7 @@
     public void testWelcomeServlet() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File inde = new File(resBase, "index.htm");
         File index = new File(resBase, "index.html");
@@ -417,13 +414,18 @@
     }
 
     @Test
-    public void testResourceBase() throws Exception
+    public void testSymLinks() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
-        File foobar = new File(resBase, "foobar.txt");
-        File link = new File(resBase, "link.txt");
+        File dir = new File(resBase,"dir");
+        File dirLink = new File(resBase,"dirlink");
+        File dirRLink = new File(resBase,"dirrlink");
+        FS.ensureDirExists(dir);
+        File foobar = new File(dir, "foobar.txt");
+        File link = new File(dir, "link.txt");
+        File rLink = new File(dir,"rlink.txt");
         createFile(foobar, "Foo Bar");
 
         String resBasePath = resBase.getAbsolutePath();
@@ -434,18 +436,43 @@
 
         String response;
 
-        response = connector.getResponses("GET /context/foobar.txt HTTP/1.0\r\n\r\n");
+        response = connector.getResponses("GET /context/dir/foobar.txt HTTP/1.0\r\n\r\n");
         assertResponseContains("Foo Bar", response);
 
         if (!OS.IS_WINDOWS)
         {
+            context.clearAliasChecks();
+            
+            Files.createSymbolicLink(dirLink.toPath(),dir.toPath());
+            Files.createSymbolicLink(dirRLink.toPath(),new File("dir").toPath());
             Files.createSymbolicLink(link.toPath(),foobar.toPath());
-            response = connector.getResponses("GET /context/link.txt HTTP/1.0\r\n\r\n");
+            Files.createSymbolicLink(rLink.toPath(),new File("foobar.txt").toPath());
+            response = connector.getResponses("GET /context/dir/link.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("404", response);
+            response = connector.getResponses("GET /context/dir/rlink.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("404", response);
+            response = connector.getResponses("GET /context/dirlink/foobar.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("404", response);
+            response = connector.getResponses("GET /context/dirrlink/foobar.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("404", response);
+            response = connector.getResponses("GET /context/dirlink/link.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("404", response);
+            response = connector.getResponses("GET /context/dirrlink/rlink.txt HTTP/1.0\r\n\r\n");
             assertResponseContains("404", response);
             
-            context.addAliasCheck(new ContextHandler.ApproveAliases());
+            context.addAliasCheck(new AllowSymLinkAliasChecker());
             
-            response = connector.getResponses("GET /context/link.txt HTTP/1.0\r\n\r\n");
+            response = connector.getResponses("GET /context/dir/link.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("Foo Bar", response);
+            response = connector.getResponses("GET /context/dir/rlink.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("Foo Bar", response);
+            response = connector.getResponses("GET /context/dirlink/foobar.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("Foo Bar", response);
+            response = connector.getResponses("GET /context/dirrlink/foobar.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("Foo Bar", response);
+            response = connector.getResponses("GET /context/dirlink/link.txt HTTP/1.0\r\n\r\n");
+            assertResponseContains("Foo Bar", response);
+            response = connector.getResponses("GET /context/dirrlink/link.txt HTTP/1.0\r\n\r\n");
             assertResponseContains("Foo Bar", response);
         }
     }
@@ -454,7 +481,7 @@
     public void testWelcomeExactServlet() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File inde = new File(resBase, "index.htm");
         File index = new File(resBase, "index.html");
@@ -499,10 +526,49 @@
     }
 
     @Test
+    public void testDirectFromResourceHttpContent() throws Exception
+    {
+        if (!OS.IS_LINUX)
+            return;
+        
+        testdir.ensureEmpty();
+        File resBase = testdir.getPathFile("docroot").toFile();
+        FS.ensureDirExists(resBase);
+        context.setBaseResource(Resource.newResource(resBase));
+        
+        File index = new File(resBase, "index.html");
+        createFile(index, "<h1>Hello World</h1>");
+
+        ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
+        defholder.setInitParameter("dirAllowed", "true");
+        defholder.setInitParameter("redirectWelcome", "false");
+        defholder.setInitParameter("useFileMappedBuffer", "true");
+        defholder.setInitParameter("welcomeServlets", "exact");
+        defholder.setInitParameter("gzip", "false");
+        defholder.setInitParameter("resourceCache","resourceCache");
+
+        String response;
+
+        response = connector.getResponses("GET /context/index.html HTTP/1.0\r\n\r\n");
+        assertResponseContains("<h1>Hello World</h1>", response);
+        
+        ResourceContentFactory factory = (ResourceContentFactory)context.getServletContext().getAttribute("resourceCache");
+        
+        HttpContent content = factory.getContent("/index.html",200);
+        ByteBuffer buffer = content.getDirectBuffer();
+        Assert.assertTrue(buffer.isDirect());        
+        content = factory.getContent("/index.html",5);
+        buffer = content.getDirectBuffer();
+        Assert.assertTrue(buffer==null);        
+    }
+    
+    
+    
+    @Test
     public void testRangeRequests() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File data = new File(resBase, "data.txt");
         createFile(data, "01234567890123456789012345678901234567890123456789012345678901234567890123456789");
@@ -649,7 +715,7 @@
     public void testFiltered() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File file0 = new File(resBase, "data0.txt");
         createFile(file0, "Hello Text 0");
@@ -667,16 +733,21 @@
         assertResponseContains("Content-Length: 12", response);
         assertResponseNotContains("Extra Info", response);
 
+        server.stop();
         context.addFilter(OutputFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
+        server.start();
+        
         response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\n\r\n");
         assertResponseContains("Content-Length: 2", response); // 20 something long
         assertResponseContains("Extra Info", response);
         assertResponseNotContains("Content-Length: 12", response);
 
+        server.stop();
         context.getServletHandler().setFilterMappings(new FilterMapping[]{});
         context.getServletHandler().setFilters(new FilterHolder[]{});
-
         context.addFilter(WriterFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
+        server.start();
+        
         response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\n\r\n");
         assertResponseContains("Content-Length: 2", response); // 20 something long
         assertResponseContains("Extra Info", response);
@@ -688,7 +759,7 @@
     public void testGzip() throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File file0 = new File(resBase, "data0.txt");
         createFile(file0, "Hello Text 0");
@@ -702,23 +773,132 @@
         defholder.setInitParameter("redirectWelcome", "false");
         defholder.setInitParameter("welcomeServlets", "false");
         defholder.setInitParameter("gzip", "true");
+        defholder.setInitParameter("etags", "true");
         defholder.setInitParameter("resourceBase", resBasePath);
 
         String response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\n\r\n");
         assertResponseContains("Content-Length: 12", response);
+        assertResponseContains("Content-Type: text/plain",response);
         assertResponseContains("Hello Text 0",response);
         assertResponseContains("Vary: Accept-Encoding",response);
+        assertResponseContains("ETag: ",response);
         assertResponseNotContains("Content-Encoding: gzip",response);
+        int e=response.indexOf("ETag: ");
+        String etag = response.substring(e+6,response.indexOf('"',e+11)+1);
+        String etag_gzip = etag.substring(0,etag.length()-1)+"--gzip\"";
         
         response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\n\r\n");
         assertResponseContains("Content-Length: 9", response);
         assertResponseContains("fake gzip",response);
+        assertResponseContains("Content-Type: text/plain",response);
         assertResponseContains("Vary: Accept-Encoding",response);
         assertResponseContains("Content-Encoding: gzip",response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+        
+        response = connector.getResponses("GET /context/data0.txt.gz HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\n\r\n");
+        assertResponseContains("Content-Length: 9", response);
+        assertResponseContains("fake gzip",response);
+        assertResponseContains("Content-Type: application/gzip",response);
+        assertResponseNotContains("Vary: Accept-Encoding",response);
+        assertResponseNotContains("Content-Encoding: gzip",response);
+        assertResponseNotContains("ETag: "+etag_gzip,response);
+        assertResponseContains("ETag: ",response);   
+        
+        response = connector.getResponses("GET /context/data0.txt.gz HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: W/\"wobble\"\r\n\r\n");
+        assertResponseContains("Content-Length: 9", response);
+        assertResponseContains("fake gzip",response);
+        assertResponseContains("Content-Type: application/gzip",response);
+        assertResponseNotContains("Vary: Accept-Encoding",response);
+        assertResponseNotContains("Content-Encoding: gzip",response);
+        assertResponseNotContains("ETag: "+etag_gzip,response);
+        assertResponseContains("ETag: ",response);   
+        
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: "+etag_gzip+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: "+etag+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag,response);
+        
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: W/\"foobar\","+etag_gzip+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: W/\"foobar\","+etag+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag,response);
         
     }
 
+    @Test
+    public void testCachedGzip() throws Exception
+    {
+        testdir.ensureEmpty();
+        File resBase = testdir.getPathFile("docroot").toFile();                
+        FS.ensureDirExists(resBase);
+        File file0 = new File(resBase, "data0.txt");
+        createFile(file0, "Hello Text 0");
+        File file0gz = new File(resBase, "data0.txt.gz");
+        createFile(file0gz, "fake gzip");
 
+        String resBasePath = resBase.getAbsolutePath();
+
+        ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
+        defholder.setInitParameter("dirAllowed", "false");
+        defholder.setInitParameter("redirectWelcome", "false");
+        defholder.setInitParameter("welcomeServlets", "false");
+        defholder.setInitParameter("gzip", "true");
+        defholder.setInitParameter("etags", "true");
+        defholder.setInitParameter("resourceBase", resBasePath);
+        defholder.setInitParameter("maxCachedFiles", "1024");
+        defholder.setInitParameter("maxCachedFileSize", "200000000");
+        defholder.setInitParameter("maxCacheSize", "256000000"); 
+
+        String response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\n\r\n");
+        assertResponseContains("Content-Length: 12", response);
+        assertResponseContains("Content-Type: text/plain",response);
+        assertResponseContains("Hello Text 0",response);
+        assertResponseContains("Vary: Accept-Encoding",response);
+        assertResponseContains("ETag: ",response);
+        assertResponseNotContains("Content-Encoding: gzip",response);
+        int e=response.indexOf("ETag: ");
+        String etag = response.substring(e+6,response.indexOf('"',e+11)+1);
+        String etag_gzip = etag.substring(0,etag.length()-1)+"--gzip\"";
+        
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\n\r\n");
+        assertResponseContains("Content-Length: 9", response);
+        assertResponseContains("fake gzip",response);
+        assertResponseContains("Content-Type: text/plain",response);
+        assertResponseContains("Vary: Accept-Encoding",response);
+        assertResponseContains("Content-Encoding: gzip",response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+        
+        response = connector.getResponses("GET /context/data0.txt.gz HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\n\r\n");
+        assertResponseContains("Content-Length: 9", response);
+        assertResponseContains("fake gzip",response);
+        assertResponseContains("Content-Type: application/gzip",response);
+        assertResponseNotContains("Vary: Accept-Encoding",response);
+        assertResponseNotContains("Content-Encoding: gzip",response);
+        assertResponseNotContains("ETag: "+etag_gzip,response);
+        assertResponseContains("ETag: ",response);
+        
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: "+etag_gzip+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: "+etag+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag,response);
+        
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: W/\"foobar\","+etag_gzip+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag_gzip,response);
+
+        response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: W/\"foobar\","+etag+"\r\n\r\n");
+        assertResponseContains("304 Not Modified", response);
+        assertResponseContains("ETag: "+etag,response);
+    }
 
     @Test
     public void testIfModifiedSmall() throws Exception
@@ -735,7 +915,7 @@
     public void testIfModified(String content) throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File file = new File(resBase, "file.txt");
 
@@ -788,7 +968,7 @@
     public void testIfETag(String content) throws Exception
     {
         testdir.ensureEmpty();
-        File resBase = testdir.getFile("docroot");
+        File resBase = testdir.getPathFile("docroot").toFile();
         FS.ensureDirExists(resBase);
         File file = new File(resBase, "file.txt");
 
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
index 2359d16..bf1ff12 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
@@ -21,6 +21,9 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletException;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServlet;
@@ -35,13 +38,15 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+
+@SuppressWarnings("serial")
 public class DispatcherForwardTest
 {
     private Server server;
     private LocalConnector connector;
     private HttpServlet servlet1;
     private HttpServlet servlet2;
-    private List<Exception> failures = new ArrayList<>();
+    private List<Throwable> failures = new ArrayList<>();
 
     public void prepare() throws Exception
     {
@@ -57,9 +62,9 @@
     }
 
     @After
-    public void dispose() throws Exception
+    public void dispose() throws Throwable
     {
-        for (Exception failure : failures)
+        for (Throwable failure : failures)
             throw failure;
         server.stop();
     }
@@ -67,30 +72,38 @@
     // Replacement for Assert that allows to check failures after the response has been sent.
     private <S> void checkThat(S item, Matcher<S> matcher)
     {
-        if (!matcher.matches(item))
-            failures.add(new Exception());
+        try
+        {
+            Assert.assertThat(item,matcher);
+        }
+        catch(Throwable th)
+        {
+            failures.add(th);
+        }
     }
 
     @Test
     public void testQueryRetainedByForwardWithoutQuery() throws Exception
     {
-        // 1. request /one?a=1
+        // 1. request /one?a=1%20one
         // 1. forward /two
-        // 2. assert query => a=1
-        // 1. assert query => a=1
+        // 2. assert query => a=1 one
+        // 1. assert query => a=1 one
 
-        final String query1 = "a=1";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two").forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -98,8 +111,8 @@
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
             }
         };
 
@@ -111,6 +124,7 @@
                 "Connection: close\r\n" +
                 "\r\n";
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -122,21 +136,23 @@
         // 2. assert query => a=2
         // 1. assert query => a=1
 
-        final String query1 = "a=1&b=2";
-        final String query2 = "a=3";
-        final String query3 = "a=3&b=2";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one&b=2%20two";
+        final String query2 = "a=3%20three";
+        final String query3 = "a=3%20three&b=2%20two";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(), Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -144,9 +160,9 @@
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query3, Matchers.equalTo(req.getQueryString()));
-                checkThat("3", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query3));
+                checkThat(req.getParameter("a"),Matchers.equalTo("3 three"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
             }
         };
 
@@ -158,6 +174,7 @@
                 "Connection: close\r\n" +
                 "\r\n";
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -169,20 +186,22 @@
         // 2. assert query => a=1&b=2
         // 1. assert query => a=1
 
-        final String query1 = "a=1";
-        final String query2 = "b=2";
-        final String query3 = "b=2&a=1";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String query2 = "b=2%20two";
+        final String query3 = "b=2%20two&a=1%20one";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -190,9 +209,9 @@
             @Override
             protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query3, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query3));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
             }
         };
 
@@ -204,6 +223,7 @@
                 "Connection: close\r\n" +
                 "\r\n";
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -215,22 +235,24 @@
         // 2. assert query => a=1 + params => a=1,2
         // 1. assert query => a=1 + params => a=1,2
 
-        final String query1 = "a=1";
-        final String form = "a=2";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String form = "a=2%20two";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two").forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 String[] values = req.getParameterValues("a");
                 checkThat(values, Matchers.notNullValue());
                 checkThat(2, Matchers.equalTo(values.length));
-                checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
+                checkThat(values, Matchers.arrayContainingInAnyOrder("1 one", "2 two"));
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -238,11 +260,11 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 String[] values = req.getParameterValues("a");
                 checkThat(values, Matchers.notNullValue());
                 checkThat(2, Matchers.equalTo(values.length));
-                checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
+                checkThat(values, Matchers.arrayContainingInAnyOrder("1 one", "2 two"));
             }
         };
 
@@ -257,6 +279,7 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -268,23 +291,25 @@
         // 2. assert query => a=3 + params => a=3,2,1
         // 1. assert query => a=1 + params => a=1,2
 
-        final String query1 = "a=1";
-        final String query2 = "a=3";
-        final String form = "a=2";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String query2 = "a=3%20three";
+        final String form = "a=2%20two";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 String[] values = req.getParameterValues("a");
                 checkThat(values, Matchers.notNullValue());
                 checkThat(2, Matchers.equalTo(values.length));
-                checkThat(values, Matchers.arrayContainingInAnyOrder("1", "2"));
+                checkThat(values, Matchers.arrayContainingInAnyOrder("1 one", "2 two"));
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -292,11 +317,11 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query2, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query2));
                 String[] values = req.getParameterValues("a");
                 checkThat(values, Matchers.notNullValue());
                 checkThat(3, Matchers.equalTo(values.length));
-                checkThat(values, Matchers.arrayContainingInAnyOrder("3", "2", "1"));
+                checkThat(values, Matchers.arrayContainingInAnyOrder("3 three", "2 two", "1 one"));
             }
         };
 
@@ -311,6 +336,7 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -322,23 +348,25 @@
         // 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
         // 1. assert query => a=1 + params => a=1&b=2
 
-        final String query1 = "a=1";
-        final String query2 = "c=3";
-        final String query3 = "c=3&a=1";
-        final String form = "b=2";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String query2 = "c=3%20three";
+        final String query3 = "c=3%20three&a=1%20one";
+        final String form = "b=2%20two";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
                 checkThat(req.getParameter("c"), Matchers.nullValue());
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -346,10 +374,10 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query3, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
-                checkThat("3", Matchers.equalTo(req.getParameter("c")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query3));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
+                checkThat(req.getParameter("c"),Matchers.equalTo("3 three"));
             }
         };
 
@@ -364,6 +392,7 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
@@ -376,25 +405,27 @@
         // 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
         // 1. assert query => a=1 + params => a=1&b=2
 
-        final String query1 = "a=1";
-        final String query2 = "c=3";
-        final String query3 = "c=3&a=1";
-        final String form = "b=2";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String query2 = "c=3%20three";
+        final String query3 = "c=3%20three&a=1%20one";
+        final String form = "b=2%20two";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
                 checkThat(req.getParameter("c"), Matchers.nullValue());
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -402,10 +433,10 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query3, Matchers.equalTo(req.getQueryString()));
-                checkThat("1", Matchers.equalTo(req.getParameter("a")));
-                checkThat("2", Matchers.equalTo(req.getParameter("b")));
-                checkThat("3", Matchers.equalTo(req.getParameter("c")));
+                checkThat(req.getQueryString(),Matchers.equalTo(query3));
+                checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+                checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
+                checkThat(req.getParameter("c"),Matchers.equalTo("3 three"));
             }
         };
 
@@ -420,25 +451,28 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
     @Test
     public void testContentCanBeReadViaInputStreamAfterForwardWithoutQuery() throws Exception
     {
-        final String query1 = "a=1";
-        final String form = "c=3";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String form = "c=3%20three";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two").forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 checkThat(req.getParameter("c"), Matchers.nullValue());
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -446,7 +480,7 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 ServletInputStream input = req.getInputStream();
                 for (int i = 0; i < form.length(); ++i)
                     checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read()));
@@ -464,27 +498,30 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
     @Test
     public void testContentCanBeReadViaInputStreamAfterForwardWithQuery() throws Exception
     {
-        final String query1 = "a=1";
-        final String query2 = "b=2";
-        final String query3 = "b=2&a=1";
-        final String form = "c=3";
+        CountDownLatch latch = new CountDownLatch(1);
+        final String query1 = "a=1%20one";
+        final String query2 = "b=2%20two";
+        final String query3 = "b=2%20two&a=1%20one";
+        final String form = "c=3%20three";
         servlet1 = new HttpServlet()
         {
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
 
                 req.getRequestDispatcher("/two?" + query2).forward(req, resp);
 
-                checkThat(query1, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query1));
                 checkThat(req.getParameter("c"), Matchers.nullValue());
+                latch.countDown();
             }
         };
         servlet2 = new HttpServlet()
@@ -492,7 +529,7 @@
             @Override
             protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
             {
-                checkThat(query3, Matchers.equalTo(req.getQueryString()));
+                checkThat(req.getQueryString(),Matchers.equalTo(query3));
                 ServletInputStream input = req.getInputStream();
                 for (int i = 0; i < form.length(); ++i)
                     checkThat(form.charAt(i) & 0xFFFF, Matchers.equalTo(input.read()));
@@ -511,6 +548,7 @@
                 "\r\n" +
                 form;
         String response = connector.getResponses(request);
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
         Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
     }
 
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java
index a296478..8cfea6f 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java
@@ -18,11 +18,18 @@
 
 package org.eclipse.jetty.servlet;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
+
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -57,12 +64,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
 public class DispatcherTest
 {
     private Server _server;
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
new file mode 100644
index 0000000..4be7ff0
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java
@@ -0,0 +1,217 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.zip.GZIPInputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
+import org.eclipse.jetty.util.IO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class GzipHandlerTest
+{
+    private static String __content =
+        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
+        "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
+        "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
+        "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
+        "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
+        "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
+        "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
+        "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
+        "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
+        "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
+        "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
+        "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
+
+    private static String __icontent = "BEFORE"+__content+"AFTER";
+            
+    private Server _server;
+    private LocalConnector _connector;
+
+    @Before
+    public void init() throws Exception
+    {
+        _server = new Server();
+        _connector = new LocalConnector(_server);
+        _server.addConnector(_connector);
+
+        GzipHandler gzipHandler = new GzipHandler();
+
+        ServletContextHandler context = new ServletContextHandler(gzipHandler,"/ctx");
+        ServletHandler servlets = context.getServletHandler();
+        
+        _server.setHandler(gzipHandler);
+        gzipHandler.setHandler(context);
+        context.setHandler(servlets);
+        servlets.addServletWithMapping(TestServlet.class,"/content");
+        servlets.addServletWithMapping(ForwardServlet.class,"/forward");
+        servlets.addServletWithMapping(IncludeServlet.class,"/include");
+        
+        _server.start();
+    }
+    
+    public static class TestServlet extends HttpServlet
+    {
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
+        {
+            PrintWriter writer = response.getWriter();
+            writer.write(__content);
+        }
+    }
+
+    public static class ForwardServlet extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            getServletContext().getRequestDispatcher("/content").forward(request,response);
+        }
+    }
+
+    public static class IncludeServlet extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            response.getWriter().write("BEFORE");
+            getServletContext().getRequestDispatcher("/content").include(request,response);
+            response.getWriter().write("AFTER");
+        }
+    }
+
+    @After
+    public void destroy() throws Exception
+    {
+        _server.stop();
+        _server.join();
+    }
+
+    @Test
+    public void testGzipHandler() throws Exception
+    {
+        // generated and parsed test
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod("GET");
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("accept-encoding","gzip");
+        request.setURI("/ctx/content");
+
+        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
+
+        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
+        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
+        IO.copy(testIn,testOut);
+
+        assertEquals(__content, testOut.toString("UTF8"));
+
+    }
+    
+    @Test
+    public void testForwardGzipHandler() throws Exception
+    {
+        // generated and parsed test
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod("GET");
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("accept-encoding","gzip");
+        request.setURI("/ctx/forward");
+
+        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
+
+        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
+        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
+        IO.copy(testIn,testOut);
+
+        assertEquals(__content, testOut.toString("UTF8"));
+    }
+    
+    @Test
+    public void testIncludeGzipHandler() throws Exception
+    {
+        // generated and parsed test
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod("GET");
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("accept-encoding","gzip");
+        request.setURI("/ctx/include");
+
+        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
+        
+        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+
+        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
+        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
+        IO.copy(testIn,testOut);
+
+        assertEquals(__icontent, testOut.toString("UTF8"));
+    }
+    
+    @Test
+    public void testAddGetPaths()
+    {
+        GzipHandler gzip = new GzipHandler();
+        gzip.addIncludedPaths("/foo");
+        gzip.addIncludedPaths("^/bar.*$");
+        
+        String[] includedPaths = gzip.getIncludedPaths();
+        assertThat("Included Paths.size", includedPaths.length, is(2));
+        assertThat("Included Paths", Arrays.asList(includedPaths), contains("/foo","^/bar.*$"));
+    }
+}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/SSLAsyncIOServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/SSLAsyncIOServletTest.java
index c779203..68223e4 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/SSLAsyncIOServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/SSLAsyncIOServletTest.java
@@ -26,6 +26,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Random;
+
 import javax.servlet.AsyncContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletOutputStream;
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
index 67ef8a6..85525e8 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -48,8 +49,12 @@
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.handler.ResourceHandler;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
 import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.Decorator;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
@@ -172,6 +177,55 @@
         response = _connector.getResponses(request.toString());
         assertResponseContains("Hello World", response);
     }
+    
+    @Test
+    public void testHandlerBeforeServletHandler() throws Exception
+    {
+        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+        
+        HandlerWrapper extra = new HandlerWrapper();
+        
+        context.getSessionHandler().insertHandler(extra);
+        
+        context.addServlet(TestServlet.class,"/test");
+        context.setContextPath("/");
+        _server.setHandler(context);
+        _server.start();
+
+        StringBuffer request = new StringBuffer();
+        request.append("GET /test HTTP/1.0\n");
+        request.append("Host: localhost\n");
+        request.append("\n");
+
+        String response = _connector.getResponses(request.toString());
+        assertResponseContains("Test", response);
+        
+        assertEquals(extra,context.getSessionHandler().getHandler());
+    }
+    
+    @Test
+    public void testGzipHandlerOption() throws Exception
+    {
+        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS|ServletContextHandler.GZIP);
+        GzipHandler gzip = context.getGzipHandler();        
+        _server.start();
+        assertEquals(context.getSessionHandler(),context.getHandler());
+        assertEquals(gzip,context.getSessionHandler().getHandler());
+        assertEquals(context.getServletHandler(),gzip.getHandler());
+    }
+    
+    @Test
+    public void testGzipHandlerSet() throws Exception
+    {
+        ServletContextHandler context = new ServletContextHandler();
+        context.setSessionHandler(new SessionHandler());
+        context.setGzipHandler(new GzipHandler());
+        GzipHandler gzip = context.getGzipHandler();        
+        _server.start();
+        assertEquals(context.getSessionHandler(),context.getHandler());
+        assertEquals(gzip,context.getSessionHandler().getHandler());
+        assertEquals(context.getServletHandler(),gzip.getHandler());
+    }
 
     @Test
     public void testReplaceServletHandlerWithServlet() throws Exception
@@ -268,7 +322,7 @@
 
         ResourceHandler rh = new ResourceHandler();
 
-        servletContextHandler.setHandler(rh);    
+        servletContextHandler.insertHandler(rh);    
         assertEquals(shandler, servletContextHandler.getServletHandler());
         assertEquals(rh, servletContextHandler.getHandler());
         assertEquals(rh.getHandler(), shandler);
@@ -310,6 +364,61 @@
         Assert.assertThat(response, Matchers.containsString("404 Fell Through"));
         
     }
+    
+    /**
+     * Test behavior of legacy ServletContextHandler.Decorator, with
+     * new DecoratedObjectFactory class
+     * @throws Exception on test failure
+     */
+    @SuppressWarnings("deprecation")
+    @Test
+    public void testLegacyDecorator() throws Exception
+    {
+        ServletContextHandler context = new ServletContextHandler();
+        context.addDecorator(new DummyLegacyDecorator());
+        _server.setHandler(context);
+        
+        context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*");
+        _server.start();
+
+        String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n");
+        assertThat("Response status code", response, containsString("200 OK"));
+        
+        String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName());
+        assertThat("Has context attribute", response, containsString(expected));
+        
+        assertThat("Decorators size", response, containsString("Decorators.size = [2]"));
+        
+        expected = String.format("decorator[] = %s", DummyLegacyDecorator.class.getName());
+        assertThat("Specific Legacy Decorator", response, containsString(expected));
+    }
+    
+    /**
+     * Test behavior of new {@link org.eclipse.jetty.util.Decorator}, with
+     * new DecoratedObjectFactory class
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testUtilDecorator() throws Exception
+    {
+        ServletContextHandler context = new ServletContextHandler();
+        context.getObjectFactory().addDecorator(new DummyUtilDecorator());
+        _server.setHandler(context);
+        
+        context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*");
+        _server.start();
+
+        String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n");
+        assertThat("Response status code", response, containsString("200 OK"));
+        
+        String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName());
+        assertThat("Has context attribute", response, containsString(expected));
+        
+        assertThat("Decorators size", response, containsString("Decorators.size = [2]"));
+        
+        expected = String.format("decorator[] = %s", DummyUtilDecorator.class.getName());
+        assertThat("Specific Legacy Decorator", response, containsString(expected));
+    }
 
     private int assertResponseContains(String expected, String response)
     {
@@ -340,6 +449,66 @@
             writer.write("Hello World");
         }
     }
+    
+    public static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator
+    {
+        @Override
+        public <T> T decorate(T o)
+        {
+            return o;
+        }
+
+        @Override
+        public void destroy(Object o)
+        {
+        }
+    }
+    
+    public static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
+    {
+        @Override
+        public <T> T decorate(T o)
+        {
+            return o;
+        }
+
+        @Override
+        public void destroy(Object o)
+        {
+        }
+    }
+
+    public static class DecoratedObjectFactoryServlet extends HttpServlet
+    {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+        {
+            resp.setContentType("text/plain");
+            resp.setStatus(HttpServletResponse.SC_OK);
+            PrintWriter out = resp.getWriter();
+            
+            Object obj = req.getServletContext().getAttribute(DecoratedObjectFactory.ATTR);
+            out.printf("Attribute[%s] = %s%n",DecoratedObjectFactory.ATTR,obj.getClass().getName());
+            
+            if (obj instanceof DecoratedObjectFactory)
+            {
+                out.printf("Object is a DecoratedObjectFactory%n");
+                DecoratedObjectFactory objFactory = (DecoratedObjectFactory)obj;
+                List<Decorator> decorators = objFactory.getDecorators();
+                out.printf("Decorators.size = [%d]%n",decorators.size());
+                for (Decorator decorator : decorators)
+                {
+                    out.printf(" decorator[] = %s%n",decorator.getClass().getName());
+                }
+            }
+            else
+            {
+                out.printf("Object is NOT a DecoratedObjectFactory%n");
+            }
+        }
+    }
 
     public static class TestServlet extends HttpServlet
     {
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java
new file mode 100644
index 0000000..eb24406
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHolderTest.java
@@ -0,0 +1,55 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+public class ServletHolderTest {
+
+    @Test
+    public void testTransitiveCompareTo() throws Exception
+    {
+        // example of jsp-file referenced in web.xml
+        final ServletHolder one = new ServletHolder();
+        one.setInitOrder(-1);
+        one.setName("Login");
+        one.setClassName(null);
+
+        // example of pre-compiled jsp
+        final ServletHolder two = new ServletHolder();
+        two.setInitOrder(-1);
+        two.setName("org.my.package.jsp.WEB_002dINF.pages.precompiled_002dpage_jsp");
+        two.setClassName("org.my.package.jsp.WEB_002dINF.pages.precompiled_002dpage_jsp");
+
+        // example of servlet referenced in web.xml
+        final ServletHolder three = new ServletHolder();
+        three.setInitOrder(-1);
+        three.setName("Download");
+        three.setClassName("org.my.package.web.DownloadServlet");
+
+        // verify compareTo transitivity
+        Assert.assertTrue(one.compareTo(two) < 0);
+        Assert.assertTrue(two.compareTo(three) < 0);
+        Assert.assertTrue(one.compareTo(three) < 0);
+    }
+}
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletRequestLogTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletRequestLogTest.java
index d06fc74..0b50aac 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletRequestLogTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletRequestLogTest.java
@@ -18,8 +18,8 @@
 
 package org.eclipse.jetty.servlet;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -79,7 +79,8 @@
         @Override
         public void log(Request request, Response response)
         {
-            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getUri().toString(),request.getProtocol(),response.getStatus()));
+            int status = response.getCommittedMetaData().getStatus();
+            captured.add(String.format("%s %s %s %03d",request.getMethod(),request.getRequestURI(),request.getProtocol(),status));
         }
     }
     
@@ -298,6 +299,7 @@
      * Test a RequestLogHandler at the end of a HandlerCollection.
      * This handler chain is setup to look like Jetty versions up to 9.2. 
      * Default configuration.
+     * @throws Exception on test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection() throws Exception
@@ -382,6 +384,7 @@
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection.
      * and also with the default ErrorHandler as server bean in place.
+     * @throws Exception on test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection_ErrorHandler_ServerBean() throws Exception
@@ -469,6 +472,7 @@
     /**
      * Test a RequestLogHandler at the end of a HandlerCollection
      * using servlet specific error page mapping.
+     * @throws Exception on test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerCollection_SimpleErrorPageMapping() throws Exception
@@ -558,6 +562,7 @@
     
     /**
      * Test an alternate (proposed) setup for using RequestLogHandler in a wrapped style
+     * @throws Exception on test failure
      */
     @Test(timeout=4000)
     public void testLogHandlerWrapped() throws Exception
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletTester.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletTester.java
new file mode 100644
index 0000000..6b9d1b4
--- /dev/null
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletTester.java
@@ -0,0 +1,260 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.util.Attributes;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+
+public class ServletTester extends ContainerLifeCycle
+{
+    private static final Logger LOG = Log.getLogger(ServletTester.class);
+    
+    private final Server _server=new Server();
+    private final LocalConnector _connector=new LocalConnector(_server);
+    private final ServletContextHandler _context;
+    
+    public Server getServer()
+    {
+        return _server;
+    }
+    
+    public LocalConnector getConnector()
+    {
+        return _connector;
+    }
+    
+    public void setVirtualHosts(String[] vhosts)
+    {
+        _context.setVirtualHosts(vhosts);
+    }
+
+    public void addVirtualHosts(String[] virtualHosts)
+    {
+        _context.addVirtualHosts(virtualHosts);
+    }
+
+    public ServletHolder addServlet(String className, String pathSpec)
+    {
+        return _context.addServlet(className,pathSpec);
+    }
+
+    public ServletHolder addServlet(Class<? extends Servlet> servlet, String pathSpec)
+    {
+        return _context.addServlet(servlet,pathSpec);
+    }
+
+    public void addServlet(ServletHolder servlet, String pathSpec)
+    {
+        _context.addServlet(servlet,pathSpec);
+    }
+
+    public void addFilter(FilterHolder holder, String pathSpec, EnumSet<DispatcherType> dispatches)
+    {
+        _context.addFilter(holder,pathSpec,dispatches);
+    }
+
+    public FilterHolder addFilter(Class<? extends Filter> filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
+    {
+        return _context.addFilter(filterClass,pathSpec,dispatches);
+    }
+
+    public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet<DispatcherType> dispatches)
+    {
+        return _context.addFilter(filterClass,pathSpec,dispatches);
+    }
+
+    public Object getAttribute(String name)
+    {
+        return _context.getAttribute(name);
+    }
+
+    public Enumeration<String> getAttributeNames()
+    {
+        return _context.getAttributeNames();
+    }
+
+    public Attributes getAttributes()
+    {
+        return _context.getAttributes();
+    }
+
+    public String getContextPath()
+    {
+        return _context.getContextPath();
+    }
+
+    public String getInitParameter(String name)
+    {
+        return _context.getInitParameter(name);
+    }
+
+    public String setInitParameter(String name, String value)
+    {
+        return _context.setInitParameter(name,value);
+    }
+
+    public Enumeration<String> getInitParameterNames()
+    {
+        return _context.getInitParameterNames();
+    }
+
+    public Map<String, String> getInitParams()
+    {
+        return _context.getInitParams();
+    }
+
+    public void removeAttribute(String name)
+    {
+        _context.removeAttribute(name);
+    }
+
+    public void setAttribute(String name, Object value)
+    {
+        _context.setAttribute(name,value);
+    }
+
+    public void setContextPath(String contextPath)
+    {
+        _context.setContextPath(contextPath);
+    }
+
+    public Resource getBaseResource()
+    {
+        return _context.getBaseResource();
+    }
+
+    public String getResourceBase()
+    {
+        return _context.getResourceBase();
+    }
+
+    public void setResourceBase(String resourceBase)
+    {
+        _context.setResourceBase(resourceBase);
+    }
+
+    public ServletTester()
+    {
+        this("/",ServletContextHandler.SECURITY|ServletContextHandler.SESSIONS);
+    }
+
+    public ServletTester(String ctxPath)
+    {
+        this(ctxPath,ServletContextHandler.SECURITY|ServletContextHandler.SESSIONS);
+    }
+
+    public ServletTester(String contextPath,int options)
+    {
+        _context=new ServletContextHandler(_server,contextPath,options);
+        _server.setConnectors(new Connector[]{_connector});
+        addBean(_server);
+    }
+
+    public ServletContextHandler getContext()
+    {
+        return _context;
+    }
+
+    public String getResponses(String request) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request: {}",request);
+        }
+        return _connector.getResponses(request);
+    }
+    
+    public String getResponses(String request, long idleFor,TimeUnit units) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request: {}",request);
+        }
+        return _connector.getResponses(request, idleFor, units);
+    }
+    
+    public ByteBuffer getResponses(ByteBuffer request) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request (Buffer): {}",BufferUtil.toUTF8String(request));
+        }
+        return _connector.getResponses(request);
+    }
+    
+    public ByteBuffer getResponses(ByteBuffer requestsBuffer,long idleFor,TimeUnit units) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Requests (Buffer): {}",BufferUtil.toUTF8String(requestsBuffer));
+        }
+        return _connector.getResponses(requestsBuffer, idleFor, units);
+    }
+
+    /** Create a port based connector.
+     * This methods adds a port connector to the server
+     * @param localhost true if connector should use localhost, false for default host behavior.
+     * @return A URL to access the server via the connector.
+     * @throws Exception on test failure
+     */
+    public String createConnector(boolean localhost) throws Exception
+    {
+        ServerConnector connector = new ServerConnector(_server);
+        if (localhost)
+            connector.setHost("127.0.0.1");
+        _server.addConnector(connector);
+        if (_server.isStarted())
+            connector.start();
+        else
+            connector.open();
+
+        return "http://"+(localhost?"127.0.0.1":
+            InetAddress.getLocalHost().getHostAddress()
+        )+":"+connector.getLocalPort();
+    }
+
+    public LocalConnector createLocalConnector()
+    {
+        LocalConnector connector = new LocalConnector(_server);
+        _server.addConnector(connector);
+        return connector;
+    }
+
+
+
+}
diff --git a/jetty-servlet/src/test/resources/jetty-logging.properties b/jetty-servlet/src/test/resources/jetty-logging.properties
index 50696d6..ed4316e 100644
--- a/jetty-servlet/src/test/resources/jetty-logging.properties
+++ b/jetty-servlet/src/test/resources/jetty-logging.properties
@@ -1,5 +1,7 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.LEVEL=INFO
 #org.eclipse.jetty.LEVEL=DEBUG
 #org.eclipse.jetty.server.LEVEL=DEBUG
 #org.eclipse.jetty.servlet.LEVEL=DEBUG
 #org.eclipse.jetty.io.ChannelEndPoint.LEVEL=DEBUG
+#org.eclipse.jetty.server.DebugListener.LEVEL=DEBUG
\ No newline at end of file
diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml
index a1d9bc2..ef38677 100644
--- a/jetty-servlets/pom.xml
+++ b/jetty-servlets/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>jetty-project</artifactId>
     <groupId>org.eclipse.jetty</groupId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-servlets</artifactId>
@@ -16,52 +16,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",*</Import-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
@@ -109,6 +63,20 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-http</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty.toolchain</groupId>
       <artifactId>jetty-test-helper</artifactId>
       <scope>test</scope>
diff --git a/jetty-servlets/src/main/config/modules/servlets.mod b/jetty-servlets/src/main/config/modules/servlets.mod
index e8724b8..2e977c0 100644
--- a/jetty-servlets/src/main/config/modules/servlets.mod
+++ b/jetty-servlets/src/main/config/modules/servlets.mod
@@ -2,6 +2,7 @@
 # Jetty Servlets Module
 #
 
+
 [depend]
 servlet
 
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java
index 4bd0e27..07af21f 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/AsyncGzipFilter.java
@@ -18,555 +18,7 @@
 
 package org.eclipse.jetty.servlets;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-import java.util.zip.Deflater;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.HttpOutput;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.servlets.gzip.GzipFactory;
-import org.eclipse.jetty.servlets.gzip.GzipHttpOutput;
-import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/* ------------------------------------------------------------ */
-/** Async GZIP Filter
- * This filter is a gzip filter using jetty internal mechanism to apply gzip compression
- * to output that is compatible with async IO and does not need to wrap the response nor output stream.
- * The filter will gzip the content of a response if: <ul>
- * <li>The filter is mapped to a matching path</li>
- * <li>accept-encoding header is set to either gzip, deflate or a combination of those</li>
- * <li>The response status code is >=200 and <300
- * <li>The content length is unknown or more than the <code>minGzipSize</code> initParameter or the minGzipSize is 0(default)</li>
- * <li>If a list of mimeTypes is set by the <code>mimeTypes</code> init parameter, then the Content-Type is in the list.</li>
- * <li>If no mimeType list is set, then the content-type is not in the list defined by <code>excludedMimeTypes</code></li>
- * <li>No content-encoding is specified by the resource</li>
- * </ul>
- *
- * <p>
- * Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and
- * CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be
- * prevented, thus use of the gzip mechanism of the {@link org.eclipse.jetty.servlet.DefaultServlet} is
- * advised instead.
- * </p>
- * <p>
- * This filter extends {@link UserAgentFilter} and if the the initParameter <code>excludedAgents</code>
- * is set to a comma separated list of user agents, then these agents will be excluded from gzip content.
- * </p>
- * <p>Init Parameters:</p>
- * <dl>
- * <dt>bufferSize</dt>       <dd>The output buffer size. Defaults to 8192. Be careful as values <= 0 will lead to an
- *                            {@link IllegalArgumentException}.
- *                            See: {@link java.util.zip.GZIPOutputStream#GZIPOutputStream(java.io.OutputStream, int)}
- *                            and: {@link java.util.zip.DeflaterOutputStream#DeflaterOutputStream(java.io.OutputStream, Deflater, int)}
- * </dd>
- * <dt>minGzipSize</dt>       <dd>Content will only be compressed if content length is either unknown or greater
- *                            than <code>minGzipSize</code>.
- * </dd>
- * <dt>deflateCompressionLevel</dt>       <dd>The compression level used for deflate compression. (0-9).
- *                            See: {@link java.util.zip.Deflater#Deflater(int, boolean)}
- * </dd>
- * <dt>deflateNoWrap</dt>       <dd>The noWrap setting for deflate compression. Defaults to true. (true/false)
- *                            See: {@link java.util.zip.Deflater#Deflater(int, boolean)}
- * </dd>
- * <dt>methods</dt>       <dd>Comma separated list of HTTP methods to compress. If not set, only GET requests are compressed.
- *  </dd>
- * <dt>mimeTypes</dt>       <dd>Comma separated list of mime types to compress. If it is not set, then the excludedMimeTypes list is used.
- * </dd>
- * <dt>excludedMimeTypes</dt>       <dd>Comma separated list of mime types to never compress. If not set, then the default is the commonly known
- * image, video, audio and compressed types.
- * </dd>
-
- * <dt>excludedAgents</dt>       <dd>Comma separated list of user agents to exclude from compression. Does a
- *                            {@link String#contains(CharSequence)} to check if the excluded agent occurs
- *                            in the user-agent header. If it does -> no compression
- * </dd>
- * <dt>excludeAgentPatterns</dt>       <dd>Same as excludedAgents, but accepts regex patterns for more complex matching.
- * </dd>
- * <dt>excludePaths</dt>       <dd>Comma separated list of paths to exclude from compression.
- *                            Does a {@link String#startsWith(String)} comparison to check if the path matches.
- *                            If it does match -> no compression. To match subpaths use <code>excludePathPatterns</code>
- *                            instead.
- * </dd>
- * <dt>excludePathPatterns</dt>       <dd>Same as excludePath, but accepts regex patterns for more complex matching.
- * </dd>
- * <dt>vary</dt>       <dd>Set to the value of the Vary header sent with responses that could be compressed.  By default it is 
- *                            set to 'Vary: Accept-Encoding, User-Agent' since IE6 is excluded by default from the excludedAgents. 
- *                            If user-agents are not to be excluded, then this can be set to 'Vary: Accept-Encoding'.  Note also 
- *                            that shared caches may cache copies of a resource that is varied by User-Agent - one per variation of 
- *                            the User-Agent, unless the cache does some normalization of the UA string.
- * </dd>                         
- * <dt>checkGzExists</dt>       <dd>If set to true, the filter check if a static resource with ".gz" appended exists.  If so then
- *                            the normal processing is done so that the default servlet can send  the pre existing gz content. If not
- *                            set, defaults to the same as the default servlet "gzip" parameter.
- *  </dd>
- *  </dl>
- */
-public class AsyncGzipFilter extends UserAgentFilter implements GzipFactory
+@Deprecated
+public class AsyncGzipFilter extends GzipFilter
 {
-    private static final Logger LOG = Log.getLogger(GzipFilter.class);
-    public final static String GZIP = "gzip";
-    public static final String DEFLATE = "deflate";
-    public final static String ETAG_GZIP="--gzip";
-    public final static String ETAG = "o.e.j.s.GzipFilter.ETag";
-    public final static int DEFAULT_MIN_GZIP_SIZE=256;
-
-    protected ServletContext _context;
-    protected final Set<String> _mimeTypes=new HashSet<>();
-    protected boolean _excludeMimeTypes;
-    protected int _bufferSize=32*1024;
-    protected int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
-    protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION;
-    protected boolean _deflateNoWrap = true;
-    protected boolean _checkGzExists = true;
-    
-    // non-static, as other GzipFilter instances may have different configurations
-    protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
-
-    protected final static ThreadLocal<byte[]> _buffer= new ThreadLocal<byte[]>();
-
-    protected final Set<String> _methods=new HashSet<String>();
-    protected Set<String> _excludedAgents;
-    protected Set<Pattern> _excludedAgentPatterns;
-    protected Set<String> _excludedPaths;
-    protected Set<Pattern> _excludedPathPatterns;
-    protected HttpField _vary=new HttpGenerator.CachedHttpField(HttpHeader.VARY,HttpHeader.ACCEPT_ENCODING+", "+HttpHeader.USER_AGENT);
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#init(javax.servlet.FilterConfig)
-     */
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-        super.init(filterConfig);
-
-        _context=filterConfig.getServletContext();
-        
-        String tmp=filterConfig.getInitParameter("bufferSize");
-        if (tmp!=null)
-            _bufferSize=Integer.parseInt(tmp);
-        LOG.debug("{} bufferSize={}",this,_bufferSize);
-
-        tmp=filterConfig.getInitParameter("minGzipSize");
-        if (tmp!=null)
-            _minGzipSize=Integer.parseInt(tmp);
-        LOG.debug("{} minGzipSize={}",this,_minGzipSize);
-
-        tmp=filterConfig.getInitParameter("deflateCompressionLevel");
-        if (tmp!=null)
-            _deflateCompressionLevel=Integer.parseInt(tmp);
-        LOG.debug("{} deflateCompressionLevel={}",this,_deflateCompressionLevel);
-
-        tmp=filterConfig.getInitParameter("deflateNoWrap");
-        if (tmp!=null)
-            _deflateNoWrap=Boolean.parseBoolean(tmp);
-        LOG.debug("{} deflateNoWrap={}",this,_deflateNoWrap);
-
-        tmp=filterConfig.getInitParameter("checkGzExists");
-        if (tmp!=null)
-            _checkGzExists=Boolean.parseBoolean(tmp);
-        else
-        {
-            // Look to Default servlet for default
-            ServletRegistration dftServlet = _context.getServletRegistration("default");
-            if (dftServlet!=null && dftServlet.getInitParameter("gzip")!=null)
-                _checkGzExists=Boolean.parseBoolean(dftServlet.getInitParameter("gzip"));
-        }
-        LOG.debug("{} checkGzExists={}",this,_checkGzExists);
-        
-        tmp=filterConfig.getInitParameter("methods");
-        if (tmp!=null)
-        {
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _methods.add(tok.nextToken().trim().toUpperCase(Locale.ENGLISH));
-        }
-        else
-            _methods.add(HttpMethod.GET.asString());
-        LOG.debug("{} methods={}",this,_methods);
-        
-        tmp=filterConfig.getInitParameter("mimeTypes");
-        if (tmp==null)
-        {
-            _excludeMimeTypes=true;
-            tmp=filterConfig.getInitParameter("excludedMimeTypes");
-            if (tmp==null)
-            {
-                for (String type:MimeTypes.getKnownMimeTypes())
-                {
-                    if (type.equals("image/svg+xml")) //always compressable (unless .svgz file)
-                        continue;
-                    if (type.startsWith("image/")||
-                        type.startsWith("audio/")||
-                        type.startsWith("video/"))
-                        _mimeTypes.add(type);
-                }
-                _mimeTypes.add("application/compress");
-                _mimeTypes.add("application/zip");
-                _mimeTypes.add("application/gzip");
-            }
-            else
-            {
-                StringTokenizer tok = new StringTokenizer(tmp,",",false);
-                while (tok.hasMoreTokens())
-                    _mimeTypes.add(tok.nextToken().trim());
-            }
-        }
-        else
-        {
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _mimeTypes.add(tok.nextToken().trim());
-        }
-        LOG.debug("{} mimeTypes={}",this,_mimeTypes);
-        LOG.debug("{} excludeMimeTypes={}",this,_excludeMimeTypes);
-        tmp=filterConfig.getInitParameter("excludedAgents");
-        if (tmp!=null)
-        {
-            _excludedAgents=new HashSet<String>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-               _excludedAgents.add(tok.nextToken().trim());
-        }
-        LOG.debug("{} excludedAgents={}",this,_excludedAgents);
-
-        tmp=filterConfig.getInitParameter("excludeAgentPatterns");
-        if (tmp!=null)
-        {
-            _excludedAgentPatterns=new HashSet<Pattern>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedAgentPatterns.add(Pattern.compile(tok.nextToken().trim()));
-        }
-        LOG.debug("{} excludedAgentPatterns={}",this,_excludedAgentPatterns);
-
-        tmp=filterConfig.getInitParameter("excludePaths");
-        if (tmp!=null)
-        {
-            _excludedPaths=new HashSet<String>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedPaths.add(tok.nextToken().trim());
-        }
-        LOG.debug("{} excludedPaths={}",this,_excludedPaths);
-
-        tmp=filterConfig.getInitParameter("excludePathPatterns");
-        if (tmp!=null)
-        {
-            _excludedPathPatterns=new HashSet<Pattern>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedPathPatterns.add(Pattern.compile(tok.nextToken().trim()));
-        }
-        LOG.debug("{} excludedPathPatterns={}",this,_excludedPathPatterns);
-        
-        tmp=filterConfig.getInitParameter("vary");
-        if (tmp!=null)
-            _vary=new HttpGenerator.CachedHttpField(HttpHeader.VARY,tmp);
-        LOG.debug("{} vary={}",this,_vary);
-        
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#destroy()
-     */
-    @Override
-    public void destroy()
-    {
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
-     */
-    @Override
-    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
-        throws IOException, ServletException
-    {
-        LOG.debug("{} doFilter {}",this,req);
-        HttpServletRequest request=(HttpServletRequest)req;
-        HttpServletResponse response=(HttpServletResponse)res;
-        HttpChannel<?> channel = HttpChannel.getCurrentHttpChannel();
-        
-        // Have we already started compressing this response?
-        if (req.getDispatcherType()!=DispatcherType.REQUEST)
-        {
-            HttpOutput out = channel.getResponse().getHttpOutput();
-            if (out instanceof GzipHttpOutput && ((GzipHttpOutput)out).mightCompress())
-            {
-                LOG.debug("{} already might compress {}",this,request);
-                super.doFilter(request,response,chain);
-                return;
-            }
-        }
-
-        // If not a supported method or it is an Excluded URI or an excluded UA - no Vary because no matter what client, this URI is always excluded
-        String requestURI = request.getRequestURI();
-        if (!_methods.contains(request.getMethod()))
-        {
-            LOG.debug("{} excluded by method {}",this,request);
-            super.doFilter(request,response,chain);
-            return;
-        }
-        
-        if (isExcludedPath(requestURI))
-        {
-            LOG.debug("{} excluded by path {}",this,request);
-            super.doFilter(request,response,chain);
-            return;
-        }
-
-        // Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
-        if (_mimeTypes.size()>0 && _excludeMimeTypes)
-        {
-            String mimeType = _context.getMimeType(request.getRequestURI());
-
-            if (mimeType!=null)
-            {
-                mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);
-                if (_mimeTypes.contains(mimeType))
-                {
-                    LOG.debug("{} excluded by path suffix {}",this,request);
-                    // handle normally without setting vary header
-                    super.doFilter(request,response,chain);
-                    return;
-                }
-            }
-        }
-
-        //If the Content-Encoding is already set, then we won't compress
-        if (response.getHeader("Content-Encoding") != null)
-        {
-            super.doFilter(request,response,chain);
-            return;
-        }
-        
-        if (_checkGzExists && request.getServletContext()!=null)
-        {
-            String path=request.getServletContext().getRealPath(URIUtil.addPaths(request.getServletPath(),request.getPathInfo()));
-            if (path!=null)
-            {
-                File gz=new File(path+".gz");
-                if (gz.exists())
-                {
-                    LOG.debug("{} gzip exists {}",this,request);
-                    // allow default servlet to handle
-                    super.doFilter(request,response,chain);
-                    return;
-                }
-            }
-        }
-        
-        // Special handling for etags
-        String etag = request.getHeader("If-None-Match"); 
-        if (etag!=null)
-        {
-            if (etag.contains(ETAG_GZIP))
-                request.setAttribute(ETAG,etag.replace(ETAG_GZIP,""));
-        }
-
-        HttpOutput out = channel.getResponse().getHttpOutput();
-        if (!(out instanceof GzipHttpOutput))
-        {
-            if (out.getClass()!=HttpOutput.class)
-                throw new IllegalStateException();
-            channel.getResponse().setHttpOutput(out = new GzipHttpOutput(channel));
-        }
-        
-        GzipHttpOutput cout=(GzipHttpOutput)out;
-        
-        try
-        {
-            cout.mightCompress(this);
-            super.doFilter(request,response,chain);
-        }
-        catch(Throwable e)
-        {
-            LOG.debug("{} excepted {}",this,request,e);
-            if (!response.isCommitted())
-            {
-                cout.resetBuffer();
-                cout.noCompressionIfPossible();
-            }
-            throw e;
-        }
-    }
-
-
-    /**
-     * Checks to see if the userAgent is excluded
-     *
-     * @param ua
-     *            the user agent
-     * @return boolean true if excluded
-     */
-    private boolean isExcludedAgent(String ua)
-    {
-        if (ua == null)
-            return false;
-
-        if (_excludedAgents != null)
-        {
-            if (_excludedAgents.contains(ua))
-            {
-                return true;
-            }
-        }
-        if (_excludedAgentPatterns != null)
-        {
-            for (Pattern pattern : _excludedAgentPatterns)
-            {
-                if (pattern.matcher(ua).matches())
-                {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks to see if the path is excluded
-     *
-     * @param requestURI
-     *            the request uri
-     * @return boolean true if excluded
-     */
-    private boolean isExcludedPath(String requestURI)
-    {
-        if (requestURI == null)
-            return false;
-        if (_excludedPaths != null)
-        {
-            for (String excludedPath : _excludedPaths)
-            {
-                if (requestURI.startsWith(excludedPath))
-                {
-                    return true;
-                }
-            }
-        }
-        if (_excludedPathPatterns != null)
-        {
-            for (Pattern pattern : _excludedPathPatterns)
-            {
-                if (pattern.matcher(requestURI).matches())
-                {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public HttpField getVaryField()
-    {
-        return _vary;
-    }
-
-    @Override
-    public Deflater getDeflater(Request request, long content_length)
-    {
-        String ua = getUserAgent(request);
-        if (ua!=null && isExcludedAgent(ua))
-        {
-            LOG.debug("{} excluded user agent {}",this,request);
-            return null;
-        }
-        
-        if (content_length>=0 && content_length<_minGzipSize)
-        {
-            LOG.debug("{} excluded minGzipSize {}",this,request);
-            return null;
-        }
-        
-        String accept = request.getHttpFields().get(HttpHeader.ACCEPT_ENCODING);
-        if (accept==null)
-        {
-            LOG.debug("{} excluded !accept {}",this,request);
-            return null;
-        }
-        
-        boolean gzip=false;
-        if (GZIP.equals(accept) || accept.startsWith("gzip,"))
-            gzip=true;
-        else
-        {
-            List<String> list=HttpFields.qualityList(request.getHttpFields().getValues(HttpHeader.ACCEPT_ENCODING.asString(),","));
-            for (String a:list)
-            {
-                if (GZIP.equalsIgnoreCase(HttpFields.valueParameters(a,null)))
-                {
-                    gzip=true;
-                    break;
-                }
-            }
-        }
-        
-        if (!gzip)
-        {
-            LOG.debug("{} excluded not gzip accept {}",this,request);
-            return null;
-        }
-        
-        Deflater df = _deflater.get();
-        if (df==null)
-            df=new Deflater(_deflateCompressionLevel,_deflateNoWrap);        
-        else
-            _deflater.set(null);
-        
-        return df;
-    }
-
-    @Override
-    public void recycle(Deflater deflater)
-    {
-        deflater.reset();
-        if (_deflater.get()==null)
-            _deflater.set(deflater);
-        
-    }
-    
-    @Override
-    public boolean isExcludedMimeType(String mimetype)
-    {
-        return _mimeTypes.contains(mimetype) == _excludeMimeTypes;
-    }
-
-    @Override
-    public int getBufferSize()
-    {
-        return _bufferSize;
-    }
-    
-    
 }
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
index e2fa409..4d9ea3e 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
@@ -44,11 +44,9 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-//-----------------------------------------------------------------------------
 /**
  * CGI Servlet.
  * <p>
- * 
  * The following init parameters are used to configure this servlet:
  * <dl>
  * <dt>cgibinResourceBase</dt>
@@ -69,7 +67,6 @@
  * <dt>ignoreExitState</dt>
  * <dd>If true then do not act on a non-zero exec exit status")</dd>
  * </dl>
- * 
  */
 public class CGI extends HttpServlet
 {
@@ -546,13 +543,18 @@
 
         /**
          * Set a name/value pair, null values will be treated as an empty String
+         * @param name the name
+         * @param value the value
          */
         public void set(String name, String value)
         {
             envMap.put(name,name + "=" + StringUtil.nonNull(value));
         }
 
-        /** Get representation suitable for passing to exec. */
+        /** 
+         * Get representation suitable for passing to exec. 
+         * @return the env map as an array 
+         */
         public String[] getEnvArray()
         {
             return envMap.values().toArray(new String[envMap.size()]);
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java
index a5af7b4..7a2a6e1 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CloseableDoSFilter.java
@@ -21,7 +21,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
 
 /* ------------------------------------------------------------ */
@@ -35,7 +34,7 @@
     @Override
     protected void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread)
     {
-        Request base_request=(request instanceof Request)?(Request)request:HttpChannel.getCurrentHttpChannel().getRequest();
+        Request base_request=Request.getBaseRequest(request);
         base_request.getHttpChannel().getEndPoint().close();
     }
 }
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
index 1f245b5..dbf6de1 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
@@ -44,13 +44,13 @@
  * relative to the context root.  So these script tags:</p>
  * <pre>
  * &lt;script type="text/javascript" src="../js/behaviour.js"&gt;&lt;/script&gt;
- * &lt;script type="text/javascript" src="../js/ajax.js&/chat/chat.js"&gt;&lt;/script&gt;
+ * &lt;script type="text/javascript" src="../js/ajax.js"&gt;&lt;/script&gt;
  * &lt;script type="text/javascript" src="../chat/chat.js"&gt;&lt;/script&gt;
  * </pre>
  * <p>can be replaced with the single tag (with the {@code ConcatServlet}
  * mapped to {@code /concat}):</p>
  * <pre>
- * &lt;script type="text/javascript" src="../concat?/js/behaviour.js&/js/ajax.js&/chat/chat.js"&gt;&lt;/script&gt;
+ * &lt;script type="text/javascript" src="../concat?/js/behaviour.js&amp;/js/ajax.js&amp;/chat/chat.js"&gt;&lt;/script&gt;
  * </pre>
  * <p>The {@link ServletContext#getMimeType(String)} method is used to determine the
  * mime type of each resource. If the types of all resources do not match, then a 415
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java
index 19ab0f8..faa0ef7 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java
@@ -26,6 +26,7 @@
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -40,44 +41,71 @@
 import org.eclipse.jetty.util.log.Logger;
 
 /**
- * <p>Implementation of the
- * <a href="http://www.w3.org/TR/cors/">cross-origin resource sharing</a>.</p>
- * <p>A typical example is to use this filter to allow cross-domain
+ * Implementation of the
+ * <a href="http://www.w3.org/TR/cors/">cross-origin resource sharing</a>.
+ * <p>
+ * A typical example is to use this filter to allow cross-domain
  * <a href="http://cometd.org">cometd</a> communication using the standard
  * long polling transport instead of the JSONP transport (that is less
- * efficient and less reactive to failures).</p>
- * <p>This filter allows the following configuration parameters:
- * <ul>
- * <li><b>allowedOrigins</b>, a comma separated list of origins that are
+ * efficient and less reactive to failures).
+ * <p>
+ * This filter allows the following configuration parameters:
+ * <dl>
+ * <dt>allowedOrigins</dt>
+ * <dd>a comma separated list of origins that are
  * allowed to access the resources. Default value is <b>*</b>, meaning all
- * origins.<br />
+ * origins.
+ * <p>
  * If an allowed origin contains one or more * characters (for example
  * http://*.domain.com), then "*" characters are converted to ".*", "."
  * characters are escaped to "\." and the resulting allowed origin
- * interpreted as a regular expression.<br />
+ * interpreted as a regular expression.
+ * <p>
  * Allowed origins can therefore be more complex expressions such as
  * https?://*.domain.[a-z]{3} that matches http or https, multiple subdomains
- * and any 3 letter top-level domain (.com, .net, .org, etc.).</li>
- * <li><b>allowedMethods</b>, a comma separated list of HTTP methods that
+ * and any 3 letter top-level domain (.com, .net, .org, etc.).</dd>
+ * 
+ * <dt>allowedTimingOrigins</dt>
+ * <dd>a comma separated list of origins that are
+ * allowed to time the resource. Default value is the empty string, meaning
+ * no origins.
+ * <p>
+ * The check whether the timing header is set, will be performed only if
+ * the user gets general access to the resource using the <b>allowedOrigins</b>.
+ *
+ * <dt>allowedMethods</dt>
+ * <dd>a comma separated list of HTTP methods that
  * are allowed to be used when accessing the resources. Default value is
- * <b>GET,POST,HEAD</b></li>
- * <li><b>allowedHeaders</b>, a comma separated list of HTTP headers that
+ * <b>GET,POST,HEAD</b></dd>
+ * 
+ * 
+ * <dt>allowedHeaders</dt>
+ * <dd>a comma separated list of HTTP headers that
  * are allowed to be specified when accessing the resources. Default value
  * is <b>X-Requested-With,Content-Type,Accept,Origin</b>. If the value is a single "*",
- * this means that any headers will be accepted.</li>
- * <li><b>preflightMaxAge</b>, the number of seconds that preflight requests
+ * this means that any headers will be accepted.</dd>
+ * 
+ * <dt>preflightMaxAge</dt>
+ * <dd>the number of seconds that preflight requests
  * can be cached by the client. Default value is <b>1800</b> seconds, or 30
- * minutes</li>
- * <li><b>allowCredentials</b>, a boolean indicating if the resource allows
- * requests with credentials. Default value is <b>true</b></li>
- * <li><b>exposedHeaders</b>, a comma separated list of HTTP headers that
+ * minutes</dd>
+ * 
+ * <dt>allowCredentials</dt>
+ * <dd>a boolean indicating if the resource allows
+ * requests with credentials. Default value is <b>true</b></dd>
+ * 
+ * <dt>exposedHeaders</dt>
+ * <dd>a comma separated list of HTTP headers that
  * are allowed to be exposed on the client. Default value is the
- * <b>empty list</b></li>
- * <li><b>chainPreflight</b>, if true preflight requests are chained to their
+ * <b>empty list</b></dd>
+ * 
+ * <dt>chainPreflight</dt>
+ * <dd>if true preflight requests are chained to their
  * target resource for normal handling (as an OPTION request).  Otherwise the
- * filter will response to the preflight. Default is <b>true</b>.</li>
- * </ul></p>
- * <p>A typical configuration could be:</p>
+ * filter will response to the preflight. Default is <b>true</b>.</dd>
+ * 
+ * </dl>
+ * A typical configuration could be:
  * <pre>
  * &lt;web-app ...&gt;
  *     ...
@@ -108,8 +136,10 @@
     public static final String ACCESS_CONTROL_MAX_AGE_HEADER = "Access-Control-Max-Age";
     public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials";
     public static final String ACCESS_CONTROL_EXPOSE_HEADERS_HEADER = "Access-Control-Expose-Headers";
+    public static final String TIMING_ALLOW_ORIGIN_HEADER = "Timing-Allow-Origin";
     // Implementation constants
     public static final String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
+    public static final String ALLOWED_TIMING_ORIGINS_PARAM = "allowedTimingOrigins";
     public static final String ALLOWED_METHODS_PARAM = "allowedMethods";
     public static final String ALLOWED_HEADERS_PARAM = "allowedHeaders";
     public static final String PREFLIGHT_MAX_AGE_PARAM = "preflightMaxAge";
@@ -118,13 +148,17 @@
     public static final String OLD_CHAIN_PREFLIGHT_PARAM = "forwardPreflight";
     public static final String CHAIN_PREFLIGHT_PARAM = "chainPreflight";
     private static final String ANY_ORIGIN = "*";
+    private static final String DEFAULT_ALLOWED_ORIGINS = "*";
+    private static final String DEFAULT_ALLOWED_TIMING_ORIGINS = "";
     private static final List<String> SIMPLE_HTTP_METHODS = Arrays.asList("GET", "POST", "HEAD");
     private static final List<String> DEFAULT_ALLOWED_METHODS = Arrays.asList("GET", "POST", "HEAD");
     private static final List<String> DEFAULT_ALLOWED_HEADERS = Arrays.asList("X-Requested-With", "Content-Type", "Accept", "Origin");
 
     private boolean anyOriginAllowed;
+    private boolean anyTimingOriginAllowed;
     private boolean anyHeadersAllowed;
     private List<String> allowedOrigins = new ArrayList<String>();
+    private List<String> allowedTimingOrigins = new ArrayList<String>();
     private List<String> allowedMethods = new ArrayList<String>();
     private List<String> allowedHeaders = new ArrayList<String>();
     private List<String> exposedHeaders = new ArrayList<String>();
@@ -135,26 +169,10 @@
     public void init(FilterConfig config) throws ServletException
     {
         String allowedOriginsConfig = config.getInitParameter(ALLOWED_ORIGINS_PARAM);
-        if (allowedOriginsConfig == null)
-            allowedOriginsConfig = "*";
-        String[] allowedOrigins = StringUtil.csvSplit(allowedOriginsConfig);
-        for (String allowedOrigin : allowedOrigins)
-        {
-            allowedOrigin = allowedOrigin.trim();
-            if (allowedOrigin.length() > 0)
-            {
-                if (ANY_ORIGIN.equals(allowedOrigin))
-                {
-                    anyOriginAllowed = true;
-                    this.allowedOrigins.clear();
-                    break;
-                }
-                else
-                {
-                    this.allowedOrigins.add(allowedOrigin);
-                }
-            }
-        }
+        String allowedTimingOriginsConfig = config.getInitParameter(ALLOWED_TIMING_ORIGINS_PARAM);
+        
+        anyOriginAllowed = generateAllowedOrigins(allowedOrigins, allowedOriginsConfig, DEFAULT_ALLOWED_ORIGINS);
+        anyTimingOriginAllowed = generateAllowedOrigins(allowedTimingOrigins, allowedTimingOriginsConfig, DEFAULT_ALLOWED_TIMING_ORIGINS);
 
         String allowedMethodsConfig = config.getInitParameter(ALLOWED_METHODS_PARAM);
         if (allowedMethodsConfig == null)
@@ -205,6 +223,7 @@
         {
             LOG.debug("Cross-origin filter configuration: " +
                             ALLOWED_ORIGINS_PARAM + " = " + allowedOriginsConfig + ", " +
+                            ALLOWED_TIMING_ORIGINS_PARAM + " = " + allowedTimingOriginsConfig + ", " +
                             ALLOWED_METHODS_PARAM + " = " + allowedMethodsConfig + ", " +
                             ALLOWED_HEADERS_PARAM + " = " + allowedHeadersConfig + ", " +
                             PREFLIGHT_MAX_AGE_PARAM + " = " + preflightMaxAgeConfig + ", " +
@@ -215,6 +234,29 @@
         }
     }
 
+    private boolean generateAllowedOrigins(List<String> allowedOriginStore, String allowedOriginsConfig, String defaultOrigin) 
+    {
+        if (allowedOriginsConfig == null)
+            allowedOriginsConfig = defaultOrigin;
+        String[] allowedOrigins = StringUtil.csvSplit(allowedOriginsConfig);
+        for (String allowedOrigin : allowedOrigins)
+        {
+            if (allowedOrigin.length() > 0)
+            {
+                if (ANY_ORIGIN.equals(allowedOrigin))
+                {
+                    allowedOriginStore.clear();
+                    return true;
+                }
+                else
+                {
+                    allowedOriginStore.add(allowedOrigin);
+                }
+            }
+        }
+        return false;
+    }
+    
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
     {
         handle((HttpServletRequest)request, (HttpServletResponse)response, chain);
@@ -226,7 +268,7 @@
         // Is it a cross origin request ?
         if (origin != null && isEnabled(request))
         {
-            if (originMatches(origin))
+            if (anyOriginAllowed || originMatches(allowedOrigins, origin))
             {
                 if (isSimpleRequest(request))
                 {
@@ -247,6 +289,15 @@
                     LOG.debug("Cross-origin request to {} is a non-simple cross-origin request", request.getRequestURI());
                     handleSimpleResponse(request, response, origin);
                 }
+
+                if (anyTimingOriginAllowed || originMatches(allowedTimingOrigins, origin))
+                {
+                    response.setHeader(TIMING_ALLOW_ORIGIN_HEADER, origin);
+                }
+                else
+                {
+                    LOG.debug("Cross-origin request to " + request.getRequestURI() + " with origin " + origin + " does not match allowed timing origins " + allowedTimingOrigins);
+                }
             }
             else
             {
@@ -261,12 +312,12 @@
     {
         // WebSocket clients such as Chrome 5 implement a version of the WebSocket
         // protocol that does not accept extra response headers on the upgrade response
-        for (Enumeration connections = request.getHeaders("Connection"); connections.hasMoreElements();)
+        for (Enumeration<String> connections = request.getHeaders("Connection"); connections.hasMoreElements();)
         {
             String connection = (String)connections.nextElement();
             if ("Upgrade".equalsIgnoreCase(connection))
             {
-                for (Enumeration upgrades = request.getHeaders("Upgrade"); upgrades.hasMoreElements();)
+                for (Enumeration<String>  upgrades = request.getHeaders("Upgrade"); upgrades.hasMoreElements();)
                 {
                     String upgrade = (String)upgrades.nextElement();
                     if ("WebSocket".equalsIgnoreCase(upgrade))
@@ -277,11 +328,8 @@
         return true;
     }
 
-    private boolean originMatches(String originList)
+    private boolean originMatches(List<String> allowedOrigins, String originList)
     {
-        if (anyOriginAllowed)
-            return true;
-
         if (originList.trim().length() == 0)
             return false;
 
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
index 4066523..262d172 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DataRateLimitedServlet.java
@@ -63,7 +63,7 @@
 {
     private static final long serialVersionUID = -4771757707068097025L;
     private int buffersize=8192;
-    private int pause=100;
+    private long pauseNS=TimeUnit.MILLISECONDS.toNanos(100);
     ScheduledThreadPoolExecutor scheduler;
     private final ConcurrentHashMap<String, ByteBuffer> cache=new ConcurrentHashMap<>();
     
@@ -76,7 +76,7 @@
             buffersize=Integer.parseInt(tmp);
         tmp = getInitParameter("pause");
         if (tmp!=null)
-            pause=Integer.parseInt(tmp);
+            pauseNS=TimeUnit.MILLISECONDS.toNanos(Integer.parseInt(tmp));
         tmp = getInitParameter("pool");
         int pool=tmp==null?Runtime.getRuntime().availableProcessors():Integer.parseInt(tmp);
         
@@ -205,7 +205,7 @@
                 
                 // Schedule a timer callback to pause writing.  Because isReady() is not called,
                 // a onWritePossible callback is no scheduled.
-                scheduler.schedule(this,pause,TimeUnit.MILLISECONDS);
+                scheduler.schedule(this,pauseNS,TimeUnit.NANOSECONDS);
             }
         }
         
@@ -261,7 +261,7 @@
         {            
             // If we are able to write
             if(out.isReady())
-            {
+            {   
                 // Position our buffers limit to allow only buffersize bytes to be written
                 int l=content.position()+buffersize;
                 // respect the ultimate limit
@@ -276,7 +276,7 @@
                     async.complete();
                     return;
                 }
-
+                
                 // write our limited buffer.  This will be an asynchronous write
                 // and will always return immediately without blocking.  If a subsequent
                 // call to out.isReady() returns false, then this onWritePossible method
@@ -284,8 +284,8 @@
                 out.write(content);
 
                 // Schedule a timer callback to pause writing.  Because isReady() is not called,
-                // a onWritePossible callback is no scheduled.
-                scheduler.schedule(this,pause,TimeUnit.MILLISECONDS);
+                // a onWritePossible callback is not scheduled.
+                scheduler.schedule(this,pauseNS,TimeUnit.NANOSECONDS);
             }
         }
         
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
index 8fb5aca..435712c 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java
@@ -64,7 +64,6 @@
 
 /**
  * Denial of Service filter
- * <p/>
  * <p>
  * This filter is useful for limiting
  * exposure to abuse from request flooding, whether malicious, or as a result of
@@ -82,53 +81,44 @@
  * The {@link #extractUserId(ServletRequest request)} function should be
  * implemented, in order to uniquely identify authenticated users.
  * <p>
- * The following init parameters control the behavior of the filter:<dl>
- * <p/>
+ * The following init parameters control the behavior of the filter:
+ * <dl>
  * <dt>maxRequestsPerSec</dt>
  * <dd>the maximum number of requests from a connection per
  * second. Requests in excess of this are first delayed,
  * then throttled.</dd>
- * <p/>
  * <dt>delayMs</dt>
  * <dd>is the delay given to all requests over the rate limit,
  * before they are considered at all. -1 means just reject request,
  * 0 means no delay, otherwise it is the delay.</dd>
- * <p/>
  * <dt>maxWaitMs</dt>
  * <dd>how long to blocking wait for the throttle semaphore.</dd>
- * <p/>
  * <dt>throttledRequests</dt>
  * <dd>is the number of requests over the rate limit able to be
  * considered at once.</dd>
- * <p/>
  * <dt>throttleMs</dt>
  * <dd>how long to async wait for semaphore.</dd>
- * <p/>
  * <dt>maxRequestMs</dt>
  * <dd>how long to allow this request to run.</dd>
- * <p/>
  * <dt>maxIdleTrackerMs</dt>
  * <dd>how long to keep track of request rates for a connection,
  * before deciding that the user has gone away, and discarding it</dd>
- * <p/>
  * <dt>insertHeaders</dt>
  * <dd>if true , insert the DoSFilter headers into the response. Defaults to true.</dd>
- * <p/>
  * <dt>trackSessions</dt>
  * <dd>if true, usage rate is tracked by session if a session exists. Defaults to true.</dd>
- * <p/>
  * <dt>remotePort</dt>
  * <dd>if true and session tracking is not used, then rate is tracked by IP+port (effectively connection). Defaults to false.</dd>
- * <p/>
  * <dt>ipWhitelist</dt>
  * <dd>a comma-separated list of IP addresses that will not be rate limited</dd>
- * <p/>
  * <dt>managedAttr</dt>
  * <dd>if set to true, then this servlet is set as a {@link ServletContext} attribute with the
  * filter name as the attribute name.  This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to
  * manage the configuration of the filter.</dd>
+ * <dt>tooManyCode</dt>
+ * <dd>The status code to send if there are too many requests.  By default is 429 (too many requests), but 503 (Unavailable) is 
+ * another option</dd>
  * </dl>
- * </p>
  * <p>
  * This filter should be configured for {@link DispatcherType#REQUEST} and {@link DispatcherType#ASYNC} and with 
  * <code>&lt;async-supported&gt;true&lt;/async-supported&gt;</code>.
@@ -169,6 +159,7 @@
     static final String REMOTE_PORT_INIT_PARAM = "remotePort";
     static final String IP_WHITELIST_INIT_PARAM = "ipWhitelist";
     static final String ENABLED_INIT_PARAM = "enabled";
+    static final String TOO_MANY_CODE = "tooManyCode";
 
     private static final int USER_AUTH = 2;
     private static final int USER_SESSION = 2;
@@ -179,6 +170,7 @@
     private final String _resumed = "DoSFilter@" + Integer.toHexString(hashCode()) + ".RESUMED";
     private final ConcurrentHashMap<String, RateTracker> _rateTrackers = new ConcurrentHashMap<>();
     private final List<String> _whitelist = new CopyOnWriteArrayList<>();
+    private int _tooManyCode;
     private volatile long _delayMs;
     private volatile long _throttleMs;
     private volatile long _maxWaitMs;
@@ -266,7 +258,10 @@
 
         parameter = filterConfig.getInitParameter(ENABLED_INIT_PARAM);
         setEnabled(parameter == null || Boolean.parseBoolean(parameter));
-
+        
+        parameter = filterConfig.getInitParameter(TOO_MANY_CODE);
+        setTooManyCode(parameter==null?429:Integer.parseInt(parameter));
+        
         _scheduler = startScheduler();
 
         ServletContext context = filterConfig.getServletContext();
@@ -337,7 +332,7 @@
                     LOG.warn("DOS ALERT: Request rejected ip={}, session={}, user={}", request.getRemoteAddr(), request.getRequestedSessionId(), request.getUserPrincipal());
                     if (insertHeaders)
                         response.addHeader("DoSFilter", "unavailable");
-                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                    response.sendError(getTooManyCode());
                     return;
                 }
                 case 0:
@@ -420,36 +415,43 @@
                     LOG.debug("Rejecting {}", request);
                 if (isInsertHeaders())
                     response.addHeader("DoSFilter", "unavailable");
-                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+                response.sendError(getTooManyCode());
             }
         }
         catch (InterruptedException e)
         {
-            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+            LOG.ignore(e);
+            response.sendError(getTooManyCode());
         }
         finally
         {
             if (accepted)
             {
-                // Wake up the next highest priority request.
-                for (int p = _queues.length - 1; p >= 0; --p)
+                try
                 {
-                    AsyncContext asyncContext = _queues[p].poll();
-                    if (asyncContext != null)
+                    // Wake up the next highest priority request.
+                    for (int p = _queues.length - 1; p >= 0; --p)
                     {
-                        ServletRequest candidate = asyncContext.getRequest();
-                        Boolean suspended = (Boolean)candidate.getAttribute(_suspended);
-                        if (suspended == Boolean.TRUE)
+                        AsyncContext asyncContext = _queues[p].poll();
+                        if (asyncContext != null)
                         {
-                            if (LOG.isDebugEnabled())
-                                LOG.debug("Resuming {}", request);
-                            candidate.setAttribute(_resumed, Boolean.TRUE);
-                            asyncContext.dispatch();
-                            break;
+                            ServletRequest candidate = asyncContext.getRequest();
+                            Boolean suspended = (Boolean)candidate.getAttribute(_suspended);
+                            if (suspended == Boolean.TRUE)
+                            {
+                                if (LOG.isDebugEnabled())
+                                    LOG.debug("Resuming {}", request);
+                                candidate.setAttribute(_resumed, Boolean.TRUE);
+                                asyncContext.dispatch();
+                                break;
+                            }
                         }
                     }
                 }
-                _passes.release();
+                finally
+                {
+                    _passes.release();
+                }
             }
         }
     }
@@ -540,12 +542,12 @@
      * track of this connection's request rate. If this is not the first request
      * from this connection, return the existing object with the stored stats.
      * If it is the first request, then create a new request tracker.
-     * <p/>
+     * <p>
      * Assumes that each connection has an identifying characteristic, and goes
      * through them in order, taking the first that matches: user id (logged
      * in), session id, client IP address. Unidentifiable connections are lumped
      * into one.
-     * <p/>
+     * <p>
      * When a session expires, its rate tracker is automatically deleted.
      *
      * @param request the current request
@@ -793,6 +795,7 @@
     /**
      * Get delay (in milliseconds) that is applied to all requests
      * over the rate limit, before they are considered at all.
+     * @return the delay in milliseconds
      */
     @ManagedAttribute("delay applied to all requests over the rate limit (in ms)")
     public long getDelayMs()
@@ -1009,6 +1012,16 @@
     {
         _enabled = enabled;
     }
+    
+    public int getTooManyCode()
+    {
+        return _tooManyCode;
+    }
+
+    public void setTooManyCode(int tooManyCode)
+    {
+        _tooManyCode = tooManyCode;
+    }
 
     /**
      * Get a list of IP addresses that will not be rate limited.
@@ -1094,10 +1107,10 @@
     {
         private static final long serialVersionUID = 3534663738034577872L;
 
-        protected transient final String _id;
-        protected transient final int _type;
-        protected transient final long[] _timestamps;
-        protected transient int _next;
+        protected final String _id;
+        protected final int _type;
+        protected final long[] _timestamps;
+        protected int _next;
 
         public RateTracker(String id, int type, int maxRequestsPerSecond)
         {
@@ -1108,6 +1121,7 @@
         }
 
         /**
+         * @param now the time now (in milliseconds)
          * @return the current calculated request rate over the last second
          */
         public boolean isRateExceeded(long now)
@@ -1150,16 +1164,14 @@
         public void sessionWillPassivate(HttpSessionEvent se)
         {
             //take the tracker of the list of trackers (if its still there)
-            //and ensure that we take ourselves out of the session so we are not saved
             _rateTrackers.remove(_id);
-            se.getSession().removeAttribute(__TRACKER);
-            if (LOG.isDebugEnabled()) 
-                LOG.debug("Value removed: {}", getId());
         }
 
         public void sessionDidActivate(HttpSessionEvent se)
         {
-            LOG.warn("Unexpected session activation");
+            RateTracker tracker = (RateTracker)se.getSession().getAttribute(__TRACKER);
+            if (tracker!=null)
+                _rateTrackers.put(tracker.getId(),tracker);
         }
 
         @Override
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
index 6159c3a..5f676e2 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
@@ -18,641 +18,42 @@
 
 package org.eclipse.jetty.servlets;
 
-import java.io.File;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-import java.util.zip.Deflater;
 
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
+import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
-import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
-import org.eclipse.jetty.servlets.gzip.DeflatedOutputStream;
-import org.eclipse.jetty.servlets.gzip.GzipOutputStream;
-import org.eclipse.jetty.util.IncludeExclude;
-import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
 /* ------------------------------------------------------------ */
-/** GZIP Filter
- * This filter will gzip or deflate the content of a response if: <ul>
- * <li>The filter is mapped to a matching path</li>
- * <li>accept-encoding header is set to either gzip, deflate or a combination of those</li>
- * <li>The response status code is >=200 and <300
- * <li>The content length is unknown or more than the <code>minGzipSize</code> initParameter or the minGzipSize is 0(default)</li>
- * <li>If a list of mimeTypes is set by the <code>mimeTypes</code> init parameter, then the Content-Type is in the list.</li>
- * <li>If no mimeType list is set, then the content-type is not in the list defined by <code>excludedMimeTypes</code></li>
- * <li>No content-encoding is specified by the resource</li>
- * </ul>
- *
- * <p>
- * If both gzip and deflate are specified in the accept-encoding header, then gzip will be used.
- * </p>
- * <p>
- * Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and
- * CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be
- * prevented, thus use of the gzip mechanism of the {@link org.eclipse.jetty.servlet.DefaultServlet} is
- * advised instead.
- * </p>
- * <p>
- * This filter extends {@link UserAgentFilter} and if the the initParameter <code>excludedAgents</code>
- * is set to a comma separated list of user agents, then these agents will be excluded from gzip content.
- * </p>
- * <p>Init Parameters:</p>
- * <dl>
- * <dt>bufferSize</dt>       <dd>The output buffer size. Defaults to 8192. Be careful as values <= 0 will lead to an
- *                            {@link IllegalArgumentException}.
- *                            See: {@link java.util.zip.GZIPOutputStream#GZIPOutputStream(java.io.OutputStream, int)}
- *                            and: {@link java.util.zip.DeflaterOutputStream#DeflaterOutputStream(java.io.OutputStream, Deflater, int)}
- * </dd>
- * <dt>minGzipSize</dt>       <dd>Content will only be compressed if content length is either unknown or greater
- *                            than <code>minGzipSize</code>.
- * </dd>
- * <dt>deflateCompressionLevel</dt>       <dd>The compression level used for deflate compression. (0-9).
- *                            See: {@link java.util.zip.Deflater#Deflater(int, boolean)}
- * </dd>
- * <dt>deflateNoWrap</dt>       <dd>The noWrap setting for deflate compression. Defaults to true. (true/false)
- *                            See: {@link java.util.zip.Deflater#Deflater(int, boolean)}
- * </dd>
- * <dt>methods</dt>       <dd>Comma separated list of HTTP methods to compress. If not set, only GET requests are compressed.
- *  </dd>
- * <dt>mimeTypes</dt>       <dd>Comma separated list of mime types to compress. If it is not set, then the excludedMimeTypes list is used.
- * </dd>
- * <dt>excludedMimeTypes</dt>       <dd>Comma separated list of mime types to never compress. If not set, then the default is the commonly known
- * image, video, audio and compressed types.
- * </dd>
-
- * <dt>excludedAgents</dt>       <dd>Comma separated list of user agents to exclude from compression. Does a
- *                            {@link String#contains(CharSequence)} to check if the excluded agent occurs
- *                            in the user-agent header. If it does -> no compression
- * </dd>
- * <dt>excludeAgentPatterns</dt>       <dd>Same as excludedAgents, but accepts regex patterns for more complex matching.
- * </dd>
- * <dt>excludePaths</dt>       <dd>Comma separated list of paths to exclude from compression.
- *                            Does a {@link String#startsWith(String)} comparison to check if the path matches.
- *                            If it does match -> no compression. To match subpaths use <code>excludePathPatterns</code>
- *                            instead.
- * </dd>
- * <dt>excludePathPatterns</dt>       <dd>Same as excludePath, but accepts regex patterns for more complex matching.
- * </dd>
- * <dt>vary</dt>       <dd>Set to the value of the Vary header sent with responses that could be compressed.  By default it is 
- *                            set to 'Vary: Accept-Encoding, User-Agent' since IE6 is excluded by default from the excludedAgents. 
- *                            If user-agents are not to be excluded, then this can be set to 'Vary: Accept-Encoding'.  Note also 
- *                            that shared caches may cache copies of a resource that is varied by User-Agent - one per variation of 
- *                            the User-Agent, unless the cache does some normalization of the UA string.
- * </dd>                         
- * <dt>checkGzExists</dt>       <dd>If set to true, the filter check if a static resource with ".gz" appended exists.  If so then
- *                            the normal processing is done so that the default servlet can send  the pre existing gz content.
- *  </dd>
- *  </dl>
+/** 
  */
-public class GzipFilter extends UserAgentFilter
+
+@Deprecated
+public class GzipFilter implements Filter
 {
     private static final Logger LOG = Log.getLogger(GzipFilter.class);
-    public final static String GZIP="gzip";
-    public final static String ETAG_GZIP="--gzip\"";
-    public final static String DEFLATE="deflate";
-    public final static String ETAG_DEFLATE="--deflate\"";
-    public final static String ETAG="o.e.j.s.GzipFilter.ETag";
 
-    protected ServletContext _context;
-    protected final Set<String> _mimeTypes=new HashSet<>();
-    protected boolean _excludeMimeTypes;
-    protected int _bufferSize=8192;
-    protected int _minGzipSize=256;
-    protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION;
-    protected boolean _deflateNoWrap = true;
-    protected boolean _checkGzExists = true;
-    
-    // non-static, as other GzipFilter instances may have different configurations
-    protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
-
-    protected final static ThreadLocal<byte[]> _buffer= new ThreadLocal<byte[]>();
-
-    protected final Set<String> _methods=new HashSet<String>();
-    protected Set<String> _excludedAgents;
-    protected Set<Pattern> _excludedAgentPatterns;
-    protected Set<String> _excludedPaths;
-    protected Set<Pattern> _excludedPathPatterns;
-    protected String _vary="Accept-Encoding, User-Agent";
-    
-    private static final int STATE_SEPARATOR = 0;
-    private static final int STATE_Q = 1;
-    private static final int STATE_QVALUE = 2;
-    private static final int STATE_DEFAULT = 3;
-
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#init(javax.servlet.FilterConfig)
-     */
     @Override
     public void init(FilterConfig filterConfig) throws ServletException
-    {
-        super.init(filterConfig);
-
-        _context=filterConfig.getServletContext();
-        
-        String tmp=filterConfig.getInitParameter("bufferSize");
-        if (tmp!=null)
-            _bufferSize=Integer.parseInt(tmp);
-
-        tmp=filterConfig.getInitParameter("minGzipSize");
-        if (tmp!=null)
-            _minGzipSize=Integer.parseInt(tmp);
-
-        tmp=filterConfig.getInitParameter("deflateCompressionLevel");
-        if (tmp!=null)
-            _deflateCompressionLevel=Integer.parseInt(tmp);
-
-        tmp=filterConfig.getInitParameter("deflateNoWrap");
-        if (tmp!=null)
-            _deflateNoWrap=Boolean.parseBoolean(tmp);
-
-        tmp=filterConfig.getInitParameter("checkGzExists");
-        if (tmp!=null)
-            _checkGzExists=Boolean.parseBoolean(tmp);
-        
-        tmp=filterConfig.getInitParameter("methods");
-        if (tmp!=null)
-        {
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _methods.add(tok.nextToken().trim().toUpperCase(Locale.ENGLISH));
-        }
-        else
-            _methods.add(HttpMethod.GET.asString());
-        
-        tmp=filterConfig.getInitParameter("mimeTypes");
-        if (tmp==null)
-        {
-            _excludeMimeTypes=true;
-            tmp=filterConfig.getInitParameter("excludedMimeTypes");
-            if (tmp==null)
-            {
-                for (String type:MimeTypes.getKnownMimeTypes())
-                {
-                    if (type.equals("image/svg+xml")) //always compressable (unless .svgz file)
-                        continue;
-                    if (type.startsWith("image/")||
-                        type.startsWith("audio/")||
-                        type.startsWith("video/"))
-                        _mimeTypes.add(type);
-                }
-                _mimeTypes.add("application/compress");
-                _mimeTypes.add("application/zip");
-                _mimeTypes.add("application/gzip");
-            }
-            else
-            {
-                StringTokenizer tok = new StringTokenizer(tmp,",",false);
-                while (tok.hasMoreTokens())
-                    _mimeTypes.add(tok.nextToken().trim());
-            }
-        }
-        else
-        {
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _mimeTypes.add(tok.nextToken().trim());
-        }
-        tmp=filterConfig.getInitParameter("excludedAgents");
-        if (tmp!=null)
-        {
-            _excludedAgents=new HashSet<String>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-               _excludedAgents.add(tok.nextToken().trim());
-        }
-
-        tmp=filterConfig.getInitParameter("excludeAgentPatterns");
-        if (tmp!=null)
-        {
-            _excludedAgentPatterns=new HashSet<Pattern>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedAgentPatterns.add(Pattern.compile(tok.nextToken().trim()));
-        }
-
-        tmp=filterConfig.getInitParameter("excludePaths");
-        if (tmp!=null)
-        {
-            _excludedPaths=new HashSet<String>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedPaths.add(tok.nextToken().trim());
-        }
-
-        tmp=filterConfig.getInitParameter("excludePathPatterns");
-        if (tmp!=null)
-        {
-            _excludedPathPatterns=new HashSet<Pattern>();
-            StringTokenizer tok = new StringTokenizer(tmp,",",false);
-            while (tok.hasMoreTokens())
-                _excludedPathPatterns.add(Pattern.compile(tok.nextToken().trim()));
-        }
-        
-        tmp=filterConfig.getInitParameter("vary");
-        if (tmp!=null)
-            _vary=tmp;
+    {        
+        LOG.warn("GzipFilter is deprecated. Use GzipHandler");
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#destroy()
-     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+    {
+        chain.doFilter(request,response);
+    }
+
     @Override
     public void destroy()
-    {
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
-     */
-    @Override
-    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
-        throws IOException, ServletException
-    {
-        HttpServletRequest request=(HttpServletRequest)req;
-        HttpServletResponse response=(HttpServletResponse)res;
-
-        // If not a supported method or it is an Excluded URI - no Vary because no matter what client, this URI is always excluded
-        String requestURI = request.getRequestURI();
-        if (!_methods.contains(request.getMethod()) || isExcludedPath(requestURI))
-        {
-            super.doFilter(request,response,chain);
-            return;
-        }
-
-        // Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
-        if (_mimeTypes.size()>0 && _excludeMimeTypes)
-        {
-            String mimeType = _context.getMimeType(request.getRequestURI());
-
-            if (mimeType!=null)
-            {
-                mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);
-                if (_mimeTypes.contains(mimeType))
-                {
-                    // handle normally without setting vary header
-                    super.doFilter(request,response,chain);
-                    return;
-                }
-            }
-        }
-        
-        //If the Content-Encoding is already set, then we won't compress
-        if (response.getHeader("Content-Encoding") != null)
-        {
-            super.doFilter(request,response,chain);
-            return;
-        }
-
-        if (_checkGzExists && request.getServletContext()!=null)
-        {
-            String path=request.getServletContext().getRealPath(URIUtil.addPaths(request.getServletPath(),request.getPathInfo()));
-            if (path!=null)
-            {
-                File gz=new File(path+".gz");
-                if (gz.exists())
-                {
-                    // allow default servlet to handle
-                    super.doFilter(request,response,chain);
-                    return;
-                }
-            }
-        }
-        
-        // Excluded User-Agents
-        String ua = getUserAgent(request);
-        boolean ua_excluded=ua!=null&&isExcludedAgent(ua);
-        
-        // Acceptable compression type
-        String compressionType = ua_excluded?null:selectCompression(request.getHeader("accept-encoding"));
-
-        // Special handling for etags
-        String etag = request.getHeader("If-None-Match"); 
-        if (etag!=null)
-        {
-            int dd=etag.indexOf("--");
-            if (dd>0)
-                request.setAttribute(ETAG,etag.substring(0,dd)+(etag.endsWith("\"")?"\"":""));
-        }
-
-        CompressedResponseWrapper wrappedResponse = createWrappedResponse(request,response,compressionType);
-
-        boolean exceptional=true;
-        try
-        {
-            super.doFilter(request,wrappedResponse,chain);
-            exceptional=false;
-        }
-        finally
-        {
-            if (request.isAsyncStarted())
-            {
-                request.getAsyncContext().addListener(new FinishOnCompleteListener(wrappedResponse));
-            }
-            else if (exceptional && !response.isCommitted())
-            {
-                wrappedResponse.resetBuffer();
-                wrappedResponse.noCompression();
-            }
-            else
-                wrappedResponse.finish();
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    private String selectCompression(String encodingHeader)
-    {
-        // TODO, this could be a little more robust.
-        // prefer gzip over deflate
-        String compression = null;
-        if (encodingHeader!=null)
-        {
-            
-            String[] encodings = getEncodings(encodingHeader);
-            if (encodings != null)
-            {
-                for (int i=0; i< encodings.length; i++)
-                {
-                    if (encodings[i].toLowerCase(Locale.ENGLISH).contains(GZIP))
-                    {
-                        if (isEncodingAcceptable(encodings[i]))
-                        {
-                            compression = GZIP;
-                            break; //prefer Gzip over deflate
-                        }
-                    }
-
-                    if (encodings[i].toLowerCase(Locale.ENGLISH).contains(DEFLATE))
-                    {
-                        if (isEncodingAcceptable(encodings[i]))
-                        {
-                            compression = DEFLATE; //Keep checking in case gzip is acceptable
-                        }
-                    }
-                }
-            }
-        }
-        return compression;
+    {        
     }
     
-    
-    private String[] getEncodings (String encodingHeader)
-    {
-        if (encodingHeader == null)
-            return null;
-        return encodingHeader.split(",");
-    }
-    
-    private boolean isEncodingAcceptable(String encoding)
-    {    
-        int state = STATE_DEFAULT;
-        int qvalueIdx = -1;
-        for (int i=0;i<encoding.length();i++)
-        {
-            char c = encoding.charAt(i);
-            switch (state)
-            {
-                case STATE_DEFAULT:
-                {
-                    if (';' == c)
-                        state = STATE_SEPARATOR;
-                    break;
-                }
-                case STATE_SEPARATOR:
-                {
-                    if ('q' == c || 'Q' == c)
-                        state = STATE_Q;
-                    break;
-                }
-                case STATE_Q:
-                {
-                    if ('=' == c)
-                        state = STATE_QVALUE;
-                    break;
-                }
-                case STATE_QVALUE:
-                {
-                    if (qvalueIdx < 0 && '0' == c || '1' == c)
-                        qvalueIdx = i;
-                    break;
-                }
-            }
-        }
-        
-        if (qvalueIdx < 0)
-            return true;
-               
-        if ("0".equals(encoding.substring(qvalueIdx).trim()))
-            return false;
-        return true;
-    }
-    
-
-    protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
-    {
-        CompressedResponseWrapper wrappedResponse = null;
-        wrappedResponse = new CompressedResponseWrapper(request,response)
-        {
-            @Override
-            protected AbstractCompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response) throws IOException
-            {
-                return new AbstractCompressedStream(compressionType,request,this,_vary)
-                {
-                    private Deflater _allocatedDeflater;
-                    private byte[] _allocatedBuffer;
-
-                    @Override
-                    protected OutputStream createStream() throws IOException
-                    {
-                        if (compressionType == null)
-                        {
-                            return null;
-                        }
-                        
-                        // acquire deflater instance
-                        _allocatedDeflater = _deflater.get();   
-                        if (_allocatedDeflater==null)
-                            _allocatedDeflater = new Deflater(_deflateCompressionLevel,_deflateNoWrap);
-                        else
-                        {
-                            _deflater.set(null);
-                            _allocatedDeflater.reset();
-                        }
-                        
-                        // acquire buffer
-                        _allocatedBuffer = _buffer.get();
-                        if (_allocatedBuffer==null)
-                            _allocatedBuffer = new byte[_bufferSize];
-                        else
-                            _buffer.set(null);
-                        
-                        switch (compressionType)
-                        {
-                            case GZIP:
-                                return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
-                            case DEFLATE:
-                                return new DeflatedOutputStream(_response.getOutputStream(),_allocatedDeflater,_allocatedBuffer);
-                        }
-                        throw new IllegalStateException(compressionType + " not supported");
-                    }
-
-                    @Override
-                    public void finish() throws IOException
-                    {
-                        super.finish();
-                        if (_allocatedDeflater != null && _deflater.get() == null)
-                        {
-                            _deflater.set(_allocatedDeflater);
-                        }
-                        if (_allocatedBuffer != null && _buffer.get() == null)
-                        {
-                            _buffer.set(_allocatedBuffer);
-                        }
-                    }
-                };
-            }
-        };
-        configureWrappedResponse(wrappedResponse);
-        return wrappedResponse;
-    }
-
-    protected void configureWrappedResponse(CompressedResponseWrapper wrappedResponse)
-    {
-        IncludeExclude<String> mimeTypeExclusions = new IncludeExclude<>();
-        if(_excludeMimeTypes) 
-            mimeTypeExclusions.getExcluded().addAll(_mimeTypes);
-        else
-            mimeTypeExclusions.getIncluded().addAll(_mimeTypes);
-        
-        wrappedResponse.setMimeTypes(mimeTypeExclusions);
-        wrappedResponse.setBufferSize(_bufferSize);
-        wrappedResponse.setMinCompressSize(_minGzipSize);
-    }
-
-    private class FinishOnCompleteListener implements AsyncListener
-    {    
-        private CompressedResponseWrapper wrappedResponse;
-
-        public FinishOnCompleteListener(CompressedResponseWrapper wrappedResponse)
-        {
-            this.wrappedResponse = wrappedResponse;
-        }
-
-        @Override
-        public void onComplete(AsyncEvent event) throws IOException
-        {          
-            try
-            {
-                wrappedResponse.finish();
-            }
-            catch (IOException e)
-            {
-                LOG.warn(e);
-            }
-        }
-
-        @Override
-        public void onTimeout(AsyncEvent event) throws IOException
-        {
-        }
-
-        @Override
-        public void onError(AsyncEvent event) throws IOException
-        {
-        }
-
-        @Override
-        public void onStartAsync(AsyncEvent event) throws IOException
-        {
-        }
-    }
-
-    /**
-     * Checks to see if the userAgent is excluded
-     *
-     * @param ua
-     *            the user agent
-     * @return boolean true if excluded
-     */
-    private boolean isExcludedAgent(String ua)
-    {
-        if (ua == null)
-            return false;
-
-        if (_excludedAgents != null)
-        {
-            if (_excludedAgents.contains(ua))
-            {
-                return true;
-            }
-        }
-        if (_excludedAgentPatterns != null)
-        {
-            for (Pattern pattern : _excludedAgentPatterns)
-            {
-                if (pattern.matcher(ua).matches())
-                {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks to see if the path is excluded
-     *
-     * @param requestURI
-     *            the request uri
-     * @return boolean true if excluded
-     */
-    private boolean isExcludedPath(String requestURI)
-    {
-        if (requestURI == null)
-            return false;
-        if (_excludedPaths != null)
-        {
-            for (String excludedPath : _excludedPaths)
-            {
-                if (requestURI.startsWith(excludedPath))
-                {
-                    return true;
-                }
-            }
-        }
-        if (_excludedPathPatterns != null)
-        {
-            for (Pattern pattern : _excludedPathPatterns)
-            {
-                if (pattern.matcher(requestURI).matches())
-                {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java
index 81f7eea..16049a2 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java
@@ -18,161 +18,7 @@
 
 package org.eclipse.jetty.servlets;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
-import java.util.zip.GZIPOutputStream;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.io.UncheckedPrintWriter;
-import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
-import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
-
-/* ------------------------------------------------------------ */
-/** Includable GZip Filter.
- * This extension to the {@link GzipFilter} that uses Jetty features to allow
- * headers to be set during calls to
- * {@link javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}.
- * This allows the gzip filter to function correct during includes and to make a decision to gzip or not
- * at the time the buffer fills and on the basis of all response headers.
- *
- * If the init parameter "uncheckedPrintWriter" is set to "true", then the PrintWriter used by
- * the wrapped getWriter will be {@link UncheckedPrintWriter}.
- *
- */
+@Deprecated
 public class IncludableGzipFilter extends GzipFilter
 {
-    boolean _uncheckedPrintWriter=false;
-
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-        super.init(filterConfig);
-
-        String tmp=filterConfig.getInitParameter("uncheckedPrintWriter");
-        if (tmp!=null)
-            _uncheckedPrintWriter=Boolean.valueOf(tmp).booleanValue();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.GzipFilter#createWrappedResponse(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
-     */
-    @Override
-    protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
-    {
-        CompressedResponseWrapper wrappedResponse = null;
-        if (compressionType==null)
-        {
-            wrappedResponse = new IncludableResponseWrapper(request,response)
-            {
-                @Override
-                protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
-                {
-                    return new AbstractCompressedStream(null,request,this,_vary)
-                    {
-                        @Override
-                        protected DeflaterOutputStream createStream() throws IOException
-                        {
-                            return null;
-                        }
-                    };
-                }
-            };
-        }
-        else if (compressionType.equals(GZIP))
-        {
-            wrappedResponse = new IncludableResponseWrapper(request,response)
-            {
-                @Override
-                protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
-                {
-                    return new AbstractCompressedStream(compressionType,request,this,_vary)
-                    {
-                        @Override
-                        protected DeflaterOutputStream createStream() throws IOException
-                        {
-                            return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
-                        }
-                    };
-                }
-            };
-        }
-        else if (compressionType.equals(DEFLATE))
-        {
-            wrappedResponse = new IncludableResponseWrapper(request,response)
-            {
-                @Override
-                protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
-                {
-                    return new AbstractCompressedStream(compressionType,request,this,_vary)
-                    {
-                        @Override
-                        protected DeflaterOutputStream createStream() throws IOException
-                        {
-                            return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
-                        }
-                    };
-                }
-            };
-        }
-        else
-        {
-            throw new IllegalStateException(compressionType + " not supported");
-        }
-        configureWrappedResponse(wrappedResponse);
-        return wrappedResponse;
-    }
-
-
-    // Extend CompressedResponseWrapper to be able to set headers during include and to create unchecked printwriters
-    private abstract class IncludableResponseWrapper extends CompressedResponseWrapper
-    {
-        public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response)
-        {
-            super(request,response);
-        }
-
-        @Override
-        public void setHeader(String name,String value)
-        {
-            if (getRequest().getDispatcherType()==DispatcherType.INCLUDE)
-            {
-                if (!"etag".equalsIgnoreCase(name) && !name.startsWith("content-"))
-                {
-                    HttpServletResponse response = (HttpServletResponse)getResponse();
-                    response.setHeader("org.eclipse.jetty.server.include."+name,value);
-                }
-            }
-            else
-                super.setHeader(name,value);
-        }
-
-        @Override
-        public void addHeader(String name, String value)
-        {
-            super.addHeader(name, value);
-            HttpServletResponse response = (HttpServletResponse)getResponse();
-            if (!response.containsHeader(name))
-                setHeader(name,value);
-        }
-        
-        @Override
-        protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
-        {
-            if (_uncheckedPrintWriter)
-                return encoding == null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding));
-            return super.newWriter(out,encoding);
-        }
-    }
-
 }
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
index 00526c7..623a0af 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
@@ -56,7 +56,6 @@
 import org.eclipse.jetty.util.log.Logger;
 
 
-/* ------------------------------------------------------------ */
 /**
  * Multipart Form Data Filter.
  * <p>
@@ -95,6 +94,7 @@
  * </dl>
  * @deprecated See servlet 3.0 apis like javax.servlet.http.HttpServletRequest.getParts()
  */
+@Deprecated
 public class MultiPartFilter implements Filter
 {
     private static final Logger LOG = Log.getLogger(MultiPartFilter.class);
@@ -243,9 +243,6 @@
         MultiMap<Object> _params;
 
         /* ------------------------------------------------------------------------------- */
-        /** Constructor.
-         * @param request
-         */
         public Wrapper(HttpServletRequest request, MultiMap map)
         {
             super(request);
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java
new file mode 100644
index 0000000..73175dd
--- /dev/null
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushCacheFilter.java
@@ -0,0 +1,306 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.servlets;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.http.HttpField;
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.server.Dispatcher;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.ManagedOperation;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>A filter that builds a cache of secondary resources associated
+ * to primary resources.</p>
+ * <p>A typical request for a primary resource such as {@code index.html}
+ * is immediately followed by a number of requests for secondary resources.
+ * Secondary resource requests will have a {@code Referer} HTTP header
+ * that points to {@code index.html}, which is used to associate the secondary
+ * resource to the primary resource.</p>
+ * <p>Only secondary resources that are requested within a (small) time period
+ * from the request of the primary resource are associated with the primary
+ * resource.</p>
+ * <p>This allows to build a cache of secondary resources associated with
+ * primary resources. When a request for a primary resource arrives, associated
+ * secondary resources are pushed to the client, unless the request carries
+ * {@code If-xxx} header that hint that the client has the resources in its
+ * cache.</p>
+ */
+@ManagedObject("Push cache based on the HTTP 'Referer' header")
+public class PushCacheFilter implements Filter
+{
+    private static final Logger LOG = Log.getLogger(PushCacheFilter.class);
+
+    private final Set<Integer> _ports = new HashSet<>();
+    private final Set<String> _hosts = new HashSet<>();
+    private final ConcurrentMap<String, PrimaryResource> _cache = new ConcurrentHashMap<>();
+    private long _associatePeriod = 4000L;
+    private int _maxAssociations = 16;
+    private long _renew = System.nanoTime();
+
+    @Override
+    public void init(FilterConfig config) throws ServletException
+    {
+        String associatePeriod = config.getInitParameter("associatePeriod");
+        if (associatePeriod != null)
+            _associatePeriod = Long.parseLong(associatePeriod);
+
+        String maxAssociations = config.getInitParameter("maxAssociations");
+        if (maxAssociations != null)
+            _maxAssociations = Integer.parseInt(maxAssociations);
+
+        String hosts = config.getInitParameter("hosts");
+        if (hosts != null)
+            Collections.addAll(_hosts, StringUtil.csvSplit(hosts));
+
+        String ports = config.getInitParameter("ports");
+        if (ports != null)
+            for (String p : StringUtil.csvSplit(ports))
+                _ports.add(Integer.parseInt(p));
+
+        // Expose for JMX.
+        config.getServletContext().setAttribute(config.getFilterName(), this);
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("period={} max={} hosts={} ports={}", _associatePeriod, _maxAssociations, _hosts, _ports);
+    }
+
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException
+    {
+        if (HttpVersion.fromString(req.getProtocol()).getVersion() < 20)
+        {
+            chain.doFilter(req, resp);
+            return;
+        }
+
+        long now = System.nanoTime();
+        HttpServletRequest request = (HttpServletRequest)req;
+
+        // Iterating over fields is more efficient than multiple gets
+        HttpFields fields = Request.getBaseRequest(request).getHttpFields();
+        boolean conditional = false;
+        String referrer = null;
+        loop:
+        for (int i = 0; i < fields.size(); i++)
+        {
+            HttpField field = fields.getField(i);
+            HttpHeader header = field.getHeader();
+            if (header == null)
+                continue;
+
+            switch (header)
+            {
+                case IF_MATCH:
+                case IF_MODIFIED_SINCE:
+                case IF_NONE_MATCH:
+                case IF_UNMODIFIED_SINCE:
+                    conditional = true;
+                    break loop;
+
+                case REFERER:
+                    referrer = field.getValue();
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} {} referrer={} conditional={}", request.getMethod(), request.getRequestURI(), referrer, conditional);
+
+        String path = URIUtil.addPaths(request.getServletPath(), request.getPathInfo());
+        String query = request.getQueryString();
+        if (query != null)
+            path += "?" + query;
+        if (referrer != null)
+        {
+            HttpURI referrerURI = new HttpURI(referrer);
+            String host = referrerURI.getHost();
+            int port = referrerURI.getPort();
+            if (port <= 0)
+                port = request.isSecure() ? 443 : 80;
+
+            boolean referredFromHere = _hosts.size() > 0 ? _hosts.contains(host) : host.equals(request.getServerName());
+            referredFromHere &= _ports.size() > 0 ? _ports.contains(port) : port == request.getServerPort();
+
+            if (referredFromHere)
+            {
+                if ("GET".equalsIgnoreCase(request.getMethod()))
+                {
+                    String referrerPath = referrerURI.getPath();
+                    if (referrerPath == null)
+                        referrerPath = "/";
+                    if (referrerPath.startsWith(request.getContextPath()))
+                    {
+                        String referrerPathNoContext = referrerPath.substring(request.getContextPath().length());
+                        if (!referrerPathNoContext.equals(path))
+                        {
+                            PrimaryResource primaryResource = _cache.get(referrerPathNoContext);
+                            if (primaryResource != null)
+                            {
+                                long primaryTimestamp = primaryResource._timestamp.get();
+                                if (primaryTimestamp != 0)
+                                {
+                                    RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher(path);
+                                    if (now - primaryTimestamp < TimeUnit.MILLISECONDS.toNanos(_associatePeriod))
+                                    {
+                                        ConcurrentMap<String, RequestDispatcher> associated = primaryResource._associated;
+                                        // Not strictly concurrent-safe, just best effort to limit associations.
+                                        if (associated.size() <= _maxAssociations)
+                                        {
+                                            if (associated.putIfAbsent(path, dispatcher) == null)
+                                            {
+                                                if (LOG.isDebugEnabled())
+                                                    LOG.debug("Associated {} to {}", path, referrerPathNoContext);
+                                            }
+                                        }
+                                        else
+                                        {
+                                            if (LOG.isDebugEnabled())
+                                                LOG.debug("Not associated {} to {}, exceeded max associations of {}", path, referrerPathNoContext, _maxAssociations);
+                                        }
+                                    }
+                                    else
+                                    {
+                                        if (LOG.isDebugEnabled())
+                                            LOG.debug("Not associated {} to {}, outside associate period of {}ms", path, referrerPathNoContext, _associatePeriod);
+                                    }
+                                }
+                            }
+                        }
+                        else
+                        {
+                            if (LOG.isDebugEnabled())
+                                LOG.debug("Not associated {} to {}, referring to self", path, referrerPathNoContext);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("External referrer {}", referrer);
+            }
+        }
+
+        // Push some resources?
+        PrimaryResource primaryResource = _cache.get(path);
+        if (primaryResource == null)
+        {
+            PrimaryResource t = new PrimaryResource();
+            primaryResource = _cache.putIfAbsent(path, t);
+            primaryResource = primaryResource == null ? t : primaryResource;
+            primaryResource._timestamp.compareAndSet(0, now);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Cached primary resource {}", path);
+        }
+        else
+        {
+            long last = primaryResource._timestamp.get();
+            if (last < _renew && primaryResource._timestamp.compareAndSet(last, now))
+            {
+                primaryResource._associated.clear();
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Clear associated resources for {}", path);
+            }
+        }
+
+        // Push associated for non conditional
+        if (!conditional && !primaryResource._associated.isEmpty())
+        {
+            for (RequestDispatcher dispatcher : primaryResource._associated.values())
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Pushing {} for {}", dispatcher, path);
+                ((Dispatcher)dispatcher).push(request);
+            }
+        }
+
+        chain.doFilter(request, resp);
+    }
+
+    @Override
+    public void destroy()
+    {
+        clearPushCache();
+    }
+
+    @ManagedAttribute("The push cache contents")
+    public Map<String, String> getPushCache()
+    {
+        Map<String, String> result = new HashMap<>();
+        for (Map.Entry<String, PrimaryResource> entry : _cache.entrySet())
+        {
+            PrimaryResource resource = entry.getValue();
+            String value = String.format("size=%d: %s", resource._associated.size(), new TreeSet<>(resource._associated.keySet()));
+            result.put(entry.getKey(), value);
+        }
+        return result;
+    }
+
+    @ManagedOperation(value = "Renews the push cache contents", impact = "ACTION")
+    public void renewPushCache()
+    {
+        _renew = System.nanoTime();
+    }
+
+    @ManagedOperation(value = "Clears the push cache contents", impact = "ACTION")
+    public void clearPushCache()
+    {
+        _cache.clear();
+    }
+
+    private static class PrimaryResource
+    {
+        private final ConcurrentMap<String, RequestDispatcher> _associated = new ConcurrentHashMap<>();
+        private final AtomicLong _timestamp = new AtomicLong();
+    }
+}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
new file mode 100644
index 0000000..4d4f313
--- /dev/null
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
@@ -0,0 +1,214 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.servlets;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.server.PushBuilder;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class PushSessionCacheFilter implements Filter
+{
+    private static final String TARGET_ATTR="PushCacheFilter.target";
+    private static final String TIMESTAMP_ATTR="PushCacheFilter.timestamp";
+    private static final Logger LOG = Log.getLogger(PushSessionCacheFilter.class);
+    private final ConcurrentMap<String, Target> _cache = new ConcurrentHashMap<>();
+    
+    private long _associateDelay=5000L;
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
+     */
+    @Override
+    public void init(FilterConfig config) throws ServletException
+    {
+        if (config.getInitParameter("associateDelay")!=null)
+            _associateDelay=Long.valueOf(config.getInitParameter("associateDelay"));
+        
+        // Add a listener that is used to collect information about associated resource,
+        // etags and modified dates
+        config.getServletContext().addListener(new ServletRequestListener()
+        {
+            // Collect information when request is destroyed.
+            @Override
+            public void requestDestroyed(ServletRequestEvent sre)
+            {
+                Request request = Request.getBaseRequest(sre.getServletRequest());
+                Target target = (Target)request.getAttribute(TARGET_ATTR);
+                if (target==null)
+                    return;
+
+                // Update conditional data
+                Response response = request.getResponse();
+                target._etag=response.getHttpFields().get(HttpHeader.ETAG);
+                target._lastModified=response.getHttpFields().get(HttpHeader.LAST_MODIFIED);
+                
+                // Don't associate pushes
+                if (request.isPush())
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Pushed {} for {}",request.getResponse().getStatus(),request.getRequestURI());
+                    return;
+                } 
+                else if (LOG.isDebugEnabled())
+                    LOG.debug("Served {} for {}",request.getResponse().getStatus(),request.getRequestURI());
+                
+                // Does this request have a referer?
+                String referer = request.getHttpFields().get(HttpHeader.REFERER);
+                
+                if (referer!=null)
+                {
+                    // Is the referer from this contexts?
+                    HttpURI referer_uri = new HttpURI(referer);
+                    if (request.getServerName().equals(referer_uri.getHost()))
+                    {
+                        Target referer_target = _cache.get(referer_uri.getPath());
+                        if (referer_target!=null)
+                        {
+                            HttpSession session = request.getSession();                            
+                            ConcurrentHashMap<String, Long> timestamps = (ConcurrentHashMap<String, Long>)session.getAttribute(TIMESTAMP_ATTR);
+                            Long last = timestamps.get(referer_target._path);
+                            if (last!=null && (System.currentTimeMillis()-last)<_associateDelay)
+                            {
+                                if (referer_target._associated.putIfAbsent(target._path,target)==null)
+                                {
+                                    if (LOG.isDebugEnabled())
+                                        LOG.debug("ASSOCIATE {}->{}",referer_target._path,target._path);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void requestInitialized(ServletRequestEvent sre)
+            {
+            }
+            
+        });
+        
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+    { 
+        // Get Jetty request as these APIs are not yet standard
+        Request baseRequest = Request.getBaseRequest(request);
+        String uri=baseRequest.getRequestURI();
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} {} push={}",baseRequest.getMethod(),uri,baseRequest.isPush());
+
+        HttpSession session = baseRequest.getSession(true);
+
+        // find the target for this resource
+        Target target = _cache.get(uri);
+        if (target == null)
+        {
+            Target t=new Target(uri);
+            target = _cache.putIfAbsent(uri,t);
+            target = target==null?t:target;
+        }
+        request.setAttribute(TARGET_ATTR,target);
+        
+        // Set the timestamp for this resource in this session
+        ConcurrentHashMap<String, Long> timestamps = (ConcurrentHashMap<String, Long>)session.getAttribute(TIMESTAMP_ATTR);
+        if (timestamps==null)
+        {
+            timestamps=new ConcurrentHashMap<>();
+            session.setAttribute(TIMESTAMP_ATTR,timestamps);
+        }
+        timestamps.put(uri,System.currentTimeMillis());
+        
+        // push any associated resources
+        if (baseRequest.isPushSupported() && target._associated.size()>0)
+        {
+            PushBuilder builder = baseRequest.getPushBuilder();
+            builder.addHeader("X-Pusher",PushSessionCacheFilter.class.toString());
+            for (Target associated : target._associated.values())
+            {
+                String path = associated._path;
+                if (LOG.isDebugEnabled())
+                    LOG.debug("PUSH {} <- {}",path,uri);
+                
+                builder.path(path).etag(associated._etag).lastModified(associated._lastModified).push();
+            }
+        }
+
+        chain.doFilter(request,response);
+    }
+
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @see javax.servlet.Filter#destroy()
+     */
+    @Override
+    public void destroy()
+    {        
+    }
+
+    
+    public static class Target
+    {
+        final String _path;
+        final ConcurrentMap<String,Target> _associated = new ConcurrentHashMap<>();
+        volatile String _etag;
+        volatile String _lastModified;
+        
+        public Target(String path)
+        {
+            _path=path;
+        }
+        
+        @Override
+        public String toString()
+        {
+            return String.format("Target{p=%s,e=%s,m=%s,a=%d}",_path,_etag,_lastModified,_associated.size());
+        }
+    }
+}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java
index bb30593..8c9aadb 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/QoSFilter.java
@@ -23,6 +23,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncEvent;
 import javax.servlet.AsyncListener;
@@ -45,19 +46,19 @@
 
 /**
  * Quality of Service Filter.
- * <p/>
+ * <p>
  * This filter limits the number of active requests to the number set by the "maxRequests" init parameter (default 10).
  * If more requests are received, they are suspended and placed on priority queues.  Priorities are determined by
  * the {@link #getPriority(ServletRequest)} method and are a value between 0 and the value given by the "maxPriority"
  * init parameter (default 10), with higher values having higher priority.
- * <p/>
+ * <p>
  * This filter is ideal to prevent wasting threads waiting for slow/limited
  * resources such as a JDBC connection pool.  It avoids the situation where all of a
  * containers thread pool may be consumed blocking on such a slow resource.
  * By limiting the number of active threads, a smaller thread pool may be used as
  * the threads are not wasted waiting.  Thus more memory may be available for use by
  * the active threads.
- * <p/>
+ * <p>
  * Furthermore, this filter uses a priority when resuming waiting requests. So that if
  * a container is under load, and there are many requests waiting for resources,
  * the {@link #getPriority(ServletRequest)} method is used, so that more important
@@ -65,12 +66,12 @@
  * maxRequest limit slightly smaller than the containers thread pool and a high priority
  * allocated to admin users.  Thus regardless of load, admin users would always be
  * able to access the web application.
- * <p/>
+ * <p>
  * The maxRequest limit is policed by a {@link Semaphore} and the filter will wait a short while attempting to acquire
  * the semaphore. This wait is controlled by the "waitMs" init parameter and allows the expense of a suspend to be
  * avoided if the semaphore is shortly available.  If the semaphore cannot be obtained, the request will be suspended
  * for the default suspend period of the container or the valued set as the "suspendMs" init parameter.
- * <p/>
+ * <p>
  * If the "managedAttr" init parameter is set to true, then this servlet is set as a {@link ServletContext} attribute with the
  * filter name as the attribute name.  This allows context external mechanism (eg JMX via {@link ContextHandler#MANAGED_ATTRIBUTES}) to
  * manage the configuration of the filter.
@@ -236,7 +237,7 @@
 
     /**
      * Computes the request priority.
-     * <p/>
+     * <p>
      * The default implementation assigns the following priorities:
      * <ul>
      * <li> 2 - for an authenticated request
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/UserAgentFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/UserAgentFilter.java
deleted file mode 100644
index d9e22e8..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/UserAgentFilter.java
+++ /dev/null
@@ -1,158 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-/* ------------------------------------------------------------ */
-/** User Agent Filter.
- * <p>
- * This filter allows efficient matching of user agent strings for
- * downstream or extended filters to use for browser specific logic.
- * </p>
- * <p>
- * The filter is configured with the following init parameters:
- * <dl>
- * <dt>attribute</dt><dd>If set, then the request attribute of this name is set with the matched user agent string</dd>
- * <dt>cacheSize</dt><dd>The size of the user-agent cache, used to avoid reparsing of user agent strings. The entire cache is flushed
- * when this size is reached</dd>
- * <dt>userAgent</dt><dd>A regex {@link Pattern} to extract the essential elements of the user agent.
- * The concatenation of matched pattern groups is used as the user agent name</dd>
- * <dl>
- * An example value for pattern is <code>(?:Mozilla[^\(]*\(compatible;\s*+([^;]*);.*)|(?:.*?([^\s]+/[^\s]+).*)</code>. These two
- * pattern match the common compatibility user-agent strings and extract the real user agent, failing that, the first
- * element of the agent string is returned.
- *
- *
- */
-public class UserAgentFilter implements Filter
-{
-    private static final String __defaultPattern = "(?:Mozilla[^\\(]*\\(compatible;\\s*+([^;]*);.*)|(?:.*?([^\\s]+/[^\\s]+).*)";
-    private Pattern _pattern = Pattern.compile(__defaultPattern);
-    private Map<String, String> _agentCache = new ConcurrentHashMap<String, String>();
-    private int _agentCacheSize=1024;
-    private String _attribute;
-
-    /* ------------------------------------------------------------ */
-    /* (non-Javadoc)
-     * @see javax.servlet.Filter#destroy()
-     */
-    public void destroy()
-    {
-    }
-
-    /* ------------------------------------------------------------ */
-    /* (non-Javadoc)
-     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
-     */
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
-    {
-        if (_attribute!=null && _pattern!=null)
-        {
-            String ua=getUserAgent(request);
-            request.setAttribute(_attribute,ua);
-        }
-        chain.doFilter(request,response);
-    }
-
-    /* ------------------------------------------------------------ */
-    /* (non-Javadoc)
-     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
-     */
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-        _attribute=filterConfig.getInitParameter("attribute");
-
-        String p=filterConfig.getInitParameter("userAgent");
-        if (p!=null)
-            _pattern=Pattern.compile(p);
-
-        String size=filterConfig.getInitParameter("cacheSize");
-        if (size!=null)
-            _agentCacheSize=Integer.parseInt(size);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String getUserAgent(ServletRequest request)
-    {
-        String ua=((HttpServletRequest)request).getHeader("User-Agent");
-        return getUserAgent(ua);
-    }
-
-    /* ------------------------------------------------------------ */
-    /** Get UserAgent.
-     * The configured agent patterns are used to match against the passed user agent string.
-     * If any patterns match, the concatenation of pattern groups is returned as the user agent
-     * string. Match results are cached.
-     * @param ua A user agent string
-     * @return The matched pattern groups or the original user agent string
-     */
-    public String getUserAgent(String ua)
-    {
-        if (ua == null)
-            return null;
-
-        String tag = _agentCache.get(ua);
-
-        if (tag == null)
-        {
-            if (_pattern != null)
-            {
-                Matcher matcher = _pattern.matcher(ua);
-                if (matcher.matches())
-                {
-                    if (matcher.groupCount() > 0)
-                    {
-                        for (int g = 1; g <= matcher.groupCount(); g++)
-                        {
-                            String group = matcher.group(g);
-                            if (group != null)
-                                tag = tag == null ? group : tag + group;
-                        }
-                    }
-                    else
-                    {
-                        tag = matcher.group();
-                    }
-                }
-            }
-
-            if (tag == null)
-                tag = ua;
-
-            if (_agentCache.size() >= _agentCacheSize)
-                _agentCache.clear();
-            _agentCache.put(ua, tag);
-        }
-
-        return tag;
-    }
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/AbstractCompressedStream.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/AbstractCompressedStream.java
deleted file mode 100644
index 9e113f3..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/AbstractCompressedStream.java
+++ /dev/null
@@ -1,409 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.util.ByteArrayOutputStream2;
-
-/* ------------------------------------------------------------ */
-/**
- * Skeletal implementation of a CompressedStream. This class adds compression features to a ServletOutputStream and takes care of setting response headers, etc.
- * Major work and configuration is done here. Subclasses using different kinds of compression only have to implement the abstract methods doCompress() and
- * setContentEncoding() using the desired compression and setting the appropriate Content-Encoding header string.
- */
-public abstract class AbstractCompressedStream extends ServletOutputStream
-{
-    private final String _encoding;
-    protected final String _vary;
-    private final HttpServletRequest _request;
-    protected final CompressedResponseWrapper _wrapper;
-    protected final HttpServletResponse _response;
-    protected OutputStream _out;
-    protected ByteArrayOutputStream2 _bOut;
-    protected OutputStream _compressedOutputStream;
-    protected boolean _closed;
-    protected boolean _doNotCompress;
-
-    /**
-     * Instantiates a new compressed stream.
-     *
-     */
-    public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper,String vary)
-            throws IOException
-    {
-        _encoding=encoding;
-        _request = request;
-        _wrapper = wrapper;
-        _response = (HttpServletResponse)wrapper.getResponse();
-        _vary=vary;
-
-        if (_wrapper.getMinCompressSize()==0)
-            doCompress();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Reset buffer.
-     */
-    public void resetBuffer()
-    {
-        if (_response.isCommitted() || _compressedOutputStream!=null )
-            throw new IllegalStateException("Committed");
-        _closed = false;
-        _out = null;
-        _bOut = null;
-        _doNotCompress = false;
-    }
-
-    /* ------------------------------------------------------------ */
-    public void setBufferSize(int bufferSize)
-    {
-        if (_bOut!=null && _bOut.getBuf().length<bufferSize)
-        {
-            ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize);
-            b.write(_bOut.getBuf(),0,_bOut.size());
-            _bOut=b;
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    public void setContentLength()
-    {
-        if (_doNotCompress)
-        {
-            long length=_wrapper.getContentLength();
-            if (length>=0)
-            {
-                if (length < Integer.MAX_VALUE)
-                    _response.setContentLength((int)length);
-                else
-                    _response.setHeader("Content-Length",Long.toString(length));
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see java.io.OutputStream#flush()
-     */
-    @Override
-    public void flush() throws IOException
-    {
-        if (_out == null || _bOut != null)
-        {
-            long length=_wrapper.getContentLength();
-            if (length > 0 && length < _wrapper.getMinCompressSize())
-                doNotCompress(false);
-            else
-                doCompress();
-        }
-
-        _out.flush();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see java.io.OutputStream#close()
-     */
-    @Override
-    public void close() throws IOException
-    {
-        if (_closed)
-            return;
-
-        if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null)
-            flush();
-        else
-        {
-            if (_bOut != null)
-            {
-                long length=_wrapper.getContentLength();
-                if (length < 0)
-                {
-                    length = _bOut.getCount();
-                    _wrapper.setContentLength(length);
-                }
-                if (length < _wrapper.getMinCompressSize())
-                    doNotCompress(false);
-                else
-                    doCompress();
-            }
-            else if (_out == null)
-            {
-                // No output
-                doNotCompress(false);
-            }
-
-            if (_compressedOutputStream != null)
-                _compressedOutputStream.close();
-            else
-                _out.close();
-            _closed = true;
-        }
-    }
-
-    /**
-     * Finish.
-     *
-     * @throws IOException
-     *             Signals that an I/O exception has occurred.
-     */
-    public void finish() throws IOException
-    {
-        if (!_closed)
-        {
-            if (_out == null || _bOut != null)
-            {
-                long length=_wrapper.getContentLength();
-                if (length<0 &&_bOut==null || length >= 0 && length < _wrapper.getMinCompressSize())
-                    doNotCompress(false);
-                else
-                    doCompress();
-            }
-
-            if (_compressedOutputStream != null && !_closed)
-            {
-                _closed = true;
-                _compressedOutputStream.close();
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see java.io.OutputStream#write(int)
-     */
-    @Override
-    public void write(int b) throws IOException
-    {
-        checkOut(1);
-        _out.write(b);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see java.io.OutputStream#write(byte[])
-     */
-    @Override
-    public void write(byte b[]) throws IOException
-    {
-        checkOut(b.length);
-        _out.write(b);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see java.io.OutputStream#write(byte[], int, int)
-     */
-    @Override
-    public void write(byte b[], int off, int len) throws IOException
-    {
-        checkOut(len);
-        _out.write(b,off,len);
-    }
-
-    /**
-     * Do compress.
-     *
-     * @throws IOException Signals that an I/O exception has occurred.
-     */
-    public void doCompress() throws IOException
-    {
-        if (_compressedOutputStream==null)
-        {
-            if (_response.isCommitted())
-                throw new IllegalStateException();
-
-            if (_encoding!=null)
-            {
-                String prefix = "";
-                if (_request.getDispatcherType() == DispatcherType.INCLUDE)
-                    prefix = Response.SET_INCLUDE_HEADER_PREFIX;
-                setHeader(prefix+"Content-Encoding", _encoding);
-
-                if (_response.containsHeader("Content-Encoding"))
-                {
-                    addHeader(prefix+"Vary",_vary);
-                    _out=_compressedOutputStream=createStream();
-                    if (_out!=null)
-                    {
-                        if (_bOut!=null)
-                        {
-                            _out.write(_bOut.getBuf(),0,_bOut.getCount());
-                            _bOut=null;
-                        }
-
-                        String etag=_wrapper.getETag();
-                        if (etag!=null)
-                        {
-                            int end = etag.length()-1;
-                            if (etag.charAt(end)=='"')
-                                setHeader(prefix+"ETag",etag.substring(0,end)+"--"+_encoding+'"');
-                            else
-                                setHeader(prefix+"ETag",etag+"--"+_encoding);
-                        }
-                        return;
-                    }
-                }
-            }
-
-            doNotCompress(true); // Send vary as it could have been compressed if encoding was present
-        }
-    }
-
-    /**
-     * Do not compress.
-     *
-     * @throws IOException
-     *             Signals that an I/O exception has occurred.
-     */
-    public void doNotCompress(boolean sendVary) throws IOException
-    {
-        if (_compressedOutputStream != null)
-            throw new IllegalStateException("Compressed output stream is already assigned.");
-        if (_out == null || _bOut != null)
-        {
-            if (sendVary)
-                addHeader("Vary",_vary);
-            if (_wrapper.getETag()!=null)
-                setHeader("ETag",_wrapper.getETag());
-
-            _doNotCompress = true;
-
-            _out = _response.getOutputStream();
-            setContentLength();
-
-            if (_bOut != null)
-                _out.write(_bOut.getBuf(),0,_bOut.getCount());
-            _bOut = null;
-        }
-    }
-
-    /**
-     * Check out.
-     *
-     * @param lengthToWrite
-     *            the length
-     * @throws IOException
-     *             Signals that an I/O exception has occurred.
-     */
-    private void checkOut(int lengthToWrite) throws IOException
-    {
-        if (_closed)
-            throw new IOException("CLOSED");
-
-        if (_out == null)
-        {
-            // If this first write is larger than buffer size, then we are committing now
-            if (lengthToWrite>_wrapper.getBufferSize())
-            {
-                // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress
-                long length=_wrapper.getContentLength();
-                if (length>=0 && length<_wrapper.getMinCompressSize())
-                    doNotCompress(false);  // Not compressing by size, so no vary on request headers
-                else
-                    doCompress();
-            }
-            else
-            {
-                // start aggregating writes into a buffered output stream
-                _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
-            }
-        }
-        // else are we aggregating writes?
-        else if (_bOut !=null)
-        {
-            // We are aggregating into the buffered output stream.
-
-            // If this write fills the buffer, then we are committing
-            if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount()))
-            {
-                // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress
-                long length=_wrapper.getContentLength();
-                if (length>=0 && length<_wrapper.getMinCompressSize())
-                    doNotCompress(false);  // Not compressing by size, so no vary on request headers
-                else
-                    doCompress();
-            }
-        }
-    }
-
-    public OutputStream getOutputStream()
-    {
-        return _out;
-    }
-
-    public boolean isClosed()
-    {
-        return _closed;
-    }
-
-    /**
-     * Allows derived implementations to replace PrintWriter implementation.
-     */
-    protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
-    {
-        return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
-    }
-
-    protected void addHeader(String name,String value)
-    {
-        _response.addHeader(name, value);
-    }
-
-    protected void setHeader(String name,String value)
-    {
-        _response.setHeader(name, value);
-    }
-
-    @Override
-    public void setWriteListener(WriteListener writeListener)
-    {
-        throw new UnsupportedOperationException("Use AsyncGzipFilter");
-    }
-
-
-    @Override
-    public boolean isReady()
-    {
-        throw new UnsupportedOperationException("Use AsyncGzipFilter");
-    }
-
-    /**
-     * Create the stream fitting to the underlying compression type.
-     *
-     * @throws IOException
-     *             Signals that an I/O exception has occurred.
-     */
-    protected abstract OutputStream createStream() throws IOException;
-
-
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/CompressedResponseWrapper.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/CompressedResponseWrapper.java
deleted file mode 100644
index 099125a..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/CompressedResponseWrapper.java
+++ /dev/null
@@ -1,483 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-
-import org.eclipse.jetty.util.IncludeExclude;
-import org.eclipse.jetty.util.StringUtil;
-
-/*------------------------------------------------------------ */
-/**
- */
-public abstract class CompressedResponseWrapper extends HttpServletResponseWrapper
-{
-
-    public static final int DEFAULT_BUFFER_SIZE = 8192;
-    public static final int DEFAULT_MIN_COMPRESS_SIZE = 256;
-
-    private IncludeExclude<String> _mimeTypes;
-    private int _bufferSize=DEFAULT_BUFFER_SIZE;
-    private int _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE;
-    protected HttpServletRequest _request;
-
-    private PrintWriter _writer;
-    private AbstractCompressedStream _compressedStream;
-    private String _etag;
-    private long _contentLength=-1;
-    private boolean _noCompression;
-
-    /* ------------------------------------------------------------ */
-    public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response)
-    {
-        super(response);
-        _request = request;
-    }
-
-
-    /* ------------------------------------------------------------ */
-    public long getContentLength()
-    {
-        return _contentLength;
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public int getBufferSize()
-    {
-        return _bufferSize;
-    }
-    
-    /* ------------------------------------------------------------ */
-    public int getMinCompressSize()
-    {
-        return _minCompressSize;
-    }
-    
-    /* ------------------------------------------------------------ */
-    public String getETag()
-    {
-        return _etag;
-    }
-
-    /* ------------------------------------------------------------ */
-    public HttpServletRequest getRequest()
-    {
-        return _request;
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     */
-    public void setMimeTypes(IncludeExclude<String> mimeTypes)
-    {
-        _mimeTypes = mimeTypes;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     */
-    @Override
-    public void setBufferSize(int bufferSize)
-    {
-        _bufferSize = bufferSize;
-        if (_compressedStream!=null)
-            _compressedStream.setBufferSize(bufferSize);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setMinCompressSize(int)
-     */
-    public void setMinCompressSize(int minCompressSize)
-    {
-        _minCompressSize = minCompressSize;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setContentType(java.lang.String)
-     */
-    @Override
-    public void setContentType(String ct)
-    {
-        super.setContentType(ct);
-
-        if (!_noCompression && (_compressedStream==null || _compressedStream.getOutputStream()==null))
-        {
-            if (ct!=null)
-            {
-                int colon=ct.indexOf(";");
-                if (colon>0)
-                    ct=ct.substring(0,colon);
-
-                if (!_mimeTypes.matches(StringUtil.asciiToLowerCase(ct)))
-                    noCompression();
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setStatus(int, java.lang.String)
-     */
-    @SuppressWarnings("deprecation")
-    @Override
-    public void setStatus(int sc, String sm)
-    {
-        super.setStatus(sc,sm);
-        if (sc<200 || sc==204 || sc==205 || sc>=300)
-            noCompression();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setStatus(int)
-     */
-    @Override
-    public void setStatus(int sc)
-    {
-        super.setStatus(sc);
-        if (sc<200 || sc==204 || sc==205 || sc>=300)
-            noCompression();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setContentLength(int)
-     */
-    @Override
-    public void setContentLength(int length)
-    {
-        if (_noCompression)
-            super.setContentLength(length);
-        else
-            setContentLength((long)length);
-    }
-
-    /* ------------------------------------------------------------ */
-    protected void setContentLength(long length)
-    {
-        _contentLength=length;
-        if (_compressedStream!=null)
-            _compressedStream.setContentLength();
-        else if (_noCompression && _contentLength>=0)
-        {
-            HttpServletResponse response = (HttpServletResponse)getResponse();
-            if(_contentLength<Integer.MAX_VALUE)
-            {
-                response.setContentLength((int)_contentLength);
-            }
-            else
-            {
-                response.setHeader("Content-Length", Long.toString(_contentLength));
-            }
-        }
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#addHeader(java.lang.String, java.lang.String)
-     */
-    @Override
-    public void addHeader(String name, String value)
-    {
-        if ("content-length".equalsIgnoreCase(name))
-        {
-            _contentLength=Long.parseLong(value);
-            if (_compressedStream!=null)
-                _compressedStream.setContentLength();
-        }
-        else if ("content-type".equalsIgnoreCase(name))
-        {
-            setContentType(value);
-        }
-        else if ("content-encoding".equalsIgnoreCase(name))
-        {
-            super.addHeader(name,value);
-            if (!isCommitted())
-            {
-                noCompression();
-            }
-        }
-        else if ("etag".equalsIgnoreCase(name))
-            _etag=value;
-        else
-            super.addHeader(name,value);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#flushBuffer()
-     */
-    @Override
-    public void flushBuffer() throws IOException
-    {
-        if (_writer!=null)
-            _writer.flush();
-        if (_compressedStream!=null)
-            _compressedStream.flush();
-        else
-            getResponse().flushBuffer();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#reset()
-     */
-    @Override
-    public void reset()
-    {
-        super.reset();
-        if (_compressedStream!=null)
-            _compressedStream.resetBuffer();
-        _writer=null;
-        _compressedStream=null;
-        _noCompression=false;
-        _contentLength=-1;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#resetBuffer()
-     */
-    @Override
-    public void resetBuffer()
-    {
-        super.resetBuffer();
-        if (_compressedStream!=null)
-            _compressedStream.resetBuffer();
-        _writer=null;
-        _compressedStream=null;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#sendError(int, java.lang.String)
-     */
-    @Override
-    public void sendError(int sc, String msg) throws IOException
-    {
-        resetBuffer();
-        super.sendError(sc,msg);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#sendError(int)
-     */
-    @Override
-    public void sendError(int sc) throws IOException
-    {
-        resetBuffer();
-        super.sendError(sc);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#sendRedirect(java.lang.String)
-     */
-    @Override
-    public void sendRedirect(String location) throws IOException
-    {
-        resetBuffer();
-        super.sendRedirect(location);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#noCompression()
-     */
-    public void noCompression()
-    {
-        if (!_noCompression)
-            setDeferredHeaders();
-        _noCompression=true;
-        if (_compressedStream!=null)
-        {
-            try
-            {
-                _compressedStream.doNotCompress(false);
-            }
-            catch (IOException e)
-            {
-                throw new IllegalStateException(e);
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#finish()
-     */
-    public void finish() throws IOException
-    {
-        if (_writer!=null && !_compressedStream.isClosed())
-            _writer.flush();
-        if (_compressedStream!=null)
-            _compressedStream.finish();
-        else 
-            setDeferredHeaders();
-    }
-
-    /* ------------------------------------------------------------ */
-    private void setDeferredHeaders()
-    {
-        if (!isCommitted())
-        {
-            if (_contentLength>=0)
-            {
-                if (_contentLength < Integer.MAX_VALUE)
-                    super.setContentLength((int)_contentLength);
-                else
-                    super.setHeader("Content-Length",Long.toString(_contentLength));
-            }
-            if(_etag!=null)
-                super.setHeader("ETag",_etag);
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setHeader(java.lang.String, java.lang.String)
-     */
-    @Override
-    public void setHeader(String name, String value)
-    {
-        if (_noCompression)
-            super.setHeader(name,value);
-        else if ("content-length".equalsIgnoreCase(name))
-        {
-            setContentLength(Long.parseLong(value));
-        }
-        else if ("content-type".equalsIgnoreCase(name))
-        {
-            setContentType(value);
-        }
-        else if ("content-encoding".equalsIgnoreCase(name))
-        {
-            super.setHeader(name,value);
-            if (!isCommitted())
-            {
-                noCompression();
-            }
-        }
-        else if ("etag".equalsIgnoreCase(name))
-            _etag=value;
-        else
-            super.setHeader(name,value);
-    }
-
-    /* ------------------------------------------------------------ */
-    @Override
-    public boolean containsHeader(String name)
-    {
-        if (!_noCompression && "etag".equalsIgnoreCase(name) && _etag!=null)
-            return true;
-        return super.containsHeader(name);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#getOutputStream()
-     */
-    @Override
-    public ServletOutputStream getOutputStream() throws IOException
-    {
-        if (_compressedStream==null)
-        {
-            if (getResponse().isCommitted() || _noCompression)
-                return getResponse().getOutputStream();
-
-            _compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
-        }
-        else if (_writer!=null)
-            throw new IllegalStateException("getWriter() called");
-
-        return _compressedStream;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#getWriter()
-     */
-    @Override
-    public PrintWriter getWriter() throws IOException
-    {
-        if (_writer==null)
-        {
-            if (_compressedStream!=null)
-                throw new IllegalStateException("getOutputStream() called");
-
-            if (getResponse().isCommitted() || _noCompression)
-                return getResponse().getWriter();
-
-            _compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
-            _writer=newWriter(_compressedStream,getCharacterEncoding());
-        }
-        return _writer;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setIntHeader(java.lang.String, int)
-     */
-    @Override
-    public void setIntHeader(String name, int value)
-    {
-        if ("content-length".equalsIgnoreCase(name))
-        {
-            _contentLength=value;
-            if (_compressedStream!=null)
-                _compressedStream.setContentLength();
-        }
-        else
-            super.setIntHeader(name,value);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Allows derived implementations to replace PrintWriter implementation.
-     *
-     * @param out the out
-     * @param encoding the encoding
-     * @return the prints the writer
-     * @throws UnsupportedEncodingException the unsupported encoding exception
-     */
-    protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
-    {
-        return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     *@return the underlying CompressedStream implementation
-     */
-    protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response) throws IOException;
-
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/DeflatedOutputStream.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/DeflatedOutputStream.java
deleted file mode 100644
index 7628526..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/DeflatedOutputStream.java
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.zip.Deflater;
-
-/**
- * Reimplementation of {@link java.util.zip.DeflaterOutputStream} that supports reusing the buffer.
- */
-public class DeflatedOutputStream extends FilterOutputStream
-{
-    protected final Deflater _def;
-    protected final byte[] _buf;
-    protected boolean closed = false;
-
-    public DeflatedOutputStream(OutputStream out, Deflater deflater, byte[] buffer)
-    {
-        super(out);
-        _def = deflater;
-        _buf = buffer;
-    }
-
-    @Override
-    public void write(int b) throws IOException
-    {
-        byte[] buf = new byte[1];
-        buf[0] = (byte)(b & 0xff);
-        write(buf,0,1);
-    }
-
-    @Override
-    public void write(byte[] b, int off, int len) throws IOException
-    {
-        if (_def.finished())
-            throw new IOException("Stream already finished");
-        if ((off | len | (off + len) | (b.length - (off + len))) < 0)
-            throw new IndexOutOfBoundsException();
-        if (len == 0)
-            return;
-        if (!_def.finished())
-        {
-            _def.setInput(b,off,len);
-            while (!_def.needsInput())
-            {
-                deflate();
-            }
-        }
-    }
-
-    private void deflate() throws IOException
-    {
-        int len = _def.deflate(_buf,0,_buf.length);
-        if (len > 0)
-        {
-            out.write(_buf,0,len);
-        }
-    }
-
-    public synchronized void finish() throws IOException
-    {
-        if (!_def.finished())
-        {
-            _def.finish();
-            while (!_def.finished())
-            {
-                deflate();
-            }
-        }
-    }
-
-    @Override
-    public synchronized void close() throws IOException
-    {
-        if (!closed)
-        {
-            finish();
-            out.close();
-            closed = true;
-        }
-    }
-
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipFactory.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipFactory.java
deleted file mode 100644
index d67874f..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.util.zip.Deflater;
-
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.server.Request;
-
-public interface GzipFactory
-{
-    int getBufferSize();
-    
-    HttpField getVaryField();
-
-    Deflater getDeflater(Request request, long content_length);
-
-    boolean isExcludedMimeType(String asciiToLowerCase);
-
-    void recycle(Deflater deflater);
-
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
deleted file mode 100644
index b28cb90..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
+++ /dev/null
@@ -1,647 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.Set;
-import java.util.zip.DeflaterOutputStream;
-import java.util.zip.GZIPOutputStream;
-
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.http.pathmap.PathSpecSet;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.eclipse.jetty.util.IncludeExclude;
-import org.eclipse.jetty.util.RegexSet;
-import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/* ------------------------------------------------------------ */
-/**
- * GZIP Handler This handler will gzip the content of a response if:
- * <ul>
- * <li>The handler is mapped to a matching path</li>
- * <li>The response status code is >=200 and <300
- * <li>The content length is unknown or more than the <code>minGzipSize</code> initParameter or the minGzipSize is 0(default)</li>
- * <li>The content-type matches one of the set of mimetypes to be compressed</li>
- * <li>The content-type does NOT match one of the set of mimetypes AND setExcludeMimeTypes is <code>true</code></li>
- * <li>No content-encoding is specified by the resource</li>
- * </ul>
- *
- * <p>
- * Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and CPU cycles. If this handler is used for static content,
- * then use of efficient direct NIO may be prevented, thus use of the gzip mechanism of the <code>org.eclipse.jetty.servlet.DefaultServlet</code> is advised instead.
- * </p>
- */
-public class GzipHandler extends HandlerWrapper
-{
-    private static final Logger LOG = Log.getLogger(GzipHandler.class);
-
-    protected int _bufferSize = 8192;
-    protected int _minGzipSize = 256;
-    protected String _vary = "Accept-Encoding, User-Agent";
-    
-    private final IncludeExclude<String> _agentPatterns=new IncludeExclude<>(RegexSet.class);
-    private final IncludeExclude<String> _methods = new IncludeExclude<>();
-    private final IncludeExclude<String> _paths = new IncludeExclude<String>(PathSpecSet.class);
-    private final IncludeExclude<String> _mimeTypes = new IncludeExclude<>();
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Instantiates a new gzip handler.
-     */
-    public GzipHandler()
-    {
-        _methods.include(HttpMethod.GET.asString());
-        for (String type:MimeTypes.getKnownMimeTypes())
-        {
-            if ("image/svg+xml".equals(type))
-                _paths.exclude("*.svgz");
-            else if (type.startsWith("image/")||
-                type.startsWith("audio/")||
-                type.startsWith("video/"))
-                _mimeTypes.exclude(type);
-        }
-        _mimeTypes.exclude("application/compress");
-        _mimeTypes.exclude("application/zip");
-        _mimeTypes.exclude("application/gzip");
-        _mimeTypes.exclude("application/bzip2");
-        _mimeTypes.exclude("application/x-rar-compressed");
-        LOG.debug("{} mime types {}",this,_mimeTypes);
-        
-        _agentPatterns.exclude(".*MSIE 6.0.*");
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param patterns Regular expressions matching user agents to exclude
-     */
-    public void addExcludedAgentPatterns(String... patterns)
-    {
-        _agentPatterns.exclude(patterns);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @param methods The methods to exclude in compression
-     */
-    public void addExcludedMethods(String... methods)
-    {
-        for (String m : methods)
-            _methods.exclude(m);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the mime types.
-     * @param types The mime types to exclude (without charset or other parameters).
-     * For backward compatibility the mimetypes may be comma separated strings, but this
-     * will not be supported in future versions.
-     */
-    public void addExcludedMimeTypes(String... types)
-    {
-        for (String t : types)
-            _mimeTypes.exclude(StringUtil.csvSplit(t));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Add path to excluded paths list.
-     * <p>
-     * There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
-     * Regex based.  This means that the initial characters on the path spec
-     * line are very strict, and determine the behavior of the path matching.
-     * <ul>
-     *  <li>If the spec starts with <code>'^'</code> the spec is assumed to be
-     *      a regex based path spec and will match with normal Java regex rules.</li>
-     *  <li>If the spec starts with <code>'/'</code> then spec is assumed to be
-     *      a Servlet url-pattern rules path spec for either an exact match
-     *      or prefix based match.</li>
-     *  <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
-     *      a Servlet url-pattern rules path spec for a suffix based match.</li>
-     *  <li>All other syntaxes are unsupported</li> 
-     * </ul>
-     * <p>
-     * Note: inclusion takes precedence over exclude.
-     * 
-     * @param pathspecs Path specs (as per servlet spec) to exclude. If a 
-     * ServletContext is available, the paths are relative to the context path,
-     * otherwise they are absolute.<br>
-     * For backward compatibility the pathspecs may be comma separated strings, but this
-     * will not be supported in future versions.
-     */
-    public void addExcludedPaths(String... pathspecs)
-    {
-        for (String p : pathspecs)
-            _paths.exclude(StringUtil.csvSplit(p));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @param patterns Regular expressions matching user agents to exclude
-     */
-    public void addIncludedAgentPatterns(String... patterns)
-    {
-        _agentPatterns.include(patterns);
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * @param methods The methods to include in compression
-     */
-    public void addIncludedMethods(String... methods)
-    {
-        for (String m : methods)
-            _methods.include(m);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Add included mime types. Inclusion takes precedence over
-     * exclusion.
-     * @param types The mime types to include (without charset or other parameters)
-     * For backward compatibility the mimetypes may be comma separated strings, but this
-     * will not be supported in future versions.
-     */
-    public void addIncludedMimeTypes(String... types)
-    {
-        for (String t : types)
-            _mimeTypes.include(StringUtil.csvSplit(t));
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Add path specs to include.
-     * <p>
-     * There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
-     * Regex based.  This means that the initial characters on the path spec
-     * line are very strict, and determine the behavior of the path matching.
-     * <ul>
-     *  <li>If the spec starts with <code>'^'</code> the spec is assumed to be
-     *      a regex based path spec and will match with normal Java regex rules.</li>
-     *  <li>If the spec starts with <code>'/'</code> then spec is assumed to be
-     *      a Servlet url-pattern rules path spec for either an exact match
-     *      or prefix based match.</li>
-     *  <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
-     *      a Servlet url-pattern rules path spec for a suffix based match.</li>
-     *  <li>All other syntaxes are unsupported</li> 
-     * </ul>
-     * <p>
-     * Note: inclusion takes precedence over exclude.
-     * 
-     * @param pathspecs Path specs (as per servlet spec) to include. If a 
-     * ServletContext is available, the paths are relative to the context path,
-     * otherwise they are absolute
-     */
-    public void addIncludedPaths(String... pathspecs)
-    {
-        for (String p : pathspecs)
-            _paths.include(StringUtil.csvSplit(p));
-    }
-    
-    /* ------------------------------------------------------------ */
-    public String[] getExcludedAgentPatterns()
-    {
-        Set<String> excluded=_agentPatterns.getExcluded();
-        return excluded.toArray(new String[excluded.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getExcludedMethods()
-    {
-        Set<String> excluded=_methods.getExcluded();
-        return excluded.toArray(new String[excluded.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getExcludedMimeTypes()
-    {
-        Set<String> excluded=_mimeTypes.getExcluded();
-        return excluded.toArray(new String[excluded.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getExcludedPaths()
-    {
-        Set<String> excluded=_paths.getExcluded();
-        return excluded.toArray(new String[excluded.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getIncludedAgentPatterns()
-    {
-        Set<String> includes=_agentPatterns.getIncluded();
-        return includes.toArray(new String[includes.size()]);
-    }
-    
-    /* ------------------------------------------------------------ */
-    public String[] getIncludedMethods()
-    {
-        Set<String> includes=_methods.getIncluded();
-        return includes.toArray(new String[includes.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getIncludedMimeTypes()
-    {
-        Set<String> includes=_mimeTypes.getIncluded();
-        return includes.toArray(new String[includes.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    public String[] getIncludedPaths()
-    {
-        Set<String> includes=_paths.getIncluded();
-        return includes.toArray(new String[includes.size()]);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Get the mime types.
-     *
-     * @return mime types to set
-     * @deprecated use {@link #getExcludedMimeTypes()} or {@link #getIncludedMimeTypes()} instead
-     */
-    @Deprecated
-    public Set<String> getMimeTypes()
-    {
-        throw new UnsupportedOperationException("Use getIncludedMimeTypes or getExcludedMimeTypes instead");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the mime types.
-     *
-     * @param mimeTypes
-     *            the mime types to set
-     * @deprecated use {@link #setExcludedMimeTypes()} or {@link #setIncludedMimeTypes()} instead
-     */
-    @Deprecated
-    public void setMimeTypes(Set<String> mimeTypes)
-    {
-        throw new UnsupportedOperationException("Use setIncludedMimeTypes or setExcludedMimeTypes instead");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the mime types.
-     *
-     * @param mimeTypes
-     *            the mime types to set
-     * @deprecated use {@link #setExcludedMimeTypes()} or {@link #setIncludedMimeTypes()} instead
-     */
-    @Deprecated
-    public void setMimeTypes(String mimeTypes)
-    {
-        throw new UnsupportedOperationException("Use setIncludedMimeTypes or setExcludedMimeTypes instead");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the mime types.
-     * @deprecated use {@link #setExcludedMimeTypes()} instead
-     */
-    @Deprecated
-    public void setExcludeMimeTypes(boolean exclude)
-    {
-        throw new UnsupportedOperationException("Use setExcludedMimeTypes instead");
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Get the excluded user agents.
-     *
-     * @return excluded user agents
-     */
-    public Set<String> getExcluded()
-    {
-        return _agentPatterns.getExcluded();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the excluded user agents.
-     *
-     * @param excluded
-     *            excluded user agents to set
-     */
-    public void setExcluded(Set<String> excluded)
-    {
-        _agentPatterns.getExcluded().clear();
-        _agentPatterns.getExcluded().addAll(excluded);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the excluded user agents.
-     *
-     * @param excluded
-     *            excluded user agents to set
-     */
-    public void setExcluded(String excluded)
-    {
-        _agentPatterns.getExcluded().clear();
-
-        if (excluded != null)
-        {
-            _agentPatterns.exclude(StringUtil.csvSplit(excluded));
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @return The value of the Vary header set if a response can be compressed.
-     */
-    public String getVary()
-    {
-        return _vary;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the value of the Vary header sent with responses that could be compressed.  
-     * <p>
-     * By default it is set to 'Accept-Encoding, User-Agent' since IE6 is excluded by 
-     * default from the excludedAgents. If user-agents are not to be excluded, then 
-     * this can be set to 'Accept-Encoding'.  Note also that shared caches may cache 
-     * many copies of a resource that is varied by User-Agent - one per variation of the 
-     * User-Agent, unless the cache does some normalization of the UA string.
-     * @param vary The value of the Vary header set if a response can be compressed.
-     */
-    public void setVary(String vary)
-    {
-        _vary = vary;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Get the buffer size.
-     *
-     * @return the buffer size
-     */
-    public int getBufferSize()
-    {
-        return _bufferSize;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the buffer size.
-     *
-     * @param bufferSize
-     *            buffer size to set
-     */
-    public void setBufferSize(int bufferSize)
-    {
-        _bufferSize = bufferSize;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Get the minimum reponse size.
-     *
-     * @return minimum reponse size
-     */
-    public int getMinGzipSize()
-    {
-        return _minGzipSize;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Set the minimum reponse size.
-     *
-     * @param minGzipSize
-     *            minimum reponse size
-     */
-    public void setMinGzipSize(int minGzipSize)
-    {
-        _minGzipSize = minGzipSize;
-    }
-    
-    /* ------------------------------------------------------------ */
-    @Override
-    protected void doStart() throws Exception
-    {
-        super.doStart();
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
-     */
-    @Override
-    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-    {
-        if(_handler == null || !isStarted())
-        {
-            // do nothing
-            return;
-        }
-        
-        if(isGzippable(baseRequest, request, response))
-        {
-            final CompressedResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response);
-
-            boolean exceptional=true;
-            try
-            {
-                _handler.handle(target, baseRequest, request, wrappedResponse);
-                exceptional=false;
-            }
-            finally
-            {
-                if (request.isAsyncStarted())
-                {
-                    request.getAsyncContext().addListener(new AsyncListener()
-                    {
-                        
-                        @Override
-                        public void onTimeout(AsyncEvent event) throws IOException
-                        {
-                        }
-                        
-                        @Override
-                        public void onStartAsync(AsyncEvent event) throws IOException
-                        {
-                        }
-                        
-                        @Override
-                        public void onError(AsyncEvent event) throws IOException
-                        {
-                        }
-                        
-                        @Override
-                        public void onComplete(AsyncEvent event) throws IOException
-                        {
-                            try
-                            {
-                                wrappedResponse.finish();
-                            }
-                            catch(IOException e)
-                            {
-                                LOG.warn(e);
-                            }
-                        }
-                    });
-                }
-                else if (exceptional && !response.isCommitted())
-                {
-                    wrappedResponse.resetBuffer();
-                    wrappedResponse.noCompression();
-                }
-                else
-                    wrappedResponse.finish();
-            }
-        }
-        else
-        {
-            _handler.handle(target,baseRequest, request, response);
-        }
-    }
-
-    private boolean isGzippable(Request baseRequest, HttpServletRequest request, HttpServletResponse response)
-    {
-        String ae = request.getHeader("accept-encoding");
-        if (ae == null || !ae.contains("gzip"))
-        {
-            // Request not indicated for Gzip
-            return false;
-        }
-        
-        if(response.containsHeader("Content-Encoding"))
-        {
-            // Response is already declared, can't gzip
-            LOG.debug("{} excluded as Content-Encoding already declared {}",this,request);
-            return false;
-        }
-        
-        if(HttpMethod.HEAD.is(request.getMethod()))
-        {
-            // HEAD is never Gzip'd
-            LOG.debug("{} excluded by method {}",this,request);
-            return false;
-        }
-        
-        // Exclude based on Request Method
-        if (!_methods.matches(baseRequest.getMethod()))
-        {
-            LOG.debug("{} excluded by method {}",this,request);
-            return false;
-        }
-        
-        // Exclude based on Request Path
-        ServletContext context = baseRequest.getServletContext();
-        String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
-
-        if(path != null && !_paths.matches(path))
-        {
-            LOG.debug("{} excluded by path {}",this,request);
-            return false;
-        }
-        
-        
-        // Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
-        String mimeType = context==null?null:context.getMimeType(path);
-        if (mimeType!=null)
-        {
-            mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);
-            if (!_mimeTypes.matches(mimeType))
-            {
-                LOG.debug("{} excluded by path suffix mime type {}",this,request);
-                return false;
-            }
-        }
-        
-        // Exclude on User Agent
-        String ua = request.getHeader("User-Agent");
-        if(ua != null && !_agentPatterns.matches(ua))
-        {
-            LOG.debug("{} excluded by user-agent {}",this,request);
-            return false;
-        }
-        
-        return true;
-    }
-
-    /**
-     * Allows derived implementations to replace ResponseWrapper implementation.
-     *
-     * @param request the request
-     * @param response the response
-     * @return the gzip response wrapper
-     */
-    protected CompressedResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
-    {
-        return new CompressedResponseWrapper(request,response)
-        {
-            {
-                super.setMimeTypes(GzipHandler.this._mimeTypes);
-                super.setBufferSize(GzipHandler.this._bufferSize);
-                super.setMinCompressSize(GzipHandler.this._minGzipSize);
-            }
-
-            @Override
-            protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
-            {
-                return new AbstractCompressedStream("gzip",request,this,_vary)
-                {
-                    @Override
-                    protected DeflaterOutputStream createStream() throws IOException
-                    {
-                        return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
-                    }
-                };
-            }
-
-            @Override
-            protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
-            {
-                return GzipHandler.this.newWriter(out,encoding);
-            }
-        };
-    }
-
-    /**
-     * Allows derived implementations to replace PrintWriter implementation.
-     *
-     * @param out the out
-     * @param encoding the encoding
-     * @return the prints the writer
-     * @throws UnsupportedEncodingException
-     */
-    protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
-    {
-        return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
-    }
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java
deleted file mode 100644
index 8803c88..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHttpOutput.java
+++ /dev/null
@@ -1,405 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.nio.ByteBuffer;
-import java.nio.channels.WritePendingException;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.zip.CRC32;
-import java.util.zip.Deflater;
-
-import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.MimeTypes;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.HttpOutput;
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.servlets.AsyncGzipFilter;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.IteratingNestedCallback;
-import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class GzipHttpOutput extends HttpOutput
-{
-    public static Logger LOG = Log.getLogger(GzipHttpOutput.class);
-    private final static HttpGenerator.CachedHttpField CONTENT_ENCODING_GZIP=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_ENCODING,"gzip");
-    private final static byte[] GZIP_HEADER = new byte[] { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 };
-    
-    private enum GZState { NOT_COMPRESSING, MIGHT_COMPRESS, COMMITTING, COMPRESSING, FINISHED};
-    private final AtomicReference<GZState> _state = new AtomicReference<>(GZState.NOT_COMPRESSING);
-    private final CRC32 _crc = new CRC32();
-    
-    private Deflater _deflater;
-    private GzipFactory _factory;
-    private ByteBuffer _buffer;
-    
-    public GzipHttpOutput(HttpChannel<?> channel)
-    {
-        super(channel);
-    }
-
-    @Override
-    public void reset()
-    {
-        _state.set(GZState.NOT_COMPRESSING);
-        super.reset();
-    }
-
-    @Override
-    protected void write(ByteBuffer content, boolean complete, Callback callback)
-    {
-        switch (_state.get())
-        {
-            case NOT_COMPRESSING:
-                super.write(content,complete,callback);
-                return;
-
-            case MIGHT_COMPRESS:
-                commit(content,complete,callback);
-                break;
-                
-            case COMMITTING:
-                callback.failed(new WritePendingException());
-                break;
-
-            case COMPRESSING:
-                gzip(content,complete,callback);
-                break;
-
-            default:
-                callback.failed(new IllegalStateException("state="+_state.get()));
-                break;
-        }
-    }
-
-    private void superWrite(ByteBuffer content, boolean complete, Callback callback)
-    {
-        super.write(content,complete,callback);
-    }
-    
-    private void addTrailer()
-    {
-        int i=_buffer.limit();
-        _buffer.limit(i+8);
-        
-        int v=(int)_crc.getValue();
-        _buffer.put(i++,(byte)(v & 0xFF));
-        _buffer.put(i++,(byte)((v>>>8) & 0xFF));
-        _buffer.put(i++,(byte)((v>>>16) & 0xFF));
-        _buffer.put(i++,(byte)((v>>>24) & 0xFF));
-        
-        v=_deflater.getTotalIn();
-        _buffer.put(i++,(byte)(v & 0xFF));
-        _buffer.put(i++,(byte)((v>>>8) & 0xFF));
-        _buffer.put(i++,(byte)((v>>>16) & 0xFF));
-        _buffer.put(i++,(byte)((v>>>24) & 0xFF));
-    }
-    
-    
-    private void gzip(ByteBuffer content, boolean complete, final Callback callback)
-    {
-        if (content.hasRemaining() || complete)
-        {
-            if (content.hasArray())
-                new GzipArrayCB(content,complete,callback).iterate();
-            else
-                new GzipBufferCB(content,complete,callback).iterate();
-        }
-        else
-            callback.succeeded();
-    }
-
-    protected void commit(ByteBuffer content, boolean complete, Callback callback)
-    {
-        // Are we excluding because of status?
-        Response response=getHttpChannel().getResponse();
-        int sc = response.getStatus();
-        if (sc>0 && (sc<200 || sc==204 || sc==205 || sc>=300))
-        {
-            LOG.debug("{} exclude by status {}",this,sc);
-            noCompression();
-            super.write(content,complete,callback);
-            return;
-        }
-        
-        // Are we excluding because of mime-type?
-        String ct = getHttpChannel().getResponse().getContentType();
-        if (ct!=null)
-        {
-            ct=MimeTypes.getContentTypeWithoutCharset(ct);
-            if (_factory.isExcludedMimeType(StringUtil.asciiToLowerCase(ct)))
-            {
-                LOG.debug("{} exclude by mimeType {}",this,ct);
-                noCompression();
-                super.write(content,complete,callback);
-                return;
-            }
-        }
-        
-        // Has the Content-Encoding header already been set?
-        String ce=getHttpChannel().getResponse().getHeader("Content-Encoding");
-        if (ce != null)
-        {
-            LOG.debug("{} exclude by content-encoding {}",this,ce);
-            noCompression();
-            super.write(content,complete,callback);
-            return;
-        }
-        
-        // Are we the thread that commits?
-        if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING))
-        {
-            // We are varying the response due to accept encoding header.
-            HttpFields fields = response.getHttpFields();
-            fields.add(_factory.getVaryField());
-
-            long content_length = response.getContentLength();
-            if (content_length<0 && complete)
-                content_length=content.remaining();
-            
-            _deflater = _factory.getDeflater(getHttpChannel().getRequest(),content_length);
-            
-            if (_deflater==null)
-            {
-                LOG.debug("{} exclude no deflater",this);
-                _state.set(GZState.NOT_COMPRESSING);
-                super.write(content,complete,callback);
-                return;
-            }
-
-            fields.put(CONTENT_ENCODING_GZIP);
-            _crc.reset();
-            _buffer=getHttpChannel().getByteBufferPool().acquire(_factory.getBufferSize(),false);
-            BufferUtil.fill(_buffer,GZIP_HEADER,0,GZIP_HEADER.length);
-
-            // Adjust headers
-            response.setContentLength(-1);
-            String etag=fields.get(HttpHeader.ETAG);
-            if (etag!=null)
-                fields.put(HttpHeader.ETAG,etag.substring(0,etag.length()-1)+AsyncGzipFilter.ETAG_GZIP+ '"');
-
-            LOG.debug("{} compressing {}",this,_deflater);
-            _state.set(GZState.COMPRESSING);
-            
-            gzip(content,complete,callback);
-        }
-        else
-            callback.failed(new WritePendingException());
-    }
-
-    public void noCompression()
-    {
-        while (true)
-        {
-            switch (_state.get())
-            {
-                case NOT_COMPRESSING:
-                    return;
-
-                case MIGHT_COMPRESS:
-                    if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.NOT_COMPRESSING))
-                        return;
-                    break;
-
-                default:
-                    throw new IllegalStateException(_state.get().toString());
-            }
-        }
-    }
-
-    public void noCompressionIfPossible()
-    {
-        while (true)
-        {
-            switch (_state.get())
-            {
-                case COMPRESSING:
-                case NOT_COMPRESSING:
-                    return;
-
-                case MIGHT_COMPRESS:
-                    if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.NOT_COMPRESSING))
-                        return;
-                    break;
-
-                default:
-                    throw new IllegalStateException(_state.get().toString());
-            }
-        }
-    }
-
-    public boolean mightCompress()
-    {
-        return _state.get()==GZState.MIGHT_COMPRESS;
-    }
-
-    public void mightCompress(GzipFactory factory)
-    {
-        while (true)
-        {
-            switch (_state.get())
-            {
-                case NOT_COMPRESSING:
-                    _factory=factory;
-                    if (_state.compareAndSet(GZState.NOT_COMPRESSING,GZState.MIGHT_COMPRESS))
-                    {
-                        LOG.debug("{} might compress",this);
-                        return;
-                    }
-                    _factory=null;
-                    break;
-                    
-                default:
-                    throw new IllegalStateException(_state.get().toString());
-            }
-        }
-    }
-    
-    private class GzipArrayCB extends IteratingNestedCallback
-    {        
-        private final boolean _complete;
-        public GzipArrayCB(ByteBuffer content, boolean complete, Callback callback)
-        {
-            super(callback);
-            _complete=complete;
-
-             byte[] array=content.array();
-             int off=content.arrayOffset()+content.position();
-             int len=content.remaining();
-             _crc.update(array,off,len);
-             _deflater.setInput(array,off,len);
-             if (complete)
-                 _deflater.finish();
-             content.position(content.limit());
-        }
-
-        @Override
-        protected Action process() throws Exception
-        {
-            if (_deflater.needsInput())
-            {
-                if (_deflater.finished())
-                {
-                    _factory.recycle(_deflater);
-                    _deflater=null;
-                    getHttpChannel().getByteBufferPool().release(_buffer);
-                    _buffer=null;
-                    return Action.SUCCEEDED;
-                }
-
-                if (!_complete)
-                    return Action.SUCCEEDED;
-                
-                _deflater.finish();
-            }
-
-            BufferUtil.compact(_buffer);
-            int off=_buffer.arrayOffset()+_buffer.limit();
-            int len=_buffer.capacity()-_buffer.limit()- (_complete?8:0);
-            if (len>0)
-            {
-                int produced=_deflater.deflate(_buffer.array(),off,len,Deflater.NO_FLUSH);
-                _buffer.limit(_buffer.limit()+produced);
-            }
-            boolean complete=_deflater.finished();
-            if (complete)
-                addTrailer();
-            
-            superWrite(_buffer,complete,this);
-            return Action.SCHEDULED;
-        }
-    }
-    
-    private class GzipBufferCB extends IteratingNestedCallback
-    {        
-        private final ByteBuffer _input;
-        private final ByteBuffer _content;
-        private final boolean _last;
-        public GzipBufferCB(ByteBuffer content, boolean complete, Callback callback)
-        {
-            super(callback);
-            _input=getHttpChannel().getByteBufferPool().acquire(Math.min(_factory.getBufferSize(),content.remaining()),false);
-            _content=content;
-            _last=complete;
-        }
-
-        @Override
-        protected Action process() throws Exception
-        {
-            if (_deflater.needsInput())
-            {                
-                if (BufferUtil.isEmpty(_content))
-                {                    
-                    if (_deflater.finished())
-                    {
-                        _factory.recycle(_deflater);
-                        _deflater=null;
-                        getHttpChannel().getByteBufferPool().release(_buffer);
-                        _buffer=null;
-                        return Action.SUCCEEDED;
-                    }
-                    
-                    if (!_last)
-                    {
-                        return Action.SUCCEEDED;
-                    }
-                    
-                    _deflater.finish();
-                }
-                else
-                {
-                    BufferUtil.clearToFill(_input);
-                    int took=BufferUtil.put(_content,_input);
-                    BufferUtil.flipToFlush(_input,0);
-                    if (took==0)
-                        throw new IllegalStateException();
-                   
-                    byte[] array=_input.array();
-                    int off=_input.arrayOffset()+_input.position();
-                    int len=_input.remaining();
-
-                    _crc.update(array,off,len);
-                    _deflater.setInput(array,off,len);                
-                    if (_last && BufferUtil.isEmpty(_content))
-                        _deflater.finish();
-                }
-            }
-
-            BufferUtil.compact(_buffer);
-            int off=_buffer.arrayOffset()+_buffer.limit();
-            int len=_buffer.capacity()-_buffer.limit() - (_last?8:0);
-            if (len>0)
-            {
-                int produced=_deflater.deflate(_buffer.array(),off,len,Deflater.NO_FLUSH);
-                _buffer.limit(_buffer.limit()+produced);
-            }
-            boolean finished=_deflater.finished();
-            
-            if (finished)
-                addTrailer();
-                
-            superWrite(_buffer,finished,this);
-            return Action.SCHEDULED;
-        }
-    }
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
deleted file mode 100644
index 3e9a4b9..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.zip.CRC32;
-import java.util.zip.Deflater;
-
-/**
- * Reimplementation of {@link java.util.zip.GZIPOutputStream} that supports reusing a {@link Deflater} instance.
- */
-public class GzipOutputStream extends DeflatedOutputStream
-{
-
-    private final static byte[] GZIP_HEADER = new byte[]
-    { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 };
-
-    private final CRC32 _crc = new CRC32();
-
-    public GzipOutputStream(OutputStream out, Deflater deflater, byte[] buffer) throws IOException
-    {
-        super(out,deflater,buffer);
-        out.write(GZIP_HEADER);
-    }
-
-    @Override
-    public synchronized void write(byte[] buf, int off, int len) throws IOException
-    {
-        super.write(buf,off,len);
-        _crc.update(buf,off,len);
-    }
-
-    @Override
-    public synchronized void finish() throws IOException
-    {
-        if (!_def.finished())
-        {
-            super.finish();
-            byte[] trailer = new byte[8];
-            writeInt((int)_crc.getValue(),trailer,0);
-            writeInt(_def.getTotalIn(),trailer,4);
-            out.write(trailer);
-        }
-    }
-
-    private void writeInt(int i, byte[] buf, int offset)
-    {
-        int o = offset;
-        buf[o++] = (byte)(i & 0xFF);
-        buf[o++] = (byte)((i >>> 8) & 0xFF);
-        buf[o++] = (byte)((i >>> 16) & 0xFF);
-        buf[o++] = (byte)((i >>> 24) & 0xFF);
-    }
-
-}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/package-info.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/package-info.java
deleted file mode 100644
index 4fd2652..0000000
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-/**
- * Jetty Servlets : GZIP Filter Classes
- */
-package org.eclipse.jetty.servlets.gzip;
-
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncManipFilter.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncManipFilter.java
new file mode 100644
index 0000000..4068d42
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncManipFilter.java
@@ -0,0 +1,103 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Filter that merely manipulates the AsyncContext.
+ * <p>
+ * The pattern of manipulation is modeled after how DOSFilter behaves. The purpose of this filter is to test arbitrary filter chains that could see unintended
+ * side-effects of async context manipulation.
+ */
+public class AsyncManipFilter implements Filter, AsyncListener
+{
+    private static final Logger LOG = Log.getLogger(AsyncManipFilter.class);
+    private static final String MANIP_KEY = AsyncManipFilter.class.getName();
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
+    {
+        LOG.debug("doFilter() - {}", chain);
+        AsyncContext ctx = (AsyncContext)request.getAttribute(MANIP_KEY);
+        if (ctx == null)
+        {
+            LOG.debug("Initial pass through: {}", chain);
+            ctx = request.startAsync();
+            ctx.addListener(this);
+            ctx.setTimeout(1000);
+            LOG.debug("AsyncContext: {}", ctx);
+            request.setAttribute(MANIP_KEY,ctx);
+            return;
+        }
+        else
+        {
+            LOG.debug("Second pass through: {}", chain);
+            chain.doFilter(request,response);
+        }
+    }
+
+    @Override
+    public void destroy()
+    {
+    }
+
+    @Override
+    public void onComplete(AsyncEvent event) throws IOException
+    {
+        LOG.debug("onComplete() {}",event);
+    }
+
+    @Override
+    public void onTimeout(AsyncEvent event) throws IOException
+    {
+        LOG.debug("onTimeout() {}",event.getAsyncContext());
+        event.getAsyncContext().dispatch();
+    }
+
+    @Override
+    public void onError(AsyncEvent event) throws IOException
+    {
+        LOG.debug("onError()",event.getThrowable());
+    }
+
+    @Override
+    public void onStartAsync(AsyncEvent event) throws IOException
+    {
+        LOG.debug("onTimeout() {}",event);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncScheduledDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncScheduledDispatchWrite.java
new file mode 100644
index 0000000..6a8479e
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncScheduledDispatchWrite.java
@@ -0,0 +1,121 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@SuppressWarnings("serial")
+public abstract class AsyncScheduledDispatchWrite extends TestDirContentServlet
+{
+    public static class Default extends AsyncScheduledDispatchWrite
+    {
+        public Default()
+        {
+            super(true);
+        }
+    }
+    
+    public static class Passed extends AsyncScheduledDispatchWrite
+    {
+        public Passed()
+        {
+            super(false);
+        }
+    }
+
+    private static class DispatchBack implements Runnable
+    {
+        private final AsyncContext ctx;
+
+        public DispatchBack(AsyncContext ctx)
+        {
+            this.ctx = ctx;
+        }
+
+        @Override
+        public void run()
+        {
+            ctx.dispatch();
+        }
+    }
+
+    private final boolean originalReqResp;
+    private ScheduledExecutorService scheduler;
+
+    public AsyncScheduledDispatchWrite(boolean originalReqResp)
+    {
+        this.originalReqResp = originalReqResp;
+    }
+
+    public void init(ServletConfig config) throws ServletException
+    {
+        super.init(config);
+        scheduler = Executors.newScheduledThreadPool(3);
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        Boolean suspended = (Boolean)request.getAttribute("SUSPENDED");
+        if (suspended == null || !suspended)
+        {
+            request.setAttribute("SUSPENDED",Boolean.TRUE);
+            AsyncContext ctx;
+            if (originalReqResp)
+            {
+                // Use Original Request & Response
+                ctx = request.startAsync();
+            }
+            else
+            {
+                // Pass Request & Response
+                ctx = request.startAsync(request,response);
+            }
+            ctx.setTimeout(0);
+            scheduler.schedule(new DispatchBack(ctx),500,TimeUnit.MILLISECONDS);
+        }
+        else
+        {
+            String fileName = request.getServletPath();
+            byte[] dataBytes = loadContentFileBytes(fileName);
+
+            response.setContentLength(dataBytes.length);
+
+            ServletOutputStream out = response.getOutputStream();
+
+            if (fileName.endsWith("txt"))
+                response.setContentType("text/plain");
+            else if (fileName.endsWith("mp3"))
+                response.setContentType("audio/mpeg");
+            response.setHeader("ETag","W/etag-" + fileName);
+
+            out.write(dataBytes);
+        }
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutCompleteWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutCompleteWrite.java
new file mode 100644
index 0000000..2a68470
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutCompleteWrite.java
@@ -0,0 +1,137 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Respond with requested content, but via AsyncContext manipulation.
+ * <p>
+ * 
+ * <pre>
+ *   1) startAsync
+ *   2) AsyncContext.setTimeout()
+ *   3) onTimeout()
+ *   4) send-response
+ *   5) AsyncContext.complete()
+ * </pre>
+ */
+@SuppressWarnings("serial")
+public abstract class AsyncTimeoutCompleteWrite extends TestDirContentServlet implements AsyncListener
+{
+    public static class Default extends AsyncTimeoutCompleteWrite
+    {
+        public Default()
+        {
+            super(true);
+        }
+    }
+    
+    public static class Passed extends AsyncTimeoutCompleteWrite
+    {
+        public Passed()
+        {
+            super(false);
+        }
+    }
+
+    private final boolean originalReqResp;
+
+    public AsyncTimeoutCompleteWrite(boolean originalReqResp)
+    {
+        this.originalReqResp = originalReqResp;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        assertThat("'filename' request attribute shouldn't be declared",request.getAttribute("filename"),nullValue());
+
+        AsyncContext ctx = (AsyncContext)request.getAttribute(this.getClass().getName());
+        assertThat("AsyncContext (shouldn't be in request attribute)", ctx, nullValue());
+        
+        if (originalReqResp)
+        {
+            // Use Original Request & Response
+            ctx = request.startAsync();
+        }
+        else
+        {
+            // Pass Request & Response
+            ctx = request.startAsync(request,response);
+        }
+        String fileName = request.getServletPath();
+        request.setAttribute("filename",fileName);
+        ctx.addListener(this);
+        ctx.setTimeout(20);
+        
+        // Setup indication of a redispatch (which this scenario shouldn't do)
+        request.setAttribute(this.getClass().getName(),ctx);
+    }
+
+    @Override
+    public void onComplete(AsyncEvent event) throws IOException
+    {
+    }
+
+    @Override
+    public void onTimeout(AsyncEvent event) throws IOException
+    {
+        HttpServletRequest request = (HttpServletRequest)event.getSuppliedRequest();
+        HttpServletResponse response = (HttpServletResponse)event.getSuppliedResponse();
+
+        String fileName = (String)request.getAttribute("filename");
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        response.setContentLength(dataBytes.length);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-" + fileName);
+
+        out.write(dataBytes);
+
+        event.getAsyncContext().complete();
+    }
+
+    @Override
+    public void onError(AsyncEvent event) throws IOException
+    {
+    }
+
+    @Override
+    public void onStartAsync(AsyncEvent event) throws IOException
+    {
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutDispatchWrite.java
new file mode 100644
index 0000000..042af57
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/AsyncTimeoutDispatchWrite.java
@@ -0,0 +1,121 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@SuppressWarnings("serial")
+public class AsyncTimeoutDispatchWrite extends TestDirContentServlet implements AsyncListener
+{
+    public static class Default extends AsyncTimeoutDispatchWrite
+    {
+        public Default()
+        {
+            super(true);
+        }
+    }
+    
+    public static class Passed extends AsyncTimeoutDispatchWrite
+    {
+        public Passed()
+        {
+            super(false);
+        }
+    }
+
+    private final boolean originalReqResp;
+
+    public AsyncTimeoutDispatchWrite(boolean originalReqResp)
+    {
+        this.originalReqResp = originalReqResp;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        AsyncContext ctx = (AsyncContext)request.getAttribute(AsyncContext.class.getName());
+        if (ctx == null)
+        {
+            // First pass through
+            if (originalReqResp)
+            {
+                // Use Original Request & Response
+                ctx = request.startAsync();
+            }
+            else
+            {
+                // Pass Request & Response
+                ctx = request.startAsync(request,response);
+            }
+            ctx.addListener(this);
+            ctx.setTimeout(200);
+            request.setAttribute(AsyncContext.class.getName(),ctx);
+        }
+        else
+        {
+            // second pass through, as result of timeout -> dispatch
+            String fileName = request.getServletPath();
+            byte[] dataBytes = loadContentFileBytes(fileName);
+
+            response.setContentLength(dataBytes.length);
+
+            ServletOutputStream out = response.getOutputStream();
+
+            if (fileName.endsWith("txt"))
+                response.setContentType("text/plain");
+            else if (fileName.endsWith("mp3"))
+                response.setContentType("audio/mpeg");
+            response.setHeader("ETag","W/etag-" + fileName);
+
+            out.write(dataBytes);
+            // no need to call AsyncContext.complete() from here
+            // in fact, it will cause an IllegalStateException if we do
+            // ctx.complete();
+        }
+    }
+
+    @Override
+    public void onComplete(AsyncEvent event) throws IOException
+    {
+    }
+
+    @Override
+    public void onTimeout(AsyncEvent event) throws IOException
+    {
+        event.getAsyncContext().dispatch();
+    }
+
+    @Override
+    public void onError(AsyncEvent event) throws IOException
+    {
+    }
+
+    @Override
+    public void onStartAsync(AsyncEvent event) throws IOException
+    {
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipContentLengthTest.java
new file mode 100644
index 0000000..3496d7c
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipContentLengthTest.java
@@ -0,0 +1,329 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.handler.gzip.GzipTester.ContentMetadata;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test the GzipHandler support for Content-Length setting variations.
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@RunWith(Parameterized.class)
+public class GzipContentLengthTest
+{
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+
+    @Rule
+    public TestingDir testingdir = new TestingDir();
+    
+    private static final HttpConfiguration defaultHttp = new HttpConfiguration();
+    private static final int LARGE = defaultHttp.getOutputBufferSize() * 8;
+    private static final int MEDIUM = defaultHttp.getOutputBufferSize();
+    private static final int SMALL = defaultHttp.getOutputBufferSize() / 4;
+    private static final int TINY = GzipHandler.DEFAULT_MIN_GZIP_SIZE / 2;
+    private static final boolean EXPECT_COMPRESSED = true;
+
+    @Parameters(name = "{0} bytes - {1} - compressed({2})")
+    public static List<Object[]> data()
+    {
+        List<Object[]> ret = new ArrayList<Object[]>();
+
+        ret.add(new Object[] { 0, "empty.txt", !EXPECT_COMPRESSED});
+        ret.add(new Object[] { TINY, "file-tiny.txt", !EXPECT_COMPRESSED});
+        ret.add(new Object[] { SMALL, "file-small.txt", EXPECT_COMPRESSED});
+        ret.add(new Object[] { SMALL, "file-small.mp3", !EXPECT_COMPRESSED});
+        ret.add(new Object[] { MEDIUM, "file-med.txt", EXPECT_COMPRESSED});
+        ret.add(new Object[] { MEDIUM, "file-medium.mp3", !EXPECT_COMPRESSED});
+        ret.add(new Object[] { LARGE, "file-large.txt", EXPECT_COMPRESSED});
+        ret.add(new Object[] { LARGE, "file-large.mp3", !EXPECT_COMPRESSED});
+
+        return ret;
+    }
+
+    @Parameter(0)
+    public int fileSize;
+    @Parameter(1)
+    public String fileName;
+    @Parameter(2)
+    public boolean expectCompressed;
+    
+    private void testWithGzip(Class<? extends TestDirContentServlet> contentServlet) throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir, GzipHandler.GZIP);
+        
+        // Add AsyncGzip Configuration
+        tester.getGzipHandler().setIncludedMimeTypes("text/plain");
+        tester.getGzipHandler().setIncludedPaths("*.txt","*.mp3");
+
+        // Add content servlet
+        tester.setContentServlet(contentServlet);
+        
+        try
+        {
+            String testFilename = String.format("%s-%s", contentServlet.getSimpleName(), fileName);
+            File testFile = tester.prepareServerFile(testFilename,fileSize);
+            
+            tester.start();
+            
+            HttpTester.Response response = tester.executeRequest("GET","/context/" + testFile.getName(),5,TimeUnit.SECONDS);
+            
+            if (response.getStatus()!=200)
+                System.err.println("DANG!!!! "+response);
+            
+            assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
+            
+            if (expectCompressed)
+            {
+                // Must be gzip compressed
+                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipHandler.GZIP));
+            } else
+            {
+                assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(GzipHandler.GZIP)));
+            }
+            
+            // Uncompressed content Size
+            ContentMetadata content = tester.getResponseMetadata(response);
+            assertThat("(Uncompressed) Content Length", content.size, is((long)fileSize));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> timeout -> onTimeout -> write-response -> complete
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncTimeoutCompleteWrite_Default() throws Exception
+    {
+        testWithGzip(AsyncTimeoutCompleteWrite.Default.class);
+    }
+    
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> timeout -> onTimeout -> write-response -> complete
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncTimeoutCompleteWrite_Passed() throws Exception
+    {
+        testWithGzip(AsyncTimeoutCompleteWrite.Passed.class);
+    }
+    
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncTimeoutDispatchWrite_Default() throws Exception
+    {
+        testWithGzip(AsyncTimeoutDispatchWrite.Default.class);
+    }
+    
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncTimeoutDispatchWrite_Passed() throws Exception
+    {
+        testWithGzip(AsyncTimeoutDispatchWrite.Passed.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncScheduledDispatchWrite_Default() throws Exception
+    {
+        testWithGzip(AsyncScheduledDispatchWrite.Default.class);
+    }
+    
+    /**
+     * Test with content servlet that does:  
+     * AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testAsyncScheduledDispatchWrite_Passed() throws Exception
+    {
+        testWithGzip(AsyncScheduledDispatchWrite.Passed.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) setHeader(content-length)
+     * 2) getOutputStream()
+     * 3) setHeader(content-type)
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletLengthStreamTypeWrite() throws Exception
+    {
+        testWithGzip(TestServletLengthStreamTypeWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) setHeader(content-length)
+     * 2) setHeader(content-type)
+     * 3) getOutputStream()
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletLengthTypeStreamWrite() throws Exception
+    {
+        testWithGzip(TestServletLengthTypeStreamWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) getOutputStream()
+     * 2) setHeader(content-length)
+     * 3) setHeader(content-type)
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletStreamLengthTypeWrite() throws Exception
+    {
+        testWithGzip(TestServletStreamLengthTypeWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) getOutputStream()
+     * 2) setHeader(content-length)
+     * 3) setHeader(content-type)
+     * 4) outputStream.write() (with frequent response flush)
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletStreamLengthTypeWriteWithFlush() throws Exception
+    {
+        testWithGzip(TestServletStreamLengthTypeWriteWithFlush.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) getOutputStream()
+     * 2) setHeader(content-type)
+     * 3) setHeader(content-length)
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletStreamTypeLengthWrite() throws Exception
+    {
+        testWithGzip(TestServletStreamTypeLengthWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) setHeader(content-type)
+     * 2) setHeader(content-length)
+     * 3) getOutputStream()
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/354014">Eclipse Bug 354014</a>
+     */
+    @Test
+    public void testServletTypeLengthStreamWrite() throws Exception
+    {
+        testWithGzip(TestServletTypeLengthStreamWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 1) setHeader(content-type)
+     * 2) getOutputStream()
+     * 3) setHeader(content-length)
+     * 4) outputStream.write()
+     * 
+     * @throws Exception on test failure
+     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+     */
+    @Test
+    public void testServletTypeStreamLengthWrite() throws Exception
+    {
+        testWithGzip(TestServletTypeStreamLengthWrite.class);
+    }
+
+    /**
+     * Test with content servlet that does:  
+     * 2) getOutputStream()
+     * 1) setHeader(content-type)
+     * 3) setHeader(content-length)
+     * 4) (unwrapped) HttpOutput.write(ByteBuffer)
+     * 
+     * This is done to demonstrate a bug with using HttpOutput.write()
+     * while also using GzipFilter
+     * 
+     * @throws Exception on test failure
+     * @see <a href="http://bugs.eclipse.org/450873">Eclipse Bug 450873</a>
+     */
+    @Test
+    public void testHttpOutputWrite() throws Exception
+    {
+        testWithGzip(TestServletBufferTypeLengthWrite.class);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultNoRecompressTest.java
new file mode 100644
index 0000000..31aad51
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultNoRecompressTest.java
@@ -0,0 +1,111 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.toolchain.test.IO;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Tests {@link GzipHandler} in combination with {@link DefaultServlet} for ability to configure {@link GzipHandler} to
+ * ignore recompress situations from upstream.
+ */
+@RunWith(Parameterized.class)
+public class GzipDefaultNoRecompressTest
+{
+    @Parameters
+    public static List<Object[]> data()
+    {
+        return Arrays.asList(new Object[][]
+        {
+            // Some already compressed files
+                { "test_quotes.gz", "application/gzip"  , GzipHandler.GZIP },
+                { "test_quotes.bz2", "application/bzip2", GzipHandler.GZIP },
+                { "test_quotes.zip", "application/zip"  , GzipHandler.GZIP },
+                { "test_quotes.rar", "application/x-rar-compressed", GzipHandler.GZIP },
+            // Some images (common first)
+                { "jetty_logo.png", "image/png", GzipHandler.GZIP},
+                { "jetty_logo.gif", "image/gif", GzipHandler.GZIP},
+                { "jetty_logo.jpeg", "image/jpeg", GzipHandler.GZIP},
+                { "jetty_logo.jpg", "image/jpeg", GzipHandler.GZIP},
+            // Lesser encountered images (usually found being requested from non-browser clients)
+                { "jetty_logo.bmp", "image/bmp", GzipHandler.GZIP },
+                { "jetty_logo.tif", "image/tiff", GzipHandler.GZIP },
+                { "jetty_logo.tiff", "image/tiff", GzipHandler.GZIP },
+                { "jetty_logo.xcf", "image/xcf", GzipHandler.GZIP },
+                { "jetty_logo.jp2", "image/jpeg2000", GzipHandler.GZIP },
+            //qvalue disables compression
+                { "test_quotes.txt", "text/plain", GzipHandler.GZIP+";q=0"},
+                { "test_quotes.txt", "text/plain", GzipHandler.GZIP+"; q =    0 "},
+                
+        });
+    }
+
+    @Rule
+    public TestingDir testingdir = new TestingDir();
+
+    private String alreadyCompressedFilename;
+    private String expectedContentType;
+    private String compressionType;
+
+    public GzipDefaultNoRecompressTest(String testFilename, String expectedContentType, String compressionType)
+    {
+        this.alreadyCompressedFilename = testFilename;
+        this.expectedContentType = expectedContentType;
+        this.compressionType = compressionType;
+    }
+
+    @Test
+    public void testNotGzipHandlered_Default_AlreadyCompressed() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir, compressionType);
+
+        copyTestFileToServer(alreadyCompressedFilename);
+
+        tester.setContentServlet(TestStaticMimeTypeServlet.class);
+
+        try
+        {
+            tester.start();
+            tester.assertIsResponseNotGziped(alreadyCompressedFilename,alreadyCompressedFilename + ".sha1",expectedContentType);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    private void copyTestFileToServer(String testFilename) throws IOException
+    {
+        File testFile = MavenTestingUtils.getTestResourceFile(testFilename);
+        File outFile = testingdir.getFile(testFilename);
+        IO.copy(testFile,outFile);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java
new file mode 100644
index 0000000..cfaf79b
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java
@@ -0,0 +1,768 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.GzipHttpContent;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.toolchain.test.IO;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.eclipse.jetty.util.StringUtil;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test the GzipHandler support built into the {@link DefaultServlet}
+ */
+public class GzipDefaultTest
+{
+    private String compressionType;
+
+    public GzipDefaultTest()
+    {
+        this.compressionType = GzipHandler.GZIP;
+    }
+
+    @SuppressWarnings("serial")
+    public static class HttpStatusServlet extends HttpServlet
+    {
+        private int _status = 204;
+
+        public HttpStatusServlet()
+        {
+            super();
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+        {
+            resp.setStatus(_status);
+            resp.setHeader("ETag","W/\"204\"");
+        }
+
+    }
+
+    @SuppressWarnings("serial")
+    public static class HttpErrorServlet extends HttpServlet
+    {
+        private int _status = 400;
+
+        public HttpErrorServlet()
+        {
+            super();
+        }
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+        {
+            resp.getOutputStream().write("error message".getBytes());
+            resp.setStatus(_status);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class HttpContentTypeWithEncoding extends HttpServlet
+    {
+        public static final String COMPRESSED_CONTENT = "<html><head></head><body><h1>COMPRESSABLE CONTENT</h1>"
+                + "This content must be longer than the default min gzip length, which is 256 bytes. "
+                + "The moon is blue to a fish in love. How now brown cow. The quick brown fox jumped over the lazy dog. A woman needs a man like a fish needs a bicycle!"
+                + "</body></html>";
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+        {
+            resp.setContentType("text/plain;charset=UTF8");
+            resp.setStatus(200);
+            ServletOutputStream out = resp.getOutputStream();
+            out.print(COMPRESSED_CONTENT);
+        }
+
+    }
+
+    @Rule
+    public TestingDir testingdir = new TestingDir();
+
+    @Test
+    public void testIsGzipByMethod() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().setIncludedMethods("POST","WIBBLE", "HEAD");
+
+        // Prepare Server File
+        int filesize = tester.getOutputBufferSize() * 2;
+        tester.prepareServerFile("file.txt",filesize);
+
+        // Content Servlet
+        tester.setContentServlet(GetServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response response;
+
+            //These methods have content bodies of the compressed response
+            tester.assertIsResponseGzipCompressed("POST","file.txt");
+            tester.assertIsResponseGzipCompressed("WIBBLE","file.txt");
+            
+            //A HEAD request should have similar headers, but no body
+            response = tester.executeRequest("HEAD","/context/file.txt",5,TimeUnit.SECONDS);
+            assertThat("Response status",response.getStatus(),is(HttpStatus.OK_200));
+            assertThat("ETag", response.get("ETag"), containsString(GzipHttpContent.ETAG_GZIP));
+            assertThat("Content encoding", response.get("Content-Encoding"), containsString("gzip"));
+            assertNull("Content length", response.get("Content-Length"));
+   
+            response = tester.executeRequest("GET","/context/file.txt",5,TimeUnit.SECONDS);
+
+            assertThat("Response status",response.getStatus(),is(HttpStatus.OK_200));
+            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
+
+            String content = tester.readResponse(response);
+            assertThat("Response content size",content.length(),is(filesize));
+            String expectedContent = IO.readToString(testingdir.getFile("file.txt"));
+            assertThat("Response content",content,is(expectedContent));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class GetServlet extends DefaultServlet
+    {
+        public GetServlet()
+        {
+            super();
+        }
+
+        @Override
+        public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
+        {
+            String uri = req.getRequestURI();
+            if (uri.endsWith(".deferred"))
+            {
+                // System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
+                resp.setContentType(getServletContext().getMimeType(uri.substring(0,uri.length() - 9)));
+            }
+
+            doGet(req,resp);
+        }
+    }
+
+    @Test
+    public void testIsGzipCompressedEmpty() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+
+        // Prepare server file
+        tester.prepareServerFile("empty.txt",0);
+
+        // Set content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+
+            HttpTester.Response response;
+
+            response = tester.executeRequest("GET","/context/empty.txt",5,TimeUnit.SECONDS);
+
+            assertThat("Response status",response.getStatus(),is(HttpStatus.OK_200));
+            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
+
+            String content = tester.readResponse(response);
+            assertThat("Response content size",content.length(),is(0));
+            String expectedContent = IO.readToString(testingdir.getFile("empty.txt"));
+            assertThat("Response content",content,is(expectedContent));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsGzipCompressedTiny() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        int filesize = tester.getOutputBufferSize() / 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
+            Assert.assertEquals("Accept-Encoding, User-Agent",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsGzipCompressedLarge() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+        tester.getGzipHandler().setExcludedAgentPatterns();
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
+            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testGzipedIfModified() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt",System.currentTimeMillis() - 4000);
+            Assert.assertEquals("Accept-Encoding, User-Agent",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testGzippedIfSVG() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+        tester.copyTestServerFile("test.svg");
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+
+        tester.getGzipHandler().addIncludedMimeTypes("image/svg+xml");
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","test.svg",System.currentTimeMillis() - 4000);
+            Assert.assertEquals("Accept-Encoding, User-Agent",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testNotGzipedIfNotModified() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            tester.assertIsResponseNotModified("GET","file.txt",System.currentTimeMillis() + 4000);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedWithZeroQ() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType + "; q=0");
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() / 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        // Add content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
+            assertThat("Response[Vary]",http.get("Vary"),containsString("Accept-Encoding"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsGzipCompressedWithQ() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType,"something;q=0.1," + compressionType + ";q=0.5");
+
+        int filesize = tester.getOutputBufferSize() / 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
+        tester.getGzipHandler().setExcludedAgentPatterns();
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
+            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedByContentType() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.mp3",filesize);
+
+        // Add content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","file.mp3",filesize,HttpStatus.OK_200);
+            Assert.assertNull(http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedByExcludedContentType() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addExcludedMimeTypes("text/plain");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("test_quotes.txt",filesize);
+
+        // Add content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","test_quotes.txt",filesize,HttpStatus.OK_200);
+            Assert.assertNull(http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedByExcludedContentTypeWithCharset() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addExcludedMimeTypes("text/plain");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("test_quotes.txt",filesize);
+        tester.addMimeType("txt","text/plain;charset=UTF-8");
+
+        // Add content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","test_quotes.txt",filesize,HttpStatus.OK_200);
+            Assert.assertNull(http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testGzipCompressedByContentTypeWithEncoding() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+        tester.setContentServlet(HttpContentTypeWithEncoding.class);
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+        tester.getGzipHandler().setExcludedAgentPatterns();
+        try
+        {
+            tester.start();
+            HttpTester.Response http = tester.assertNonStaticContentIsResponseGzipCompressed("GET","xxx",HttpContentTypeWithEncoding.COMPRESSED_CONTENT);
+            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedByDeferredContentType() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.mp3.deferred",filesize);
+
+        // Add content servlet
+        tester.setContentServlet(GetServlet.class);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response response = assertIsResponseNotGzipCompressed(tester,"GET","file.mp3.deferred",filesize,HttpStatus.OK_200);
+            assertThat("Response[Vary]", response.get("Vary"), isEmptyOrNullString());
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIsNotGzipCompressedHttpStatus() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+
+        // Test error code 204
+        tester.setContentServlet(HttpStatusServlet.class);
+
+        try
+        {
+            tester.start();
+
+            HttpTester.Response response = tester.executeRequest("GET","/context/",5,TimeUnit.SECONDS);
+
+            assertThat("Response status",response.getStatus(),is(HttpStatus.NO_CONTENT_204));
+            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
+        }
+        finally
+        {
+            tester.stop();
+        }
+
+    }
+
+    @Test
+    public void testIsNotGzipCompressedHttpBadRequestStatus() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+
+        // Test error code 400
+        tester.setContentServlet(HttpErrorServlet.class);
+
+        try
+        {
+            tester.start();
+
+            HttpTester.Response response = tester.executeRequest("GET","/context/",5,TimeUnit.SECONDS);
+
+            assertThat("Response status",response.getStatus(),is(HttpStatus.BAD_REQUEST_400));
+            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
+
+            String content = tester.readResponse(response);
+            assertThat("Response content",content,is("error message"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testUserAgentExclusion() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+        tester.setUserAgent("foo");
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().addIncludedMimeTypes("text/plain");
+        tester.getGzipHandler().setExcludedAgentPatterns("bar","foo");
+        
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        // Add content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+    
+    @Test
+    public void testUserAgentExclusionDefault() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+        tester.setContentServlet(DefaultServlet.class);
+        tester.setUserAgent("Some MSIE 6.0 user-agent");
+
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        try
+        {
+            tester.start();
+            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
+            Assert.assertEquals("Accept-Encoding, User-Agent",http.get("Vary"));
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testUserAgentExclusionByExcludedAgentPatterns() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+        tester.setUserAgent("foo");
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().setExcludedAgentPatterns("bar","fo.*");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        // Set content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testExcludePaths() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().setExcludedPaths("*.txt");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+
+        // Set content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testIncludedPaths() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        // Configure Gzip Handler
+        tester.getGzipHandler().setExcludedPaths("/bad.txt");
+        tester.getGzipHandler().setIncludedPaths("*.txt");
+
+        // Prepare server file
+        int filesize = tester.getOutputBufferSize() * 4;
+        tester.prepareServerFile("file.txt",filesize);
+        tester.prepareServerFile("bad.txt",filesize);
+
+        // Set content servlet
+        tester.setContentServlet(DefaultServlet.class);
+
+        try
+        {
+            tester.start();
+            tester.assertIsResponseGzipCompressed("GET","file.txt");
+        }
+        finally
+        {
+            tester.stop();
+        }
+        
+        try
+        {
+            tester.start();
+            assertIsResponseNotGzipCompressed(tester,"GET","bad.txt",filesize,HttpStatus.OK_200);
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+
+    public HttpTester.Response assertIsResponseNotGzipCompressed(GzipTester tester, String method, String filename, int expectedFilesize, int status)
+            throws Exception
+    {
+        HttpTester.Response response = tester.executeRequest(method,"/context/" + filename,5,TimeUnit.SECONDS);
+
+        assertThat("Response status",response.getStatus(),is(status));
+        assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
+
+        assertResponseContent(tester,response,status,filename,expectedFilesize);
+
+        return response;
+    }
+
+    private void assertResponseContent(GzipTester tester, HttpTester.Response response, int status, String filename, int expectedFilesize) throws IOException,
+            UnsupportedEncodingException
+    {
+        if (expectedFilesize >= 0)
+        {
+            assertThat("filename",filename,notNullValue());
+            assertThat("Response contentBytes.length",response.getContentBytes().length,is(expectedFilesize));
+            String contentLength = response.get("Content-Length");
+            if (StringUtil.isNotBlank(contentLength))
+            {
+                assertThat("Content-Length",response.get("Content-Length"),is(Integer.toString(expectedFilesize)));
+            }
+
+            if (status >= 200 && status < 300)
+            {
+                assertThat("ETag",response.get("ETAG"),startsWith("W/"));
+            }
+
+            File serverFile = testingdir.getFile(filename);
+            String expectedResponse = IO.readToString(serverFile);
+
+            String actual = tester.readResponse(response);
+            Assert.assertEquals("Expected response equals actual response",expectedResponse,actual);
+        }
+    }
+
+    
+    @Test
+    public void testIsNotGzipCompressedSVGZ() throws Exception
+    {
+        GzipTester tester = new GzipTester(testingdir,compressionType);
+
+        tester.setContentServlet(DefaultServlet.class);
+        tester.copyTestServerFile("test.svgz");
+        
+        try
+        {
+            tester.start();
+            tester.assertIsResponseNotGzipFiltered("test.svgz","test.svgz.sha1","image/svg+xml","gzip");
+        }
+        finally
+        {
+            tester.stop();
+        }
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipTester.java
new file mode 100644
index 0000000..6c50758
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipTester.java
@@ -0,0 +1,656 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Servlet;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.DateGenerator;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.http.HttpTester.Response;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.ServletTester;
+import org.eclipse.jetty.toolchain.test.IO;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+
+public class GzipTester
+{
+    private static final Logger LOG = Log.getLogger(GzipTester.class);
+
+    public static class ContentMetadata
+    {
+        public final long size;
+        public final String sha1;
+
+        public ContentMetadata(long size, String sha1checksum)
+        {
+            this.size = size;
+            this.sha1 = sha1checksum;
+        }
+    }
+
+    private String encoding = "ISO8859_1";
+    private String userAgent = null;
+    private final ServletTester tester = new ServletTester("/context",ServletContextHandler.GZIP);
+    private TestingDir testdir;
+    private String accept;
+    private String compressionType;
+    
+
+    public GzipTester(TestingDir testingdir, String compressionType, String accept)
+    {
+        this.testdir = testingdir;
+        this.compressionType = compressionType;
+        this.accept = accept;
+        
+    }
+
+    public GzipTester(TestingDir testingdir, String compressionType)
+    {
+        this.testdir = testingdir;
+        this.compressionType = compressionType;
+        this.accept = compressionType;
+    }
+    
+    public GzipHandler getGzipHandler()
+    {
+        return tester.getContext().getGzipHandler();
+    }
+
+    public int getOutputBufferSize()
+    {
+        return tester.getConnector().getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().getOutputBufferSize();
+    }
+    
+    public ContentMetadata getResponseMetadata(Response response) throws Exception
+    {
+        long size = response.getContentBytes().length;
+
+        String contentEncoding = response.get("Content-Encoding");
+
+        ByteArrayInputStream bais = null;
+        InputStream in = null;
+        DigestOutputStream digester = null;
+        ByteArrayOutputStream uncompressedStream = null;
+        try
+        {
+            MessageDigest digest = MessageDigest.getInstance("SHA1");
+            bais = new ByteArrayInputStream(response.getContentBytes());
+
+            if (contentEncoding == null)
+            {
+                LOG.debug("No response content-encoding");
+                in = new PassThruInputStream(bais);
+            }
+            else if (contentEncoding.contains(GzipHandler.GZIP))
+            {
+                in = new GZIPInputStream(bais);
+            }
+            else if (contentEncoding.contains(GzipHandler.DEFLATE))
+            {
+                in = new InflaterInputStream(bais,new Inflater(true));
+            }
+            else
+            {
+                assertThat("Unexpected response content-encoding", contentEncoding, isEmptyOrNullString());
+            }
+            
+            uncompressedStream = new ByteArrayOutputStream((int)size); 
+
+            digester = new DigestOutputStream(uncompressedStream,digest);
+            IO.copy(in,digester);
+            
+            byte output[] = uncompressedStream.toByteArray();
+            String actualSha1Sum = Hex.asHex(digest.digest());
+            return new ContentMetadata(output.length,actualSha1Sum);
+        }
+        finally
+        {
+            IO.close(digester);
+            IO.close(in);
+            IO.close(bais);
+            IO.close(uncompressedStream);
+        }
+    }
+
+    public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename) throws Exception
+    {
+        return assertIsResponseGzipCompressed(method,filename,filename,-1);
+    }
+
+    public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename, long ifmodifiedsince) throws Exception
+    {
+        return assertIsResponseGzipCompressed(method,filename,filename,ifmodifiedsince);
+    }
+
+    public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename) throws Exception
+    {
+        return assertIsResponseGzipCompressed(method,requestedFilename,serverFilename,-1);
+    }
+
+    public HttpTester.Response assertNonStaticContentIsResponseGzipCompressed(String method, String path, String expected) throws Exception
+    {
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod(method);
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("Accept-Encoding",accept);
+
+        if (this.userAgent != null)
+            request.setHeader("User-Agent",this.userAgent);
+        request.setURI("/context/" + path);
+
+        // Issue the request
+        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+
+        int qindex = compressionType.indexOf(";");
+        if (qindex < 0)
+            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType));
+        else
+            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
+
+        ByteArrayInputStream bais = null;
+        InputStream in = null;
+        ByteArrayOutputStream out = null;
+        String actual = null;
+
+        try
+        {
+            bais = new ByteArrayInputStream(response.getContentBytes());
+            if (compressionType.startsWith(GzipHandler.GZIP))
+            {
+                in = new GZIPInputStream(bais);
+            }
+            else if (compressionType.startsWith(GzipHandler.DEFLATE))
+            {
+                in = new InflaterInputStream(bais,new Inflater(true));
+            }
+            out = new ByteArrayOutputStream();
+            IO.copy(in,out);
+
+            actual = out.toString(encoding);
+            assertThat("Uncompressed contents",actual,equalTo(expected));
+        }
+        finally
+        {
+            IO.close(out);
+            IO.close(in);
+            IO.close(bais);
+        }
+
+        return response;
+    }
+
+    public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename, long ifmodifiedsince)
+            throws Exception
+    {
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod(method);
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("Accept-Encoding",compressionType);
+        if (ifmodifiedsince > 0)
+            request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(),DateGenerator.formatDate(ifmodifiedsince));
+        if (this.userAgent != null)
+            request.setHeader("User-Agent",this.userAgent);
+        request.setURI("/context/" + requestedFilename);
+
+        // Issue the request
+        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+
+        // Assert the response headers
+        // Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
+
+        // Response headers should have either a Transfer-Encoding indicating chunked OR a Content-Length
+        /*
+         * TODO need to check for the 3rd option of EOF content. To do this properly you might need to look at both HTTP/1.1 and HTTP/1.0 requests String
+         * contentLength = response.get("Content-Length"); String transferEncoding = response.get("Transfer-Encoding");
+         * 
+         * boolean chunked = (transferEncoding != null) && (transferEncoding.indexOf("chunk") >= 0); if(!chunked) {
+         * Assert.assertThat("Response.header[Content-Length]",contentLength,notNullValue()); } else {
+         * Assert.assertThat("Response.header[Transfer-Encoding]",transferEncoding,notNullValue()); }
+         */
+
+        int qindex = compressionType.indexOf(";");
+        if (qindex < 0)
+            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType));
+        else
+            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
+
+        Assert.assertThat(response.get("ETag"),Matchers.startsWith("W/"));
+
+        // Assert that the decompressed contents are what we expect.
+        File serverFile = testdir.getFile(serverFilename);
+        String expected = IO.readToString(serverFile);
+        String actual = null;
+
+        ByteArrayInputStream bais = null;
+        InputStream in = null;
+        ByteArrayOutputStream out = null;
+        try
+        {
+            bais = new ByteArrayInputStream(response.getContentBytes());
+            if (compressionType.startsWith(GzipHandler.GZIP))
+            {
+                in = new GZIPInputStream(bais);
+            }
+            else if (compressionType.startsWith(GzipHandler.DEFLATE))
+            {
+                in = new InflaterInputStream(bais,new Inflater(true));
+            }
+            out = new ByteArrayOutputStream();
+            IO.copy(in,out);
+
+            actual = out.toString(encoding);
+            assertThat("Uncompressed contents",actual,equalTo(expected));
+        }
+        finally
+        {
+            IO.close(out);
+            IO.close(in);
+            IO.close(bais);
+        }
+
+        return response;
+    }
+
+    public HttpTester.Response assertIsResponseNotModified(String method, String requestedFilename, long ifmodifiedsince) throws Exception
+    {
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod(method);
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("Accept-Encoding",compressionType);
+        if (ifmodifiedsince > 0)
+            request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(),DateGenerator.formatDate(ifmodifiedsince));
+        if (this.userAgent != null)
+            request.setHeader("User-Agent",this.userAgent);
+        request.setURI("/context/" + requestedFilename);
+
+        // Issue the request
+        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+
+        Assert.assertThat(response.getStatus(),Matchers.equalTo(304));
+        Assert.assertThat(response.get("ETag"),Matchers.startsWith("W/"));
+
+        return response;
+    }
+
+    /**
+     * Makes sure that the response contains an unfiltered file contents.
+     * <p>
+     * This is used to test exclusions and passthroughs in the GzipHandler.
+     * <p>
+     * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter.
+     *
+     * @param requestedFilename
+     *            the filename used to on the GET request,.
+     * @param testResourceSha1Sum
+     *            the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended.
+     * @param expectedContentType the expected content type
+     * @throws Exception on test failure
+     */
+    public void assertIsResponseNotGziped(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception
+    {
+        assertIsResponseNotGzipFiltered(requestedFilename,testResourceSha1Sum,expectedContentType,null);
+    }
+
+    /**
+     * Makes sure that the response contains an unfiltered file contents.
+     * <p>
+     * This is used to test exclusions and passthroughs in the GzipHandler.
+     * <p>
+     * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter.
+     *
+     * @param requestedFilename
+     *            the filename used to on the GET request,.
+     * @param testResourceSha1Sum
+     *            the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended.
+     * @param expectedContentType the expected content type
+     * @param expectedContentEncoding
+     *            can be non-null in some circumstances, eg when dealing with pre-gzipped .svgz files
+     * @throws Exception on test failure
+     */
+    public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType, String expectedContentEncoding)
+            throws Exception
+    {
+        HttpTester.Request request = HttpTester.newRequest();
+        HttpTester.Response response;
+
+        request.setMethod("GET");
+        request.setVersion("HTTP/1.0");
+        request.setHeader("Host","tester");
+        request.setHeader("Accept-Encoding",compressionType);
+        if (this.userAgent != null)
+            request.setHeader("User-Agent",this.userAgent);
+        request.setURI("/context/" + requestedFilename);
+
+        // Issue the request
+        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
+
+        dumpHeaders(requestedFilename + " / Response Headers",response);
+
+        // Assert the response headers
+        String prefix = requestedFilename + " / Response";
+        Assert.assertThat(prefix + ".status",response.getStatus(),is(HttpServletResponse.SC_OK));
+        Assert.assertThat(prefix + ".header[Content-Length]",response.get("Content-Length"),notNullValue());
+        Assert.assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipHandler)",response.get("Content-Encoding"),
+                expectedContentEncoding == null?nullValue():notNullValue());
+        if (expectedContentEncoding != null)
+            Assert.assertThat(prefix + ".header[Content-Encoding]",response.get("Content-Encoding"),is(expectedContentEncoding));
+        Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.get("Content-Type"),notNullValue());
+        Assert.assertThat(prefix + ".header[Content-Type]",response.get("Content-Type"),is(expectedContentType));
+
+        Assert.assertThat(response.get("ETAG"),Matchers.startsWith("W/"));
+
+        ByteArrayInputStream bais = null;
+        DigestOutputStream digester = null;
+        try
+        {
+            MessageDigest digest = MessageDigest.getInstance("SHA1");
+            bais = new ByteArrayInputStream(response.getContentBytes());
+            digester = new DigestOutputStream(new NoOpOutputStream(),digest);
+            IO.copy(bais,digester);
+
+            String actualSha1Sum = Hex.asHex(digest.digest());
+            String expectedSha1Sum = loadExpectedSha1Sum(testResourceSha1Sum);
+            Assert.assertEquals(requestedFilename + " / SHA1Sum of content",expectedSha1Sum,actualSha1Sum);
+        }
+        finally
+        {
+            IO.close(digester);
+            IO.close(bais);
+        }
+    }
+
+    private void dumpHeaders(String prefix, HttpTester.Message message)
+    {
+        LOG.debug("dumpHeaders: {}",prefix);
+        Enumeration<String> names = message.getFieldNames();
+        while (names.hasMoreElements())
+        {
+            String name = names.nextElement();
+            String value = message.get(name);
+            LOG.debug("dumpHeaders:   {} = {}",name,value);
+        }
+    }
+
+    private String loadExpectedSha1Sum(String testResourceSha1Sum) throws IOException
+    {
+        File sha1File = MavenTestingUtils.getTestResourceFile(testResourceSha1Sum);
+        String contents = IO.readToString(sha1File);
+        Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
+        Matcher mat = pat.matcher(contents);
+        Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
+        return mat.group();
+    }
+
+    public HttpTester.Response executeRequest(String method, String path, int idleFor, TimeUnit idleUnit) throws Exception
+    {
+        HttpTester.Request request = HttpTester.newRequest();
+
+        request.setMethod(method);
+        request.setVersion("HTTP/1.1");
+        request.setHeader("Host","tester");
+        request.setHeader("Accept-Encoding",accept);
+        request.setHeader("Connection","close");
+
+        if (this.userAgent != null)
+        {
+            request.setHeader("User-Agent",this.userAgent);
+        }
+        
+        request.setURI(path);
+
+        // Issue the request
+        return HttpTester.parseResponse(tester.getResponses(request.generate(),idleFor,idleUnit));
+    }
+
+    public String readResponse(HttpTester.Response response) throws IOException, UnsupportedEncodingException
+    {
+        String actual = null;
+        InputStream in = null;
+        ByteArrayOutputStream out = null;
+        try
+        {
+            byte[] content = response.getContentBytes();
+            if (content != null)
+                actual = new String(response.getContentBytes(),encoding);
+            else
+                actual = "";
+        }
+        finally
+        {
+            IO.close(out);
+            IO.close(in);
+        }
+        return actual;
+    }
+
+    /**
+     * Generate string content of arbitrary length.
+     *
+     * @param length
+     *            the length of the string to generate.
+     * @return the string content.
+     */
+    public String generateContent(int length)
+    {
+        StringBuilder builder = new StringBuilder();
+        do
+        {
+            builder.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc.\n");
+            builder.append("Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque\n");
+            builder.append("habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n");
+            builder.append("Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam\n");
+            builder.append("at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate\n");
+            builder.append("velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum.\n");
+            builder.append("Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum\n");
+            builder.append("eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa\n");
+            builder.append("sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam\n");
+            builder.append("consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque.\n");
+            builder.append("Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse\n");
+            builder.append("et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.\n");
+        }
+        while (builder.length() < length);
+
+        // Make sure we are exactly at requested length. (truncate the extra)
+        if (builder.length() > length)
+        {
+            builder.setLength(length);
+        }
+
+        return builder.toString();
+    }
+
+    public String getEncoding()
+    {
+        return encoding;
+    }
+
+    /**
+     * Create a file on the server resource path of a specified filename and size.
+     *
+     * @param filename
+     *            the filename to create
+     * @param filesize
+     *            the file size to create (Note: this isn't suitable for creating large multi-megabyte files)
+     * @return the prepared file
+     * @throws IOException if unable to create file
+     */
+    public File prepareServerFile(String filename, int filesize) throws IOException
+    {
+        File dir = testdir.getDir();
+        File testFile = new File(dir,filename);
+        // Make sure we have a uniq filename (to work around windows File.delete bug)
+        int i = 0;
+        while (testFile.exists())
+        {
+            testFile = new File(dir,(i++) + "-" + filename);
+        }
+
+        FileOutputStream fos = null;
+        ByteArrayInputStream in = null;
+        try
+        {
+            fos = new FileOutputStream(testFile,false);
+            in = new ByteArrayInputStream(generateContent(filesize).getBytes(encoding));
+            IO.copy(in,fos);
+            return testFile;
+        }
+        finally
+        {
+            IO.close(in);
+            IO.close(fos);
+        }
+    }
+
+    /**
+     * Copy a src/test/resource file into the server tree for eventual serving.
+     *
+     * @param filename
+     *            the filename to look for in src/test/resources
+     * @throws IOException if unable to copy file
+     */
+    public void copyTestServerFile(String filename) throws IOException
+    {
+        File srcFile = MavenTestingUtils.getTestResourceFile(filename);
+        File testFile = testdir.getFile(filename);
+
+        IO.copy(srcFile,testFile);
+    }
+
+    /**
+     * Set the servlet that provides content for the GzipHandler in being tested.
+     *
+     * @param servletClass
+     *            the servlet that will provide content.
+     * @throws IOException if unable to set content servlet
+     */
+    public void setContentServlet(Class<? extends Servlet> servletClass) throws IOException
+    {
+        tester.setContextPath("/context");
+        tester.setResourceBase(testdir.getDir().getCanonicalPath());
+        ServletHolder servletHolder = tester.addServlet(servletClass,"/");
+        servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath());
+        servletHolder.setInitParameter("etags","true");
+    }
+
+    public void setEncoding(String encoding)
+    {
+        this.encoding = encoding;
+    }
+
+    public void setUserAgent(String ua)
+    {
+        this.userAgent = ua;
+    }
+
+    public void addMimeType(String extension, String mimetype)
+    {
+        this.tester.getContext().getMimeTypes().addMimeMapping(extension,mimetype);
+    }
+
+    /**
+     * Add an arbitrary filter to the test case.
+     * 
+     * @param holder
+     *            the filter to add
+     * @param pathSpec
+     *            the path spec for this filter
+     * @param dispatches
+     *            the set of {@link DispatcherType} to associate with this filter
+     * @throws IOException if unable to add filter
+     */
+    public void addFilter(FilterHolder holder, String pathSpec, EnumSet<DispatcherType> dispatches) throws IOException
+    {
+        tester.addFilter(holder,pathSpec,dispatches);
+    }
+
+    public void start() throws Exception
+    {
+        Assert.assertThat("No servlet defined yet.  Did you use #setContentServlet()?",tester,notNullValue());
+        
+        if (LOG.isDebugEnabled())
+        {
+            tester.dumpStdErr();
+        }
+        tester.start();
+    }
+
+    public void stop()
+    {
+        // NOTE: Do not cleanup the testdir. Failures can't be diagnosed if you do that.
+        // IO.delete(testdir.getDir()):
+        try
+        {
+            tester.stop();
+        }
+        catch (Exception e)
+        {
+            // Don't toss this out into Junit as this would be the last exception
+            // that junit will report as being the cause of the test failure.
+            // when in reality, the earlier setup issue is the real cause.
+            e.printStackTrace(System.err);
+        }
+    }
+
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/Hex.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/Hex.java
new file mode 100644
index 0000000..7d56c2b
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/Hex.java
@@ -0,0 +1,76 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+public final class Hex
+{
+    private static final char[] hexcodes = "0123456789abcdef".toCharArray();
+
+    public static byte[] asByteArray(String id, int size)
+    {
+        if ((id.length() < 0) || (id.length() > (size * 2)))
+        {
+            throw new IllegalArgumentException(String.format("Invalid ID length of <%d> expected range of <0> to <%d>",id.length(),(size * 2)));
+        }
+
+        byte buf[] = new byte[size];
+        byte hex;
+        int len = id.length();
+
+        int idx = (int)Math.floor(((size * 2) - (double)len) / 2);
+        int i = 0;
+        if ((len % 2) != 0)
+        { // deal with odd numbered chars
+            i -= 1;
+        }
+
+        for (; i < len; i++)
+        {
+            hex = 0;
+            if (i >= 0)
+            {
+                hex = (byte)(Character.digit(id.charAt(i),16) << 4);
+            }
+            i++;
+            hex += (byte)(Character.digit(id.charAt(i),16));
+
+            buf[idx] = hex;
+            idx++;
+        }
+
+        return buf;
+    }
+
+    public static String asHex(byte buf[])
+    {
+        int len = buf.length;
+        char out[] = new char[len * 2];
+        for (int i = 0; i < len; i++)
+        {
+            out[i * 2] = hexcodes[(buf[i] & 0xF0) >> 4];
+            out[(i * 2) + 1] = hexcodes[(buf[i] & 0x0F)];
+        }
+        return String.valueOf(out);
+    }
+
+    private Hex()
+    {
+        /* prevent instantiation */
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipMinSizeTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipMinSizeTest.java
new file mode 100644
index 0000000..31fbc49
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipMinSizeTest.java
@@ -0,0 +1,87 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import javax.servlet.Servlet;
+
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Perform specific tests on the IncludableGzipHandler's ability to manage
+ * minGzipSize initialization parameter.
+ *
+ * @see <a href="Eclipse Bug 366106">http://bugs.eclipse.org/366106</a>
+ */
+public class IncludedGzipMinSizeTest
+{
+    public IncludedGzipMinSizeTest()
+    {
+        this.compressionType = GzipHandler.GZIP;
+    }
+
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
+    private String compressionType;
+    private Class<? extends Servlet> testServlet = TestMinGzipSizeServlet.class;
+
+    @Test
+    public void testUnderMinSize() throws Exception
+    {
+        GzipTester tester = new GzipTester(testdir, compressionType);
+
+        tester.setContentServlet(testServlet);
+        // A valid mime type that we will never use in this test.
+        // configured here to prevent mimeType==null logic
+        tester.getGzipHandler().addIncludedMimeTypes("application/soap+xml");
+        tester.getGzipHandler().setMinGzipSize(2048);
+
+        tester.copyTestServerFile("small_script.js");
+
+        try {
+            tester.start();
+            tester.assertIsResponseNotGziped("small_script.js",
+                    "small_script.js.sha1",
+                    "text/javascript; charset=utf-8");
+        } finally {
+            tester.stop();
+        }
+    }
+
+    @Test
+    public void testOverMinSize() throws Exception
+    {
+        GzipTester tester = new GzipTester(testdir, compressionType);
+
+        tester.setContentServlet(testServlet);
+        tester.getGzipHandler().addIncludedMimeTypes("application/soap+xml","text/javascript","application/javascript");
+        tester.getGzipHandler().setMinGzipSize(2048);
+
+        tester.copyTestServerFile("big_script.js");
+
+        try {
+            tester.start();
+            tester.assertIsResponseGzipCompressed("GET","big_script.js");
+        } finally {
+            tester.stop();
+        }
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java
new file mode 100644
index 0000000..4e02fcc
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/IncludedGzipTest.java
@@ -0,0 +1,136 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.servlet.ServletTester;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.IO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class IncludedGzipTest
+{
+
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
+    private static String __content =
+        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
+        "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
+        "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
+        "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
+        "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
+        "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
+        "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
+        "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
+        "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
+        "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
+        "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
+        "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
+
+    private ServletTester tester;
+    private String compressionType;
+
+    public IncludedGzipTest()
+    {
+        this.compressionType = GzipHandler.GZIP;
+    }
+
+    @Before
+    public void setUp() throws Exception
+    {
+        testdir.ensureEmpty();
+
+        File testFile = testdir.getFile("file.txt");
+        try (OutputStream testOut = new BufferedOutputStream(new FileOutputStream(testFile)))
+        {
+            ByteArrayInputStream testIn = new ByteArrayInputStream(__content.getBytes("ISO8859_1"));
+            IO.copy(testIn,testOut);
+        }
+
+        tester=new ServletTester("/context");
+        tester.getContext().setResourceBase(testdir.getDir().getCanonicalPath());
+        tester.getContext().addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
+        
+        GzipHandler gzipHandler = new GzipHandler();
+        gzipHandler.setHandler(tester.getContext().getHandler());
+        tester.getContext().setHandler(gzipHandler);
+        tester.start();
+    }
+
+    @After
+    public void tearDown() throws Exception
+    {
+        tester.stop();
+        IO.delete(testdir.getDir());
+    }
+
+    @Test
+    public void testGzip() throws Exception
+    {
+        // generated and parsed test
+
+        ByteBuffer request=BufferUtil.toBuffer(
+            "GET /context/file.txt HTTP/1.0\r\n"+
+            "Host: tester\r\n"+
+            "Accept-Encoding: "+compressionType+"\r\n"+
+            "\r\n");
+
+
+        HttpTester.Response response=HttpTester.parseResponse(tester.getResponses(request));
+
+        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+        assertEquals(compressionType,response.get("Content-Encoding"));
+
+        InputStream testIn = null;
+        ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes());
+        if (compressionType.equals(GzipHandler.GZIP))
+        {
+            testIn = new GZIPInputStream(compressedResponseStream);
+        }
+        else if (compressionType.equals(GzipHandler.DEFLATE))
+        {
+            testIn = new InflaterInputStream(compressedResponseStream, new Inflater(true));
+        }
+        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
+        IO.copy(testIn,testOut);
+
+        assertEquals(__content, testOut.toString("ISO8859_1"));
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/NoOpOutputStream.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/NoOpOutputStream.java
new file mode 100644
index 0000000..2f900f8
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/NoOpOutputStream.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that does nothing. (Used by SHA1SUM routines)
+ */
+public class NoOpOutputStream extends OutputStream
+{
+    @Override
+    public void close() throws IOException
+    {
+        /* noop */
+    }
+    
+    @Override
+    public void flush() throws IOException
+    {
+        /* noop */
+    }
+    
+    @Override
+    public void write(byte[] b) throws IOException
+    {
+        /* noop */
+    }
+    
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException
+    {
+        /* noop */
+    }
+    
+    @Override
+    public void write(int b) throws IOException
+    {
+        /* noop */
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/PassThruInputStream.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/PassThruInputStream.java
new file mode 100644
index 0000000..08d4da6
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/PassThruInputStream.java
@@ -0,0 +1,36 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+
+/**
+ * A simple pass-through input stream.
+ * <p>
+ * Used in some test cases where a proper resource open/close is needed for
+ * some potentially optional layers of the input stream.
+ */
+public class PassThruInputStream extends FilterInputStream
+{
+    public PassThruInputStream(InputStream in)
+    {
+        super(in);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestDirContentServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestDirContentServlet.java
new file mode 100644
index 0000000..4c274e7
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestDirContentServlet.java
@@ -0,0 +1,74 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.eclipse.jetty.toolchain.test.PathAssert;
+import org.eclipse.jetty.util.IO;
+
+@SuppressWarnings("serial")
+public class TestDirContentServlet extends HttpServlet
+{
+    private File basedir;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException
+    {
+        basedir = new File(config.getInitParameter("baseDir"));
+    }
+
+    public File getTestFile(String filename)
+    {
+        File testfile = new File(basedir,filename);
+        PathAssert.assertFileExists("Content File should exist",testfile);
+        return testfile;
+    }
+
+    protected byte[] loadContentFileBytes(final String fileName) throws IOException
+    {
+        String relPath = fileName;
+        relPath = relPath.replaceFirst("^/context/","");
+        relPath = relPath.replaceFirst("^/","");
+
+        File contentFile =  getTestFile(relPath);
+
+        FileInputStream in = null;
+        ByteArrayOutputStream out = null;
+        try
+        {
+            in = new FileInputStream(contentFile);
+            out = new ByteArrayOutputStream();
+            IO.copy(in,out);
+            return out.toByteArray();
+        }
+        finally
+        {
+            IO.close(out);
+            IO.close(in);
+        }
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestMinGzipSizeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestMinGzipSizeServlet.java
new file mode 100644
index 0000000..d14171f
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestMinGzipSizeServlet.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.MimeTypes;
+
+/**
+ * Test servlet for testing against unusual minGzip configurable.
+ */
+@SuppressWarnings("serial")
+public class TestMinGzipSizeServlet extends TestDirContentServlet
+{
+    private MimeTypes mimeTypes;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException
+    {
+        super.init(config);
+        mimeTypes = new MimeTypes();
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        response.setContentLength(dataBytes.length);
+        response.setHeader("ETag","W/etag-"+fileName);
+        if (fileName.endsWith(".js"))
+        {
+            // intentionally long-form content type to test ";" splitting in code
+            response.setContentType("text/javascript; charset=utf-8");
+        }
+        else
+        {
+            String mime = mimeTypes.getMimeByExtension(fileName);
+            if (mime != null)
+                response.setContentType(mime);
+        }
+        ServletOutputStream out = response.getOutputStream();
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletBufferTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletBufferTypeLengthWrite.java
new file mode 100644
index 0000000..ffc6328
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletBufferTypeLengthWrite.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.HttpOutput;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) get stream
+ *  2) set content type
+ *  2) set content length
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletBufferTypeLengthWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        response.setContentLength(dataBytes.length);
+        
+        ((HttpOutput)out).write(ByteBuffer.wrap(dataBytes).asReadOnlyBuffer());
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthStreamTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthStreamTypeWrite.java
new file mode 100644
index 0000000..29abb8f
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthStreamTypeWrite.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) set content length
+ *  2) get stream
+ *  3) set content type
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletLengthStreamTypeWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        response.setContentLength(dataBytes.length);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthTypeStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthTypeStreamWrite.java
new file mode 100644
index 0000000..47ed938
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletLengthTypeStreamWrite.java
@@ -0,0 +1,63 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) set content length
+ *  2) set content type
+ *  3) get stream
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletLengthTypeStreamWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        response.setContentLength(dataBytes.length);
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWrite.java
new file mode 100644
index 0000000..8b6fc12
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWrite.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) get stream
+ *  2) set content length
+ *  3) set content type
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletStreamLengthTypeWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        response.setContentLength(dataBytes.length);
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWriteWithFlush.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWriteWithFlush.java
new file mode 100644
index 0000000..c04afb6
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamLengthTypeWriteWithFlush.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ * 
+ * Using a real-world pattern of:
+ * 
+ * <pre>
+ *  1) get stream
+ *  2) set content length
+ *  3) set content type
+ *  4) write and flush
+ * </pre>
+ * 
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletStreamLengthTypeWriteWithFlush extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        // set content-length of uncompressed content (GzipHandler should handle this)
+        response.setContentLength(dataBytes.length);
+        
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        for ( int i = 0 ; i < dataBytes.length ; i++)
+        {
+            out.write(dataBytes[i]);
+            // flush using response object (not the stream itself)
+            response.flushBuffer();
+        }
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamTypeLengthWrite.java
new file mode 100644
index 0000000..5b3b2c1
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletStreamTypeLengthWrite.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) get stream
+ *  2) set content type
+ *  2) set content length
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletStreamTypeLengthWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        response.setContentLength(dataBytes.length);
+
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeLengthStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeLengthStreamWrite.java
new file mode 100644
index 0000000..9d24bfc
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeLengthStreamWrite.java
@@ -0,0 +1,63 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) set content type
+ *  2) set content length
+ *  3) get stream
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletTypeLengthStreamWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        response.setContentLength(dataBytes.length);
+
+        ServletOutputStream out = response.getOutputStream();
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeStreamLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeStreamLengthWrite.java
new file mode 100644
index 0000000..c757bde
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestServletTypeStreamLengthWrite.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A sample servlet to serve static content, using a order of construction that has caused problems for
+ * {@link GzipHandler} in the past.
+ *
+ * Using a real-world pattern of:
+ *
+ * <pre>
+ *  1) set content type
+ *  2) get stream
+ *  3) set content length
+ *  4) write
+ * </pre>
+ *
+ * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
+ */
+@SuppressWarnings("serial")
+public class TestServletTypeStreamLengthWrite extends TestDirContentServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        if (fileName.endsWith("txt"))
+            response.setContentType("text/plain");
+        else if (fileName.endsWith("mp3"))
+            response.setContentType("audio/mpeg");
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        ServletOutputStream out = response.getOutputStream();
+
+        response.setContentLength(dataBytes.length);
+
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestStaticMimeTypeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestStaticMimeTypeServlet.java
new file mode 100644
index 0000000..663bdd0
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/TestStaticMimeTypeServlet.java
@@ -0,0 +1,81 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.handler.gzip;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.MimeTypes;
+
+/**
+ * Test servlet for testing against unusual MimeTypes and Content-Types.
+ */
+@SuppressWarnings("serial")
+public class TestStaticMimeTypeServlet extends TestDirContentServlet
+{
+    private MimeTypes mimeTypes;
+
+    @Override
+    public void init(ServletConfig config) throws ServletException
+    {
+        super.init(config);
+        mimeTypes = new MimeTypes();
+        // Some real world, yet not terribly common, mime type mappings.
+        mimeTypes.addMimeMapping("bz2","application/bzip2");
+        mimeTypes.addMimeMapping("bmp","image/bmp");
+        mimeTypes.addMimeMapping("tga","application/tga");
+        mimeTypes.addMimeMapping("xcf","image/xcf");
+        mimeTypes.addMimeMapping("jp2","image/jpeg2000");
+
+        // Some of the other gzip mime-types seen in the wild.
+        // NOTE: Using oddball extensions just so that the calling request can specify
+        //       which strange mime type to use.
+        mimeTypes.addMimeMapping("x-gzip","application/x-gzip");
+        mimeTypes.addMimeMapping("x-gunzip","application/x-gunzip");
+        mimeTypes.addMimeMapping("gzipped","application/gzippped");
+        mimeTypes.addMimeMapping("gzip-compressed","application/gzip-compressed");
+        mimeTypes.addMimeMapping("x-compressed","application/x-compressed");
+        mimeTypes.addMimeMapping("x-compress","application/x-compress");
+        mimeTypes.addMimeMapping("gzipdoc","gzip/document");
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    {
+        String fileName = request.getServletPath();
+        byte[] dataBytes = loadContentFileBytes(fileName);
+
+        response.setContentLength(dataBytes.length);
+        response.setHeader("ETag","W/etag-"+fileName);
+
+        String mime = mimeTypes.getMimeByExtension(fileName);
+        if (mime == null)
+            response.setContentType("application/octet-stream");
+        else
+            response.setContentType(mime);
+
+        ServletOutputStream out = response.getOutputStream();
+        out.write(dataBytes);
+    }
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java
index 666bdeb..b2f66d0 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java
@@ -260,7 +260,7 @@
         // System.err.println("RESPONSES: \n"+responses);
 
         assertEquals(4,count(responses,"HTTP/1.1 200 OK"));
-        assertEquals(1,count(responses,"HTTP/1.1 503"));
+        assertEquals(1,count(responses,"HTTP/1.1 429"));
         assertEquals(1,count(responses,"DoSFilter: delayed"));
         assertEquals(1,count(responses,"DoSFilter: throttled"));
         assertEquals(1,count(responses,"DoSFilter: unavailable"));
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java
index 96cc743..9108f48 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java
@@ -173,7 +173,7 @@
     }
 
     @Test
-    public void testSimpleRequestWithMatchingOrigin() throws Exception
+    public void testSimpleRequestWithMatchingOriginAndWithoutTimingOrigin() throws Exception
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
         String origin = "http://localhost";
@@ -193,11 +193,67 @@
         Assert.assertTrue(response.contains("HTTP/1.1 200"));
         Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
         Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
+        Assert.assertFalse(response.contains(CrossOriginFilter.TIMING_ALLOW_ORIGIN_HEADER));
         Assert.assertTrue(response.contains("Vary"));
         Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
     }
 
     @Test
+    public void testSimpleRequestWithMatchingOriginAndNonMatchingTimingOrigin() throws Exception
+    {
+    	FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
+    	String origin = "http://localhost";
+    	String timingOrigin = "http://127.0.0.1";
+    	filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
+    	filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_TIMING_ORIGINS_PARAM, timingOrigin);
+    	tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
+    	
+    	CountDownLatch latch = new CountDownLatch(1);
+    	tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
+    	
+    	String request = "" +
+    			"GET / HTTP/1.1\r\n" +
+    			"Host: localhost\r\n" +
+    			"Connection: close\r\n" +
+    			"Origin: " + origin + "\r\n" +
+    			"\r\n";
+    	String response = tester.getResponses(request);
+    	Assert.assertTrue(response.contains("HTTP/1.1 200"));
+    	Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
+    	Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
+        Assert.assertFalse(response.contains(CrossOriginFilter.TIMING_ALLOW_ORIGIN_HEADER));
+    	Assert.assertTrue(response.contains("Vary"));
+    	Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
+    }
+    
+    @Test
+    public void testSimpleRequestWithMatchingOriginAndMatchingTimingOrigin() throws Exception
+    {
+    	FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
+    	String origin = "http://localhost";
+    	filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin);
+    	filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_TIMING_ORIGINS_PARAM, origin);
+    	tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
+    	
+    	CountDownLatch latch = new CountDownLatch(1);
+    	tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*");
+    	
+    	String request = "" +
+    			"GET / HTTP/1.1\r\n" +
+    			"Host: localhost\r\n" +
+    			"Connection: close\r\n" +
+    			"Origin: " + origin + "\r\n" +
+    			"\r\n";
+    	String response = tester.getResponses(request);
+    	Assert.assertTrue(response.contains("HTTP/1.1 200"));
+    	Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
+    	Assert.assertTrue(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
+    	Assert.assertTrue(response.contains(CrossOriginFilter.TIMING_ALLOW_ORIGIN_HEADER));
+    	Assert.assertTrue(response.contains("Vary"));
+    	Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
+    }
+    
+    @Test
     public void testSimpleRequestWithMatchingMultipleOrigins() throws Exception
     {
         FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter());
@@ -455,7 +511,7 @@
                 "Upgrade: WebSocket\r\n" +
                 "Origin: http://localhost\r\n" +
                 "\r\n";
-        String response = tester.getResponses(request);
+        String response = tester.getResponses(request,1,TimeUnit.SECONDS);
         Assert.assertTrue(response.contains("HTTP/1.1 200"));
         Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER));
         Assert.assertFalse(response.contains(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER));
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DataRateLimitedServletTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DataRateLimitedServletTest.java
index e9e94eb..94fc06d 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DataRateLimitedServletTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DataRateLimitedServletTest.java
@@ -25,6 +25,8 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
 import java.util.Arrays;
 
 import org.eclipse.jetty.server.HttpConfiguration;
@@ -63,7 +65,12 @@
  
         context.setContextPath("/context");
         context.setWelcomeFiles(new String[]{"index.html", "index.jsp", "index.htm"});
-        context.setBaseResource(Resource.newResource(testdir.getEmptyDir()));
+        
+        File baseResourceDir = testdir.getEmptyDir();
+        // Use resolved real path for Windows and OSX
+        Path baseResourcePath = baseResourceDir.toPath().toRealPath();
+        
+        context.setBaseResource(Resource.newResource(baseResourcePath.toFile()));
         
         ServletHolder holder =context.addServlet(DataRateLimitedServlet.class,"/stream/*");
         holder.setInitParameter("buffersize",""+BUFFER);
@@ -85,15 +92,19 @@
     public void testStream() throws Exception
     {
         File content = testdir.getFile("content.txt");
+        String[] results=new String[10];
         try(OutputStream out = new FileOutputStream(content);)
         {
             byte[] b= new byte[1024];
             
             for (int i=1024;i-->0;)
             {
-                Arrays.fill(b,(byte)('0'+(i%10)));
+                int index=i%10;
+                Arrays.fill(b,(byte)('0'+(index)));
                 out.write(b);
                 out.write('\n');
+                if (results[index]==null)
+                    results[index]=new String(b,StandardCharsets.US_ASCII);
             }
         }
         
@@ -101,9 +112,11 @@
         String response = connector.getResponses("GET /context/stream/content.txt HTTP/1.0\r\n\r\n");
         long duration=System.currentTimeMillis()-start;
         
-        assertThat(response.length(),greaterThan(1024*1024));
-        assertThat(response,containsString("200 OK"));
-        assertThat(duration,greaterThan(PAUSE*1024L*1024/BUFFER));
+        assertThat("Response",response,containsString("200 OK"));
+        assertThat("Response Length",response.length(),greaterThan(1024*1024));
+        assertThat("Duration",duration,greaterThan(PAUSE*1024L*1024/BUFFER));
         
+        for (int i=0;i<10;i++)
+            assertThat(response,containsString(results[i]));
     }
 }
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
index f7b3352..04a434f 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java
@@ -18,8 +18,12 @@
 
 package org.eclipse.jetty.servlets;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import java.util.ArrayList;
 import java.util.List;
+
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -30,9 +34,6 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
 public class DoSFilterTest extends AbstractDoSFilterTest
 {
     private static final Logger LOG = Log.getLogger(DoSFilterTest.class);
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java
deleted file mode 100644
index 2a19f5f..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java
+++ /dev/null
@@ -1,352 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.DispatcherType;
-
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.gzip.AsyncScheduledDispatchWrite;
-import org.eclipse.jetty.servlets.gzip.AsyncTimeoutDispatchWrite;
-import org.eclipse.jetty.servlets.gzip.AsyncTimeoutCompleteWrite;
-import org.eclipse.jetty.servlets.gzip.GzipTester;
-import org.eclipse.jetty.servlets.gzip.GzipTester.ContentMetadata;
-import org.eclipse.jetty.servlets.gzip.TestDirContentServlet;
-import org.eclipse.jetty.servlets.gzip.TestServletBufferTypeLengthWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletLengthTypeStreamWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletStreamLengthTypeWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletStreamLengthTypeWriteWithFlush;
-import org.eclipse.jetty.servlets.gzip.TestServletStreamTypeLengthWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletTypeLengthStreamWrite;
-import org.eclipse.jetty.servlets.gzip.TestServletTypeStreamLengthWrite;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Test the GzipFilter support for Content-Length setting variations.
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@RunWith(Parameterized.class)
-public class GzipFilterContentLengthTest
-{
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-
-    @Rule
-    public TestingDir testingdir = new TestingDir();
-    
-    private static final HttpConfiguration defaultHttp = new HttpConfiguration();
-    private static final int LARGE = defaultHttp.getOutputBufferSize() * 8;
-    private static final int MEDIUM = defaultHttp.getOutputBufferSize();
-    private static final int SMALL = defaultHttp.getOutputBufferSize() / 4;
-    private static final int TINY = AsyncGzipFilter.DEFAULT_MIN_GZIP_SIZE / 2;
-    private static final boolean EXPECT_COMPRESSED = true;
-
-    @Parameters(name = "{0} bytes - {1} - compressed({2}) - type({3}) - filter({4})")
-    public static List<Object[]> data()
-    {
-        List<Object[]> ret = new ArrayList<Object[]>();
-        
-        String compressionTypes[] = new String[] { GzipFilter.GZIP, GzipFilter.DEFLATE };
-        Class<?> gzipFilters[] = new Class<?>[] { GzipFilter.class, AsyncGzipFilter.class };
-        
-        for(String compressionType: compressionTypes)
-        {
-            for(Class<?> gzipFilter: gzipFilters)
-            {
-                ret.add(new Object[] { 0, "empty.txt", !EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { TINY, "file-tiny.txt", !EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { SMALL, "file-small.txt", EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { SMALL, "file-small.mp3", !EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { MEDIUM, "file-med.txt", EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { MEDIUM, "file-medium.mp3", !EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { LARGE, "file-large.txt", EXPECT_COMPRESSED, compressionType, gzipFilter });
-                ret.add(new Object[] { LARGE, "file-large.mp3", !EXPECT_COMPRESSED, compressionType, gzipFilter });
-            }
-        }
-
-        return ret;
-    }
-
-    @Parameter(0)
-    public int fileSize;
-    @Parameter(1)
-    public String fileName;
-    @Parameter(2)
-    public boolean expectCompressed;
-    @Parameter(3)
-    public String compressionType;
-    @Parameter(4)
-    public Class<? extends GzipFilter> gzipFilterClass;
-    
-    private void testWithGzip(Class<? extends TestDirContentServlet> contentServlet) throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir, GzipFilter.GZIP);
-        
-        // Add AsyncGzip Filter
-        FilterHolder gzipHolder = new FilterHolder(gzipFilterClass);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"*.txt",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        tester.addFilter(gzipHolder,"*.mp3",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Add content servlet
-        tester.setContentServlet(contentServlet);
-        
-        try
-        {
-            String testFilename = String.format("%s-%s-%s", gzipFilterClass.getSimpleName(), contentServlet.getSimpleName(), fileName);
-            File testFile = tester.prepareServerFile(testFilename,fileSize);
-            
-            tester.start();
-            
-            HttpTester.Response response = tester.executeRequest("GET","/context/" + testFile.getName(),5,TimeUnit.SECONDS);
-            
-            if (response.getStatus()!=200)
-                System.err.println("DANG!!!! "+response);
-            
-            assertThat("Response status", response.getStatus(), is(HttpStatus.OK_200));
-            
-            if (expectCompressed)
-            {
-                // Must be gzip compressed
-                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipFilter.GZIP));
-            } else
-            {
-                assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(GzipFilter.GZIP)));
-            }
-            
-            // Uncompressed content Size
-            ContentMetadata content = tester.getResponseMetadata(response);
-            assertThat("(Uncompressed) Content Length", content.size, is((long)fileSize));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> timeout -> onTimeout -> write-response -> complete
-     */
-    @Test
-    public void testAsyncTimeoutCompleteWrite_Default() throws Exception
-    {
-        if (expectCompressed && gzipFilterClass==GzipFilter.class)
-            return; // Default startAsync will never work with GzipFilter, which needs wrapping
-        testWithGzip(AsyncTimeoutCompleteWrite.Default.class);
-    }
-    
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> timeout -> onTimeout -> write-response -> complete
-     */
-    @Test
-    public void testAsyncTimeoutCompleteWrite_Passed() throws Exception
-    {
-        testWithGzip(AsyncTimeoutCompleteWrite.Passed.class);
-    }
-    
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
-     */
-    @Test
-    public void testAsyncTimeoutDispatchWrite_Default() throws Exception
-    {
-        testWithGzip(AsyncTimeoutDispatchWrite.Default.class);
-    }
-    
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> timeout -> onTimeout -> dispatch -> write-response
-     */
-    @Test
-    public void testAsyncTimeoutDispatchWrite_Passed() throws Exception
-    {
-        testWithGzip(AsyncTimeoutDispatchWrite.Passed.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
-     */
-    @Test
-    public void testAsyncScheduledDispatchWrite_Default() throws Exception
-    {
-        testWithGzip(AsyncScheduledDispatchWrite.Default.class);
-    }
-    
-    /**
-     * Test with content servlet that does:  
-     * AsyncContext create -> no-timeout -> scheduler.schedule -> dispatch -> write-response
-     */
-    @Test
-    public void testAsyncScheduledDispatchWrite_Passed() throws Exception
-    {
-        testWithGzip(AsyncScheduledDispatchWrite.Passed.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) setHeader(content-length)
-     * 2) getOutputStream()
-     * 3) setHeader(content-type)
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletLengthStreamTypeWrite() throws Exception
-    {
-        testWithGzip(TestServletLengthStreamTypeWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) setHeader(content-length)
-     * 2) setHeader(content-type)
-     * 3) getOutputStream()
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletLengthTypeStreamWrite() throws Exception
-    {
-        testWithGzip(TestServletLengthTypeStreamWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) getOutputStream()
-     * 2) setHeader(content-length)
-     * 3) setHeader(content-type)
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletStreamLengthTypeWrite() throws Exception
-    {
-        testWithGzip(TestServletStreamLengthTypeWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) getOutputStream()
-     * 2) setHeader(content-length)
-     * 3) setHeader(content-type)
-     * 4) outputStream.write() (with frequent response flush)
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletStreamLengthTypeWriteWithFlush() throws Exception
-    {
-        testWithGzip(TestServletStreamLengthTypeWriteWithFlush.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) getOutputStream()
-     * 2) setHeader(content-type)
-     * 3) setHeader(content-length)
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletStreamTypeLengthWrite() throws Exception
-    {
-        testWithGzip(TestServletStreamTypeLengthWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) setHeader(content-type)
-     * 2) setHeader(content-length)
-     * 3) getOutputStream()
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletTypeLengthStreamWrite() throws Exception
-    {
-        testWithGzip(TestServletTypeLengthStreamWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 1) setHeader(content-type)
-     * 2) getOutputStream()
-     * 3) setHeader(content-length)
-     * 4) outputStream.write()
-     * 
-     * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
-     */
-    @Test
-    public void testServletTypeStreamLengthWrite() throws Exception
-    {
-        testWithGzip(TestServletTypeStreamLengthWrite.class);
-    }
-
-    /**
-     * Test with content servlet that does:  
-     * 2) getOutputStream()
-     * 1) setHeader(content-type)
-     * 3) setHeader(content-length)
-     * 4) (unwrapped) HttpOutput.write(ByteBuffer)
-     * 
-     * This is done to demonstrate a bug with using HttpOutput.write()
-     * while also using GzipFilter
-     * 
-     * @see <a href="Eclipse Bug 450873">http://bugs.eclipse.org/450873</a>
-     */
-    @Test
-    public void testHttpOutputWrite() throws Exception
-    {
-        if (gzipFilterClass == GzipFilter.class)
-            return;  // Can't downcaste output stream when wrapper is used
-        testWithGzip(TestServletBufferTypeLengthWrite.class);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
deleted file mode 100644
index 2304699..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.servlet.Filter;
-
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.gzip.GzipTester;
-import org.eclipse.jetty.servlets.gzip.TestStaticMimeTypeServlet;
-import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Tests {@link GzipFilter} in combination with {@link DefaultServlet} for ability to configure {@link GzipFilter} to
- * ignore recompress situations from upstream.
- */
-@RunWith(Parameterized.class)
-public class GzipFilterDefaultNoRecompressTest
-{
-    @Parameters
-    public static List<Object[]> data()
-    {
-        return Arrays.asList(new Object[][]
-        {
-                // Some already compressed files
-                { GzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP },
-                { GzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP },
-                { GzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP },
-                { GzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP },
-                // Some images (common first)
-                { GzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP },
-                // Lesser encountered images (usually found being requested from non-browser clients)
-                { GzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP },
-                { GzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP },
-                //qvalue disables compression
-                { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"},
-                { GzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q =    0 "},
-                
-                
-                // Some already compressed files
-                { AsyncGzipFilter.class, "test_quotes.gz", "application/gzip", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "test_quotes.zip", "application/zip", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP },
-                // Some images (common first)
-                { AsyncGzipFilter.class, "jetty_logo.png", "image/png", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.gif", "image/gif", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP },
-                // Lesser encountered images (usually found being requested from non-browser clients)
-                { AsyncGzipFilter.class, "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.tga", "application/tga", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.tif", "image/tiff", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP },
-                { AsyncGzipFilter.class, "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP },
-                //qvalue disables compression
-                { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+";q=0"},
-                { AsyncGzipFilter.class, "test_quotes.txt", "text/plain", GzipFilter.GZIP+"; q =    0 "}
-        });
-    }
-
-    @Rule
-    public TestingDir testingdir = new TestingDir();
-
-    private Class<? extends Filter> testFilter;
-    private String alreadyCompressedFilename;
-    private String expectedContentType;
-    private String compressionType;
-
-    public GzipFilterDefaultNoRecompressTest(Class<? extends Filter> testFilter,String testFilename, String expectedContentType, String compressionType)
-    {
-        this.testFilter = testFilter;
-        this.alreadyCompressedFilename = testFilename;
-        this.expectedContentType = expectedContentType;
-        this.compressionType = compressionType;
-    }
-
-    @Test
-    public void testNotGzipFiltered_Default_AlreadyCompressed() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir, compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        copyTestFileToServer(alreadyCompressedFilename);
-
-        FilterHolder holder = tester.setContentServlet(TestStaticMimeTypeServlet.class);
-        StringBuilder mimeTypes = new StringBuilder();
-        mimeTypes.append("text/plain");
-        holder.setInitParameter("mimeTypes",mimeTypes.toString());
-
-        try
-        {
-            tester.start();
-            tester.assertIsResponseNotGzipFiltered(alreadyCompressedFilename,alreadyCompressedFilename + ".sha1",expectedContentType);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    private void copyTestFileToServer(String testFilename) throws IOException
-    {
-        File testFile = MavenTestingUtils.getTestResourceFile(testFilename);
-        File outFile = testingdir.getFile(testFilename);
-        IO.copy(testFile,outFile);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
deleted file mode 100644
index 845cf68..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java
+++ /dev/null
@@ -1,794 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.gzip.GzipTester;
-import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.eclipse.jetty.util.StringUtil;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Test the GzipFilter support built into the {@link DefaultServlet}
- */
-@RunWith(Parameterized.class)
-public class GzipFilterDefaultTest
-{
-    @Parameters(name="{1} - {0}")
-    public static List<Object[]> data()
-    {
-        return Arrays.asList(new Object[][]
-        { 
-            { AsyncGzipFilter.class, GzipFilter.GZIP },
-            { GzipFilter.class, GzipFilter.GZIP },
-            { GzipFilter.class, GzipFilter.DEFLATE },
-        });
-    }
-
-    private Class<? extends Filter> testFilter;
-    private String compressionType;
-
-    public GzipFilterDefaultTest(Class<? extends Filter> testFilter, String compressionType)
-    {
-        this.testFilter = testFilter;
-        this.compressionType = compressionType;
-    }
-
-    @SuppressWarnings("serial")
-    public static class HttpStatusServlet extends HttpServlet
-    {
-        private int _status = 204;
-
-        public HttpStatusServlet()
-        {
-            super();
-        }
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-        {
-            resp.setStatus(_status);
-            resp.setHeader("ETag","W/\"204\"");
-        }
-
-    }
-
-    @SuppressWarnings("serial")
-    public static class HttpErrorServlet extends HttpServlet
-    {
-        private int _status = 400;
-
-        public HttpErrorServlet()
-        {
-            super();
-        }
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-        {
-            resp.getOutputStream().write("error message".getBytes());
-            resp.setStatus(_status);
-        }
-    }
-
-    @SuppressWarnings("serial")
-    public static class HttpContentTypeWithEncoding extends HttpServlet
-    {
-        public static final String COMPRESSED_CONTENT = "<html><head></head><body><h1>COMPRESSABLE CONTENT</h1>"
-                + "This content must be longer than the default min gzip length, which is 256 bytes. "
-                + "The moon is blue to a fish in love. How now brown cow. The quick brown fox jumped over the lazy dog. A woman needs a man like a fish needs a bicycle!"
-                + "</body></html>";
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-        {
-            resp.setContentType("text/plain;charset=UTF8");
-            resp.setStatus(200);
-            ServletOutputStream out = resp.getOutputStream();
-            out.print(COMPRESSED_CONTENT);
-        }
-
-    }
-
-    @Rule
-    public TestingDir testingdir = new TestingDir();
-
-    @Test
-    public void testIsGzipByMethod() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-        gzipHolder.setInitParameter("methods","POST, WIBBLE");
-
-        // Prepare Server File
-        int filesize = tester.getOutputBufferSize() * 2;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Content Servlet
-        tester.setContentServlet(GetServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response response;
-
-            tester.assertIsResponseGzipCompressed("POST","file.txt");
-            tester.assertIsResponseGzipCompressed("WIBBLE","file.txt");
-
-            response = tester.executeRequest("GET","/context/file.txt",5,TimeUnit.SECONDS);
-
-            assertThat("Response status",response.getStatus(),is(HttpStatus.OK_200));
-            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
-
-            String content = tester.readResponse(response);
-            assertThat("Response content size",content.length(),is(filesize));
-            String expectedContent = IO.readToString(testingdir.getFile("file.txt"));
-            assertThat("Response content",content,is(expectedContent));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @SuppressWarnings("serial")
-    public static class GetServlet extends DefaultServlet
-    {
-        public GetServlet()
-        {
-            super();
-        }
-
-        @Override
-        public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
-        {
-            String uri = req.getRequestURI();
-            if (uri.endsWith(".deferred"))
-            {
-                // System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
-                resp.setContentType(getServletContext().getMimeType(uri.substring(0,uri.length() - 9)));
-            }
-
-            doGet(req,resp);
-        }
-    }
-
-    @Test
-    public void testIsGzipCompressedEmpty() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Prepare server file
-        tester.prepareServerFile("empty.txt",0);
-
-        // Set content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-
-            HttpTester.Response response;
-
-            response = tester.executeRequest("GET","/context/empty.txt",5,TimeUnit.SECONDS);
-
-            assertThat("Response status",response.getStatus(),is(HttpStatus.OK_200));
-            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
-
-            String content = tester.readResponse(response);
-            assertThat("Response content size",content.length(),is(0));
-            String expectedContent = IO.readToString(testingdir.getFile("empty.txt"));
-            assertThat("Response content",content,is(expectedContent));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsGzipCompressedTiny() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        int filesize = tester.getOutputBufferSize() / 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsGzipCompressedLarge() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testGzipedIfModified() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt",System.currentTimeMillis() - 4000);
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testGzippedIfSVG() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-        tester.copyTestServerFile("test.svg");
-        @SuppressWarnings("unused")
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","test.svg",System.currentTimeMillis() - 4000);
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testNotGzipedIfNotModified() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-        holder.setInitParameter("etags","true");
-
-        try
-        {
-            tester.start();
-            tester.assertIsResponseNotModified("GET","file.txt",System.currentTimeMillis() + 4000);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedWithZeroQ() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType + "; q=0");
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() / 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Add content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
-            assertThat("Response[Vary]",http.get("Vary"),containsString("Accept-Encoding"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsGzipCompressedWithQ() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType,"something;q=0.1," + compressionType + ";q=0.5");
-        tester.setGzipFilterClass(testFilter);
-
-        int filesize = tester.getOutputBufferSize() / 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertIsResponseGzipCompressed("GET","file.txt");
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedByContentType() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.mp3",filesize);
-
-        // Add content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","file.mp3",filesize,HttpStatus.OK_200);
-            Assert.assertNull(http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedByExcludedContentType() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("excludedMimeTypes","text/plain");
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("test_quotes.txt",filesize);
-
-        // Add content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","test_quotes.txt",filesize,HttpStatus.OK_200);
-            Assert.assertNull(http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedByExcludedContentTypeWithCharset() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("excludedMimeTypes","text/plain");
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("test_quotes.txt",filesize);
-        tester.addMimeType("txt","text/plain;charset=UTF-8");
-
-        // Add content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response http = assertIsResponseNotGzipCompressed(tester,"GET","test_quotes.txt",filesize,HttpStatus.OK_200);
-            Assert.assertNull(http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testGzipCompressedByContentTypeWithEncoding() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-        FilterHolder holder = tester.setContentServlet(HttpContentTypeWithEncoding.class);
-        holder.setInitParameter("mimeTypes","text/plain");
-        try
-        {
-            tester.start();
-            HttpTester.Response http = tester.assertNonStaticContentIsResponseGzipCompressed("GET","xxx",HttpContentTypeWithEncoding.COMPRESSED_CONTENT);
-            Assert.assertEquals("Accept-Encoding",http.get("Vary"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedByDeferredContentType() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.mp3.deferred",filesize);
-
-        // Add content servlet
-        tester.setContentServlet(GetServlet.class);
-
-        try
-        {
-            tester.start();
-            HttpTester.Response response = assertIsResponseNotGzipCompressed(tester,"GET","file.mp3.deferred",filesize,HttpStatus.OK_200);
-            assertThat("Response[Vary]", response.get("Vary"), isEmptyOrNullString());
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedHttpStatus() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-
-        // Test error code 204
-        tester.setContentServlet(HttpStatusServlet.class);
-
-        try
-        {
-            tester.start();
-
-            HttpTester.Response response = tester.executeRequest("GET","/context/",5,TimeUnit.SECONDS);
-
-            assertThat("Response status",response.getStatus(),is(HttpStatus.NO_CONTENT_204));
-            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
-        }
-        finally
-        {
-            tester.stop();
-        }
-
-    }
-
-    @Test
-    public void testIsNotGzipCompressedHttpBadRequestStatus() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-
-        // Test error code 400
-        tester.setContentServlet(HttpErrorServlet.class);
-
-        try
-        {
-            tester.start();
-
-            HttpTester.Response response = tester.executeRequest("GET","/context/",5,TimeUnit.SECONDS);
-
-            assertThat("Response status",response.getStatus(),is(HttpStatus.BAD_REQUEST_400));
-            assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
-
-            String content = tester.readResponse(response);
-            assertThat("Response content",content,is("error message"));
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testUserAgentExclusion() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setUserAgent("foo");
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        gzipHolder.setInitParameter("mimeTypes","text/plain");
-        gzipHolder.setInitParameter("excludedAgents","bar, foo");
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Add content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testUserAgentExclusionByExcludedAgentPatterns() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setUserAgent("foo");
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        gzipHolder.setInitParameter("excludedAgents","bar");
-        gzipHolder.setInitParameter("excludeAgentPatterns","fo.*");
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Set content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testExcludePaths() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        gzipHolder.setInitParameter("excludePaths","/bar/, /context/");
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Set content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testExcludePathPatterns() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-
-        // Add Gzip Filter first
-        FilterHolder gzipHolder = new FilterHolder(testFilter);
-        gzipHolder.setAsyncSupported(true);
-        gzipHolder.setInitParameter("excludePathPatterns","/cont.*");
-        tester.addFilter(gzipHolder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC));
-
-        // Prepare server file
-        int filesize = tester.getOutputBufferSize() * 4;
-        tester.prepareServerFile("file.txt",filesize);
-
-        // Set content servlet
-        tester.setContentServlet(DefaultServlet.class);
-
-        try
-        {
-            tester.start();
-            assertIsResponseNotGzipCompressed(tester,"GET","file.txt",filesize,HttpStatus.OK_200);
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-
-    public HttpTester.Response assertIsResponseNotGzipCompressed(GzipTester tester, String method, String filename, int expectedFilesize, int status)
-            throws Exception
-    {
-        HttpTester.Response response = tester.executeRequest(method,"/context/" + filename,5,TimeUnit.SECONDS);
-
-        assertThat("Response status",response.getStatus(),is(status));
-        assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(compressionType)));
-
-        assertResponseContent(tester,response,status,filename,expectedFilesize);
-
-        return response;
-    }
-
-    private void assertResponseContent(GzipTester tester, HttpTester.Response response, int status, String filename, int expectedFilesize) throws IOException,
-            UnsupportedEncodingException
-    {
-        if (expectedFilesize >= 0)
-        {
-            assertThat("filename",filename,notNullValue());
-            assertThat("Response contentBytes.length",response.getContentBytes().length,is(expectedFilesize));
-            String contentLength = response.get("Content-Length");
-            if (StringUtil.isNotBlank(contentLength))
-            {
-                assertThat("Content-Length",response.get("Content-Length"),is(Integer.toString(expectedFilesize)));
-            }
-
-            if (status >= 200 && status < 300)
-            {
-                assertThat("ETag",response.get("ETAG"),startsWith("W/"));
-            }
-
-            File serverFile = testingdir.getFile(filename);
-            String expectedResponse = IO.readToString(serverFile);
-
-            String actual = tester.readResponse(response);
-            Assert.assertEquals("Expected response equals actual response",expectedResponse,actual);
-        }
-    }
-
-    @Test
-    public void testIsNotGzipCompressedSVGZ() throws Exception
-    {
-        GzipTester tester = new GzipTester(testingdir,compressionType);
-        tester.setGzipFilterClass(testFilter);
-
-        @SuppressWarnings("unused")
-        FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
-        tester.copyTestServerFile("test.svgz");
-        try
-        {
-            tester.start();
-            tester.assertIsResponseNotGzipFiltered("test.svgz","test.svgz.sha1","image/svg+xml","gzip");
-        }
-        finally
-        {
-            tester.stop();
-        }
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterLayeredTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterLayeredTest.java
index d5ec9bd..327c23a 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterLayeredTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterLayeredTest.java
@@ -18,8 +18,10 @@
 
 package org.eclipse.jetty.servlets;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -32,15 +34,16 @@
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpTester;
 import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.handler.gzip.AsyncManipFilter;
+import org.eclipse.jetty.server.handler.gzip.AsyncScheduledDispatchWrite;
+import org.eclipse.jetty.server.handler.gzip.AsyncTimeoutCompleteWrite;
+import org.eclipse.jetty.server.handler.gzip.AsyncTimeoutDispatchWrite;
+import org.eclipse.jetty.server.handler.gzip.GzipHandler;
+import org.eclipse.jetty.server.handler.gzip.GzipTester;
+import org.eclipse.jetty.server.handler.gzip.GzipTester.ContentMetadata;
+import org.eclipse.jetty.server.handler.gzip.TestDirContentServlet;
+import org.eclipse.jetty.server.handler.gzip.TestServletLengthStreamTypeWrite;
 import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.gzip.AsyncManipFilter;
-import org.eclipse.jetty.servlets.gzip.AsyncScheduledDispatchWrite;
-import org.eclipse.jetty.servlets.gzip.AsyncTimeoutCompleteWrite;
-import org.eclipse.jetty.servlets.gzip.AsyncTimeoutDispatchWrite;
-import org.eclipse.jetty.servlets.gzip.GzipTester;
-import org.eclipse.jetty.servlets.gzip.GzipTester.ContentMetadata;
-import org.eclipse.jetty.servlets.gzip.TestDirContentServlet;
-import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite;
 import org.eclipse.jetty.toolchain.test.TestTracker;
 import org.eclipse.jetty.toolchain.test.TestingDir;
 import org.junit.Ignore;
@@ -64,7 +67,7 @@
     private static final HttpConfiguration defaultHttp = new HttpConfiguration();
     private static final int LARGE = defaultHttp.getOutputBufferSize() * 8;
     private static final int SMALL = defaultHttp.getOutputBufferSize() / 4;
-    private static final int TINY = AsyncGzipFilter.DEFAULT_MIN_GZIP_SIZE / 2;
+    private static final int TINY = GzipHandler.DEFAULT_MIN_GZIP_SIZE / 2;
     private static final boolean EXPECT_COMPRESSED = true;
 
     @Parameters(name = "{0} bytes - {1} - compressed({2}) - filter({3}) - servlet({4}")
@@ -115,7 +118,7 @@
     @Test
     public void testGzipDos() throws Exception
     {
-        GzipTester tester = new GzipTester(testingdir, GzipFilter.GZIP);
+        GzipTester tester = new GzipTester(testingdir, GzipHandler.GZIP);
         
         // Add Gzip Filter first
         FilterHolder gzipHolder = new FilterHolder(gzipFilterClass);
@@ -146,7 +149,7 @@
             if (expectCompressed)
             {
                 // Must be gzip compressed
-                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipFilter.GZIP));
+                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipHandler.GZIP));
             }
             
             // Uncompressed content Size
@@ -162,7 +165,7 @@
     @Test
     public void testDosGzip() throws Exception
     {
-        GzipTester tester = new GzipTester(testingdir, GzipFilter.GZIP);
+        GzipTester tester = new GzipTester(testingdir, GzipHandler.GZIP);
         
         // Add (DoSFilter-like) manip filter
         FilterHolder manipHolder = new FilterHolder(AsyncManipFilter.class);
@@ -193,10 +196,10 @@
             if (expectCompressed)
             {
                 // Must be gzip compressed
-                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipFilter.GZIP));
+                assertThat("Content-Encoding",response.get("Content-Encoding"),containsString(GzipHandler.GZIP));
             } else
             {
-                assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(GzipFilter.GZIP)));
+                assertThat("Content-Encoding",response.get("Content-Encoding"),not(containsString(GzipHandler.GZIP)));
             }
             
             // Uncompressed content Size
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java
deleted file mode 100644
index ef4eb16..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.servlet.Servlet;
-
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.gzip.GzipTester;
-import org.eclipse.jetty.servlets.gzip.TestMinGzipSizeServlet;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Perform specific tests on the IncludableGzipFilter's ability to manage
- * minGzipSize initialization parameter.
- *
- * @see <a href="Eclipse Bug 366106">http://bugs.eclipse.org/366106</a>
- */
-@RunWith(Parameterized.class)
-public class IncludableGzipFilterMinSizeTest
-{
-    @Parameters
-    public static Collection<String[]> data()
-    {
-        String[][] data = new String[][]
-                {
-                { GzipFilter.GZIP },
-                { GzipFilter.DEFLATE }
-                };
-
-        return Arrays.asList(data);
-    }
-
-    public IncludableGzipFilterMinSizeTest(String compressionType)
-    {
-        this.compressionType = compressionType;
-    }
-
-    @Rule
-    public TestingDir testdir = new TestingDir();
-
-    private String compressionType;
-    private Class<? extends Servlet> testServlet = TestMinGzipSizeServlet.class;
-
-    @Test
-    public void testUnderMinSize() throws Exception
-    {
-        GzipTester tester = new GzipTester(testdir, compressionType);
-        // Use IncludableGzipFilter
-        tester.setGzipFilterClass(IncludableGzipFilter.class);
-
-        FilterHolder holder = tester.setContentServlet(testServlet);
-        // A valid mime type that we will never use in this test.
-        // configured here to prevent mimeType==null logic
-        holder.setInitParameter("mimeTypes","application/soap+xml");
-        holder.setInitParameter("minGzipSize", "2048");
-        holder.setInitParameter("uncheckedPrintWriter","true");
-
-        tester.copyTestServerFile("small_script.js");
-
-        try {
-            tester.start();
-            tester.assertIsResponseNotGzipFiltered("small_script.js",
-                    "small_script.js.sha1",
-                    "text/javascript; charset=utf-8");
-        } finally {
-            tester.stop();
-        }
-    }
-
-    @Test
-    public void testOverMinSize() throws Exception
-    {
-        GzipTester tester = new GzipTester(testdir, compressionType);
-        // Use IncludableGzipFilter
-        tester.setGzipFilterClass(IncludableGzipFilter.class);
-
-        FilterHolder holder = tester.setContentServlet(testServlet);
-        holder.setInitParameter("mimeTypes","application/soap+xml,text/javascript,application/javascript");
-        holder.setInitParameter("minGzipSize", "2048");
-        holder.setInitParameter("uncheckedPrintWriter","true");
-
-        tester.copyTestServerFile("big_script.js");
-
-        try {
-            tester.start();
-            tester.assertIsResponseGzipCompressed("GET","big_script.js");
-        } finally {
-            tester.stop();
-        }
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java
deleted file mode 100644
index 51b567a..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.ServletTester;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.IO;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class IncludableGzipFilterTest
-{
-    @Parameters
-    public static Collection<String[]> data()
-    {
-        String[][] data = new String[][]
-                {
-                { GzipFilter.GZIP },
-                { GzipFilter.DEFLATE }
-                };
-
-        return Arrays.asList(data);
-    }
-
-    @Rule
-    public TestingDir testdir = new TestingDir();
-
-    private static String __content =
-        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
-        "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
-        "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
-        "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
-        "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
-        "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
-        "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
-        "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
-        "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
-        "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
-        "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
-        "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
-
-    private ServletTester tester;
-    private String compressionType;
-
-    public IncludableGzipFilterTest(String compressionType)
-    {
-        this.compressionType = compressionType;
-    }
-
-    @Before
-    public void setUp() throws Exception
-    {
-        testdir.ensureEmpty();
-
-        File testFile = testdir.getFile("file.txt");
-        try (OutputStream testOut = new BufferedOutputStream(new FileOutputStream(testFile)))
-        {
-            ByteArrayInputStream testIn = new ByteArrayInputStream(__content.getBytes("ISO8859_1"));
-            IO.copy(testIn,testOut);
-        }
-
-        tester=new ServletTester("/context");
-        tester.getContext().setResourceBase(testdir.getDir().getCanonicalPath());
-        tester.getContext().addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
-        FilterHolder holder = tester.getContext().addFilter(IncludableGzipFilter.class,"/*",null);
-        holder.setInitParameter("mimeTypes","text/plain");
-        tester.start();
-    }
-
-    @After
-    public void tearDown() throws Exception
-    {
-        tester.stop();
-        IO.delete(testdir.getDir());
-    }
-
-    @Test
-    public void testGzipFilter() throws Exception
-    {
-        // generated and parsed test
-
-        ByteBuffer request=BufferUtil.toBuffer(
-            "GET /context/file.txt HTTP/1.0\r\n"+
-            "Host: tester\r\n"+
-            "Accept-Encoding: "+compressionType+"\r\n"+
-            "\r\n");
-
-
-        HttpTester.Response response=HttpTester.parseResponse(tester.getResponses(request));
-
-        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-        assertEquals(compressionType,response.get("Content-Encoding"));
-
-        InputStream testIn = null;
-        ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes());
-        if (compressionType.equals(GzipFilter.GZIP))
-        {
-            testIn = new GZIPInputStream(compressedResponseStream);
-        }
-        else if (compressionType.equals(GzipFilter.DEFLATE))
-        {
-            testIn = new InflaterInputStream(compressedResponseStream, new Inflater(true));
-        }
-        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
-        IO.copy(testIn,testOut);
-
-        assertEquals(__content, testOut.toString("ISO8859_1"));
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
index d1ad20a..01cdb45 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
@@ -780,10 +780,6 @@
         assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.getStatus());
     }
 
-    /*
-     * see the testParameterMap test
-     *
-     */
     public static class TestServletParameterMap extends DumpServlet
     {
         @Override
@@ -798,7 +794,7 @@
     /**
      * Validate that the getParameterMap() call is correctly unencoding the parameters in the
      * map that it returns.
-     * @throws Exception
+     * @throws Exception on test failure
      */
     @Test
     public void testParameterMap() throws Exception
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
index 1e56f55..37815c1 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
@@ -23,6 +23,7 @@
 import java.util.EnumSet;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.DispatcherType;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ThreadStarvationTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ThreadStarvationTest.java
new file mode 100644
index 0000000..9ff0db5
--- /dev/null
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ThreadStarvationTest.java
@@ -0,0 +1,419 @@
+//

+//  ========================================================================

+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.servlets;

+

+import java.io.File;

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStream;

+import java.net.Socket;

+import java.nio.ByteBuffer;

+import java.nio.channels.SelectionKey;

+import java.nio.channels.SocketChannel;

+import java.nio.charset.StandardCharsets;

+import java.nio.file.Files;

+import java.nio.file.Path;

+import java.nio.file.Paths;

+import java.nio.file.StandardOpenOption;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.List;

+import java.util.concurrent.BrokenBarrierException;

+import java.util.concurrent.CountDownLatch;

+import java.util.concurrent.CyclicBarrier;

+import java.util.concurrent.Exchanger;

+import java.util.concurrent.Executors;

+import java.util.concurrent.ScheduledFuture;

+import java.util.concurrent.TimeUnit;

+import java.util.concurrent.TimeoutException;

+import java.util.concurrent.atomic.AtomicBoolean;

+import java.util.concurrent.atomic.AtomicInteger;

+

+import javax.servlet.ServletException;

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import org.eclipse.jetty.io.ManagedSelector;

+import org.eclipse.jetty.io.SelectChannelEndPoint;

+import org.eclipse.jetty.server.HttpChannel;

+import org.eclipse.jetty.server.Request;

+import org.eclipse.jetty.server.Server;

+import org.eclipse.jetty.server.ServerConnector;

+import org.eclipse.jetty.server.handler.AbstractHandler;

+import org.eclipse.jetty.servlet.DefaultServlet;

+import org.eclipse.jetty.servlet.ServletContextHandler;

+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;

+import org.eclipse.jetty.toolchain.test.TestTracker;

+import org.eclipse.jetty.toolchain.test.annotation.Slow;

+import org.eclipse.jetty.util.log.Log;

+import org.eclipse.jetty.util.log.StdErrLog;

+import org.eclipse.jetty.util.thread.QueuedThreadPool;

+import org.junit.After;

+import org.junit.Assert;

+import org.junit.Rule;

+import org.junit.Test;

+

+public class ThreadStarvationTest

+{

+    @Rule

+    public TestTracker tracker = new TestTracker();

+    private Server _server;

+

+    @After

+    public void dispose() throws Exception

+    {

+        if (_server != null)

+            _server.stop();

+    }

+

+    @Test

+    @Slow

+    public void testDefaultServletSuccess() throws Exception

+    {

+        int maxThreads = 10;

+        QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, maxThreads);

+        threadPool.setDetailedDump(true);

+        _server = new Server(threadPool);

+

+        // Prepare a big file to download.

+        File directory = MavenTestingUtils.getTargetTestingDir();

+        Files.createDirectories(directory.toPath());

+        String resourceName = "resource.bin";

+        Path resourcePath = Paths.get(directory.getPath(), resourceName);

+        try (OutputStream output = Files.newOutputStream(resourcePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE))

+        {

+            byte[] chunk = new byte[1024];

+            Arrays.fill(chunk,(byte)'X');

+            chunk[chunk.length-2]='\r';

+            chunk[chunk.length-1]='\n';

+            for (int i = 0; i < 256 * 1024; ++i)

+                output.write(chunk);

+        }

+

+        final CountDownLatch writePending = new CountDownLatch(1);

+        ServerConnector connector = new ServerConnector(_server, 0, 1)

+        {

+            @Override

+            protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException

+            {

+                return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout())

+                {

+                    @Override

+                    protected void onIncompleteFlush()

+                    {

+                        super.onIncompleteFlush();

+                        writePending.countDown();

+                    }

+                };

+            }

+        };

+        connector.setIdleTimeout(Long.MAX_VALUE);

+        _server.addConnector(connector);

+

+        ServletContextHandler context = new ServletContextHandler(_server, "/");

+        context.setResourceBase(directory.toURI().toString());

+        context.addServlet(DefaultServlet.class, "/*").setAsyncSupported(false);

+        _server.setHandler(context);

+

+        _server.start();

+

+        List<Socket> sockets = new ArrayList<>();

+        for (int i = 0; i < maxThreads*2; ++i)

+        {

+            Socket socket = new Socket("localhost", connector.getLocalPort());

+            sockets.add(socket);

+            OutputStream output = socket.getOutputStream();

+            String request = "" +

+                    "GET /" + resourceName + " HTTP/1.1\r\n" +

+                    "Host: localhost\r\n" +

+                    "\r\n";

+            output.write(request.getBytes(StandardCharsets.UTF_8));

+            output.flush();

+            Thread.sleep(100);

+        }

+

+        // Wait for a the servlet to block.

+        Assert.assertTrue(writePending.await(5, TimeUnit.SECONDS));

+

+        long expected = Files.size(resourcePath);

+        byte[] buffer = new byte[48 * 1024];

+        List<Exchanger<Long>> totals = new ArrayList<>();

+        for (Socket socket : sockets)

+        {

+            final Exchanger<Long> x = new Exchanger<>();

+            totals.add(x);

+            final InputStream input = socket.getInputStream();

+

+            new Thread()

+            {

+                @Override

+                public void run()

+                {

+                    long total=0;

+                    try

+                    {

+                        // look for CRLFCRLF

+                        StringBuilder header = new StringBuilder();

+                        int state=0;

+                        while (state<4 && header.length()<2048)

+                        {

+                            int ch=input.read();

+                            if (ch<0)

+                                break;

+                            header.append((char)ch);

+                            switch(state)

+                            {

+                                case 0:

+                                    if (ch=='\r')

+                                        state=1;

+                                    break;

+                                case 1:

+                                    if (ch=='\n')

+                                        state=2;

+                                    else

+                                        state=0;

+                                    break;

+                                case 2:

+                                    if (ch=='\r')

+                                        state=3;

+                                    else

+                                        state=0;

+                                    break;

+                                case 3:

+                                    if (ch=='\n')

+                                        state=4;

+                                    else

+                                        state=0;

+                                    break;

+                            }

+                        }

+

+                        while (total<expected)

+                        {

+                            int read=input.read(buffer);

+                            if (read<0)

+                                break;

+                            total+=read;

+                        }

+                    }

+                    catch (IOException e)

+                    {

+                        e.printStackTrace();

+                    }

+                    finally

+                    {

+                        try

+                        {

+                            x.exchange(total);

+                        }

+                        catch (InterruptedException e)

+                        {

+                            e.printStackTrace();

+                        }

+                    }

+                }

+            }.start();

+        }

+

+        for (Exchanger<Long> x : totals)

+        {

+            Long total = x.exchange(-1L,10000,TimeUnit.SECONDS);

+            Assert.assertEquals(expected,total.longValue());

+        }

+        

+        // We could read everything, good.

+        for (Socket socket : sockets)

+            socket.close();

+    }

+    

+    @Test

+    public void testFailureStarvation() throws Exception

+    {

+        try

+        {

+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);

+

+            int acceptors = 0;

+            int selectors = 1;

+            int maxThreads = 10;

+            final int barried=maxThreads-acceptors-selectors;

+            final CyclicBarrier barrier = new CyclicBarrier(barried);

+

+

+            QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, maxThreads);

+            threadPool.setDetailedDump(true);

+            _server = new Server(threadPool);

+

+

+            ServerConnector connector = new ServerConnector(_server, acceptors, selectors)

+            {

+                @Override

+                protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException

+                {

+                    return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout())

+                    {

+

+                        @Override

+                        public boolean flush(ByteBuffer... buffers) throws IOException

+                        {

+                            super.flush(buffers[0]);

+                            throw new IOException("TEST FAILURE");

+                        }

+

+                    };

+                }

+            };

+            connector.setIdleTimeout(Long.MAX_VALUE);

+            _server.addConnector(connector);

+

+            final AtomicInteger count = new AtomicInteger(0);

+            _server.setHandler(new AbstractHandler()

+            {

+                @Override

+                public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException

+                {

+                    int c=count.getAndIncrement();

+                    try

+                    {

+                        if (c<barried)

+                        {

+                            barrier.await(10,TimeUnit.SECONDS);

+                        }

+                    }

+                    catch (InterruptedException | BrokenBarrierException | TimeoutException e)

+                    {

+                        throw new ServletException(e);

+                    }

+                    baseRequest.setHandled(true);

+                    response.setStatus(200);

+                    response.setContentLength(13);

+                    response.getWriter().print("Hello World!\n");

+                    response.getWriter().flush();

+                }

+            });

+

+            _server.start();

+

+            List<Socket> sockets = new ArrayList<>();

+            for (int i = 0; i < maxThreads*2; ++i)

+            {

+                Socket socket = new Socket("localhost", connector.getLocalPort());

+                sockets.add(socket);

+                OutputStream output = socket.getOutputStream();

+                String request = "" +

+                        "GET / HTTP/1.1\r\n" +

+                        "Host: localhost\r\n" +

+                        //                    "Connection: close\r\n" +

+                        "\r\n";

+                output.write(request.getBytes(StandardCharsets.UTF_8));

+                output.flush();

+            }

+

+

+            byte[] buffer = new byte[48 * 1024];

+            List<Exchanger<Integer>> totals = new ArrayList<>();

+            for (Socket socket : sockets)

+            {

+                final Exchanger<Integer> x = new Exchanger<>();

+                totals.add(x);

+                final InputStream input = socket.getInputStream();

+

+                new Thread()

+                {

+                    @Override

+                    public void run()

+                    {

+                        int read=0;

+                        try

+                        {

+                            // look for CRLFCRLF

+                            StringBuilder header = new StringBuilder();

+                            int state=0;

+                            while (state<4 && header.length()<2048)

+                            {

+                                int ch=input.read();

+                                if (ch<0)

+                                    break;

+                                header.append((char)ch);

+                                switch(state)

+                                {

+                                    case 0:

+                                        if (ch=='\r')

+                                            state=1;

+                                        break;

+                                    case 1:

+                                        if (ch=='\n')

+                                            state=2;

+                                        else

+                                            state=0;

+                                        break;

+                                    case 2:

+                                        if (ch=='\r')

+                                            state=3;

+                                        else

+                                            state=0;

+                                        break;

+                                    case 3:

+                                        if (ch=='\n')

+                                            state=4;

+                                        else

+                                            state=0;

+                                        break;

+                                }

+                            }

+

+                            read=input.read(buffer);

+                        }

+                        catch (IOException e)

+                        {

+                            // e.printStackTrace();

+                        }

+                        finally

+                        {

+                            try

+                            {

+                                x.exchange(read);

+                            }

+                            catch (InterruptedException e)

+                            {

+                                e.printStackTrace();

+                            }

+                        }

+                    }

+                }.start();

+            }

+

+            for (Exchanger<Integer> x : totals)

+            {

+                Integer read = x.exchange(-1,10,TimeUnit.SECONDS);

+                Assert.assertEquals(-1,read.intValue());

+            }

+

+            // We could read everything, good.

+            for (Socket socket : sockets)

+                socket.close();

+            

+            _server.stop();

+        }

+        finally

+        {

+            ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);

+        }

+    }

+}

diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncManipFilter.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncManipFilter.java
deleted file mode 100644
index 54a7957..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncManipFilter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * Filter that merely manipulates the AsyncContext.
- * <p>
- * The pattern of manipulation is modeled after how DOSFilter behaves. The purpose of this filter is to test arbitrary filter chains that could see unintended
- * side-effects of async context manipulation.
- */
-public class AsyncManipFilter implements Filter, AsyncListener
-{
-    private static final Logger LOG = Log.getLogger(AsyncManipFilter.class);
-    private static final String MANIP_KEY = AsyncManipFilter.class.getName();
-
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-    }
-
-    @Override
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
-    {
-        LOG.debug("doFilter() - {}", chain);
-        AsyncContext ctx = (AsyncContext)request.getAttribute(MANIP_KEY);
-        if (ctx == null)
-        {
-            LOG.debug("Initial pass through: {}", chain);
-            ctx = request.startAsync();
-            ctx.addListener(this);
-            ctx.setTimeout(1000);
-            LOG.debug("AsyncContext: {}", ctx);
-            request.setAttribute(MANIP_KEY,ctx);
-            return;
-        }
-        else
-        {
-            LOG.debug("Second pass through: {}", chain);
-            chain.doFilter(request,response);
-        }
-    }
-
-    @Override
-    public void destroy()
-    {
-    }
-
-    @Override
-    public void onComplete(AsyncEvent event) throws IOException
-    {
-        LOG.debug("onComplete() {}",event);
-    }
-
-    @Override
-    public void onTimeout(AsyncEvent event) throws IOException
-    {
-        LOG.debug("onTimeout() {}",event.getAsyncContext());
-        event.getAsyncContext().dispatch();
-    }
-
-    @Override
-    public void onError(AsyncEvent event) throws IOException
-    {
-        LOG.debug("onError()",event.getThrowable());
-    }
-
-    @Override
-    public void onStartAsync(AsyncEvent event) throws IOException
-    {
-        LOG.debug("onTimeout() {}",event);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncScheduledDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncScheduledDispatchWrite.java
deleted file mode 100644
index da92340..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncScheduledDispatchWrite.java
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.AsyncContext;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-@SuppressWarnings("serial")
-public abstract class AsyncScheduledDispatchWrite extends TestDirContentServlet
-{
-    public static class Default extends AsyncScheduledDispatchWrite
-    {
-        public Default()
-        {
-            super(true);
-        }
-    }
-    
-    public static class Passed extends AsyncScheduledDispatchWrite
-    {
-        public Passed()
-        {
-            super(false);
-        }
-    }
-
-    private static class DispatchBack implements Runnable
-    {
-        private final AsyncContext ctx;
-
-        public DispatchBack(AsyncContext ctx)
-        {
-            this.ctx = ctx;
-        }
-
-        @Override
-        public void run()
-        {
-            ctx.dispatch();
-        }
-    }
-
-    private final boolean originalReqResp;
-    private ScheduledExecutorService scheduler;
-
-    public AsyncScheduledDispatchWrite(boolean originalReqResp)
-    {
-        this.originalReqResp = originalReqResp;
-    }
-
-    public void init(ServletConfig config) throws ServletException
-    {
-        super.init(config);
-        scheduler = Executors.newScheduledThreadPool(3);
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        Boolean suspended = (Boolean)request.getAttribute("SUSPENDED");
-        if (suspended == null || !suspended)
-        {
-            request.setAttribute("SUSPENDED",Boolean.TRUE);
-            AsyncContext ctx;
-            if (originalReqResp)
-            {
-                // Use Original Request & Response
-                ctx = request.startAsync();
-            }
-            else
-            {
-                // Pass Request & Response
-                ctx = request.startAsync(request,response);
-            }
-            ctx.setTimeout(0);
-            scheduler.schedule(new DispatchBack(ctx),500,TimeUnit.MILLISECONDS);
-        }
-        else
-        {
-            String fileName = request.getServletPath();
-            byte[] dataBytes = loadContentFileBytes(fileName);
-
-            response.setContentLength(dataBytes.length);
-
-            ServletOutputStream out = response.getOutputStream();
-
-            if (fileName.endsWith("txt"))
-                response.setContentType("text/plain");
-            else if (fileName.endsWith("mp3"))
-                response.setContentType("audio/mpeg");
-            response.setHeader("ETag","W/etag-" + fileName);
-
-            out.write(dataBytes);
-        }
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutCompleteWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutCompleteWrite.java
deleted file mode 100644
index fde8283..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutCompleteWrite.java
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Respond with requested content, but via AsyncContext manipulation.
- * <p>
- * 
- * <pre>
- *   1) startAsync
- *   2) AsyncContext.setTimeout()
- *   3) onTimeout()
- *   4) send-response
- *   5) AsyncContext.complete()
- * </pre>
- */
-@SuppressWarnings("serial")
-public abstract class AsyncTimeoutCompleteWrite extends TestDirContentServlet implements AsyncListener
-{
-    public static class Default extends AsyncTimeoutCompleteWrite
-    {
-        public Default()
-        {
-            super(true);
-        }
-    }
-    
-    public static class Passed extends AsyncTimeoutCompleteWrite
-    {
-        public Passed()
-        {
-            super(false);
-        }
-    }
-
-    private final boolean originalReqResp;
-
-    public AsyncTimeoutCompleteWrite(boolean originalReqResp)
-    {
-        this.originalReqResp = originalReqResp;
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        assertThat("'filename' request attribute shouldn't be declared",request.getAttribute("filename"),nullValue());
-
-        AsyncContext ctx = (AsyncContext)request.getAttribute(this.getClass().getName());
-        assertThat("AsyncContext (shouldn't be in request attribute)", ctx, nullValue());
-        
-        if (originalReqResp)
-        {
-            // Use Original Request & Response
-            ctx = request.startAsync();
-        }
-        else
-        {
-            // Pass Request & Response
-            ctx = request.startAsync(request,response);
-        }
-        String fileName = request.getServletPath();
-        request.setAttribute("filename",fileName);
-        ctx.addListener(this);
-        ctx.setTimeout(20);
-        
-        // Setup indication of a redispatch (which this scenario shouldn't do)
-        request.setAttribute(this.getClass().getName(),ctx);
-    }
-
-    @Override
-    public void onComplete(AsyncEvent event) throws IOException
-    {
-    }
-
-    @Override
-    public void onTimeout(AsyncEvent event) throws IOException
-    {
-        HttpServletRequest request = (HttpServletRequest)event.getSuppliedRequest();
-        HttpServletResponse response = (HttpServletResponse)event.getSuppliedResponse();
-
-        String fileName = (String)request.getAttribute("filename");
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        response.setContentLength(dataBytes.length);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-" + fileName);
-
-        out.write(dataBytes);
-
-        event.getAsyncContext().complete();
-    }
-
-    @Override
-    public void onError(AsyncEvent event) throws IOException
-    {
-    }
-
-    @Override
-    public void onStartAsync(AsyncEvent event) throws IOException
-    {
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutDispatchWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutDispatchWrite.java
deleted file mode 100644
index 463d1bb..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/AsyncTimeoutDispatchWrite.java
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-@SuppressWarnings("serial")
-public class AsyncTimeoutDispatchWrite extends TestDirContentServlet implements AsyncListener
-{
-    public static class Default extends AsyncTimeoutDispatchWrite
-    {
-        public Default()
-        {
-            super(true);
-        }
-    }
-    
-    public static class Passed extends AsyncTimeoutDispatchWrite
-    {
-        public Passed()
-        {
-            super(false);
-        }
-    }
-
-    private final boolean originalReqResp;
-
-    public AsyncTimeoutDispatchWrite(boolean originalReqResp)
-    {
-        this.originalReqResp = originalReqResp;
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        AsyncContext ctx = (AsyncContext)request.getAttribute(AsyncContext.class.getName());
-        if (ctx == null)
-        {
-            // First pass through
-            if (originalReqResp)
-            {
-                // Use Original Request & Response
-                ctx = request.startAsync();
-            }
-            else
-            {
-                // Pass Request & Response
-                ctx = request.startAsync(request,response);
-            }
-            ctx.addListener(this);
-            ctx.setTimeout(200);
-            request.setAttribute(AsyncContext.class.getName(),ctx);
-        }
-        else
-        {
-            // second pass through, as result of timeout -> dispatch
-            String fileName = request.getServletPath();
-            byte[] dataBytes = loadContentFileBytes(fileName);
-
-            response.setContentLength(dataBytes.length);
-
-            ServletOutputStream out = response.getOutputStream();
-
-            if (fileName.endsWith("txt"))
-                response.setContentType("text/plain");
-            else if (fileName.endsWith("mp3"))
-                response.setContentType("audio/mpeg");
-            response.setHeader("ETag","W/etag-" + fileName);
-
-            out.write(dataBytes);
-            // no need to call AsyncContext.complete() from here
-            // in fact, it will cause an IllegalStateException if we do
-            // ctx.complete();
-        }
-    }
-
-    @Override
-    public void onComplete(AsyncEvent event) throws IOException
-    {
-    }
-
-    @Override
-    public void onTimeout(AsyncEvent event) throws IOException
-    {
-        event.getAsyncContext().dispatch();
-    }
-
-    @Override
-    public void onError(AsyncEvent event) throws IOException
-    {
-    }
-
-    @Override
-    public void onStartAsync(AsyncEvent event) throws IOException
-    {
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipHandlerTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipHandlerTest.java
deleted file mode 100644
index a652f4a..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipHandlerTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.zip.GZIPInputStream;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.LocalConnector;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlets.gzip.GzipHandler;
-import org.eclipse.jetty.util.IO;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class GzipHandlerTest
-{
-    private static String __content =
-        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
-        "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
-        "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "+
-        "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "+
-        "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "+
-        "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "+
-        "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "+
-        "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "+
-        "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "+
-        "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "+
-        "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
-        "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
-
-    private static String __icontent = "BEFORE"+__content+"AFTER";
-            
-    private Server _server;
-    private LocalConnector _connector;
-
-    @Before
-    public void init() throws Exception
-    {
-        _server = new Server();
-        _connector = new LocalConnector(_server);
-        _server.addConnector(_connector);
-
-        GzipHandler gzipHandler = new GzipHandler();
-
-        ServletContextHandler context = new ServletContextHandler(gzipHandler,"/ctx");
-        ServletHandler servlets = context.getServletHandler();
-        
-        _server.setHandler(gzipHandler);
-        gzipHandler.setHandler(context);
-        context.setHandler(servlets);
-        servlets.addServletWithMapping(TestServlet.class,"/content");
-        servlets.addServletWithMapping(ForwardServlet.class,"/forward");
-        servlets.addServletWithMapping(IncludeServlet.class,"/include");
-        
-        _server.start();
-    }
-    
-    public static class TestServlet extends HttpServlet
-    {
-
-        @Override
-        protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
-        {
-            PrintWriter writer = response.getWriter();
-            writer.write(__content);
-        }
-    }
-
-    public static class ForwardServlet extends HttpServlet
-    {
-        @Override
-        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-        {
-            getServletContext().getRequestDispatcher("/content").forward(request,response);
-        }
-    }
-
-    public static class IncludeServlet extends HttpServlet
-    {
-        @Override
-        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-        {
-            response.getWriter().write("BEFORE");
-            getServletContext().getRequestDispatcher("/content").include(request,response);
-            response.getWriter().write("AFTER");
-        }
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        _server.stop();
-        _server.join();
-    }
-
-    @Test
-    public void testGzipHandler() throws Exception
-    {
-        // generated and parsed test
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod("GET");
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("accept-encoding","gzip");
-        request.setURI("/ctx/content");
-
-        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
-
-        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
-        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
-        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
-        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
-        IO.copy(testIn,testOut);
-
-        assertEquals(__content, testOut.toString("UTF8"));
-
-    }
-    
-    @Test
-    public void testForwardGzipHandler() throws Exception
-    {
-        // generated and parsed test
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod("GET");
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("accept-encoding","gzip");
-        request.setURI("/ctx/forward");
-
-        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
-
-        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
-        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
-        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
-        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
-        IO.copy(testIn,testOut);
-
-        assertEquals(__content, testOut.toString("UTF8"));
-    }
-    
-    @Test
-    public void testIncludeGzipHandler() throws Exception
-    {
-        // generated and parsed test
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod("GET");
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("accept-encoding","gzip");
-        request.setURI("/ctx/include");
-
-        response = HttpTester.parseResponse(_connector.getResponses(request.generate()));
-        
-        assertTrue(response.get("Content-Encoding").equalsIgnoreCase("gzip"));
-        assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-
-        InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
-        ByteArrayOutputStream testOut = new ByteArrayOutputStream();
-        IO.copy(testIn,testOut);
-
-        assertEquals(__icontent, testOut.toString("UTF8"));
-    }
-    
-    @Test
-    public void testAddGetPaths()
-    {
-        GzipHandler gzip = new GzipHandler();
-        gzip.addIncludedPaths("/foo");
-        gzip.addIncludedPaths("^/bar.*$");
-        
-        String[] includedPaths = gzip.getIncludedPaths();
-        assertThat("Included Paths.size", includedPaths.length, is(2));
-        assertThat("Included Paths", Arrays.asList(includedPaths), contains("/foo","^/bar.*$"));
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
deleted file mode 100644
index 944b611..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java
+++ /dev/null
@@ -1,662 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.Servlet;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.DateGenerator;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpTester;
-import org.eclipse.jetty.http.HttpTester.Response;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.servlet.ServletTester;
-import org.eclipse.jetty.servlets.GzipFilter;
-import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.hamcrest.Matchers;
-import org.junit.Assert;
-
-public class GzipTester
-{
-    private static final Logger LOG = Log.getLogger(GzipTester.class);
-
-    public static class ContentMetadata
-    {
-        public final long size;
-        public final String sha1;
-
-        public ContentMetadata(long size, String sha1checksum)
-        {
-            this.size = size;
-            this.sha1 = sha1checksum;
-        }
-    }
-
-    private Class<? extends Filter> gzipFilterClass = null;
-    private String encoding = "ISO8859_1";
-    private String userAgent = null;
-    private final ServletTester tester = new ServletTester();;
-    private TestingDir testdir;
-    private String accept;
-    private String compressionType;
-
-    public GzipTester(TestingDir testingdir, String compressionType, String accept)
-    {
-        this.testdir = testingdir;
-        this.compressionType = compressionType;
-        this.accept = accept;
-    }
-
-    public GzipTester(TestingDir testingdir, String compressionType)
-    {
-        this.testdir = testingdir;
-        this.compressionType = compressionType;
-        this.accept = compressionType;
-    }
-
-    public int getOutputBufferSize()
-    {
-        return tester.getConnector().getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().getOutputBufferSize();
-    }
-    
-    public ContentMetadata getResponseMetadata(Response response) throws Exception
-    {
-        long size = response.getContentBytes().length;
-
-        String contentEncoding = response.get("Content-Encoding");
-
-        ByteArrayInputStream bais = null;
-        InputStream in = null;
-        DigestOutputStream digester = null;
-        ByteArrayOutputStream uncompressedStream = null;
-        try
-        {
-            MessageDigest digest = MessageDigest.getInstance("SHA1");
-            bais = new ByteArrayInputStream(response.getContentBytes());
-
-            if (contentEncoding == null)
-            {
-                LOG.debug("No response content-encoding");
-                in = new PassThruInputStream(bais);
-            }
-            else if (contentEncoding.contains(GzipFilter.GZIP))
-            {
-                in = new GZIPInputStream(bais);
-            }
-            else if (contentEncoding.contains(GzipFilter.DEFLATE))
-            {
-                in = new InflaterInputStream(bais,new Inflater(true));
-            }
-            else
-            {
-                assertThat("Unexpected response content-encoding", contentEncoding, isEmptyOrNullString());
-            }
-            
-            uncompressedStream = new ByteArrayOutputStream((int)size); 
-
-            digester = new DigestOutputStream(uncompressedStream,digest);
-            IO.copy(in,digester);
-            
-            byte output[] = uncompressedStream.toByteArray();
-            String actualSha1Sum = Hex.asHex(digest.digest());
-            return new ContentMetadata(output.length,actualSha1Sum);
-        }
-        finally
-        {
-            IO.close(digester);
-            IO.close(in);
-            IO.close(bais);
-            IO.close(uncompressedStream);
-        }
-    }
-
-    public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename) throws Exception
-    {
-        return assertIsResponseGzipCompressed(method,filename,filename,-1);
-    }
-
-    public HttpTester.Response assertIsResponseGzipCompressed(String method, String filename, long ifmodifiedsince) throws Exception
-    {
-        return assertIsResponseGzipCompressed(method,filename,filename,ifmodifiedsince);
-    }
-
-    public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename) throws Exception
-    {
-        return assertIsResponseGzipCompressed(method,requestedFilename,serverFilename,-1);
-    }
-
-    public HttpTester.Response assertNonStaticContentIsResponseGzipCompressed(String method, String path, String expected) throws Exception
-    {
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod(method);
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("Accept-Encoding",accept);
-
-        if (this.userAgent != null)
-            request.setHeader("User-Agent",this.userAgent);
-        request.setURI("/context/" + path);
-
-        // Issue the request
-        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
-
-        int qindex = compressionType.indexOf(";");
-        if (qindex < 0)
-            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType));
-        else
-            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
-
-        ByteArrayInputStream bais = null;
-        InputStream in = null;
-        ByteArrayOutputStream out = null;
-        String actual = null;
-
-        try
-        {
-            bais = new ByteArrayInputStream(response.getContentBytes());
-            if (compressionType.startsWith(GzipFilter.GZIP))
-            {
-                in = new GZIPInputStream(bais);
-            }
-            else if (compressionType.startsWith(GzipFilter.DEFLATE))
-            {
-                in = new InflaterInputStream(bais,new Inflater(true));
-            }
-            out = new ByteArrayOutputStream();
-            IO.copy(in,out);
-
-            actual = out.toString(encoding);
-            assertThat("Uncompressed contents",actual,equalTo(expected));
-        }
-        finally
-        {
-            IO.close(out);
-            IO.close(in);
-            IO.close(bais);
-        }
-
-        return response;
-    }
-
-    public HttpTester.Response assertIsResponseGzipCompressed(String method, String requestedFilename, String serverFilename, long ifmodifiedsince)
-            throws Exception
-    {
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod(method);
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("Accept-Encoding",compressionType);
-        if (ifmodifiedsince > 0)
-            request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(),DateGenerator.formatDate(ifmodifiedsince));
-        if (this.userAgent != null)
-            request.setHeader("User-Agent",this.userAgent);
-        request.setURI("/context/" + requestedFilename);
-
-        // Issue the request
-        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
-
-        // Assert the response headers
-        // Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
-
-        // Response headers should have either a Transfer-Encoding indicating chunked OR a Content-Length
-        /*
-         * TODO need to check for the 3rd option of EOF content. To do this properly you might need to look at both HTTP/1.1 and HTTP/1.0 requests String
-         * contentLength = response.get("Content-Length"); String transferEncoding = response.get("Transfer-Encoding");
-         * 
-         * boolean chunked = (transferEncoding != null) && (transferEncoding.indexOf("chunk") >= 0); if(!chunked) {
-         * Assert.assertThat("Response.header[Content-Length]",contentLength,notNullValue()); } else {
-         * Assert.assertThat("Response.header[Transfer-Encoding]",transferEncoding,notNullValue()); }
-         */
-
-        int qindex = compressionType.indexOf(";");
-        if (qindex < 0)
-            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType));
-        else
-            Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
-
-        Assert.assertThat(response.get("ETag"),Matchers.startsWith("W/"));
-
-        // Assert that the decompressed contents are what we expect.
-        File serverFile = testdir.getFile(serverFilename);
-        String expected = IO.readToString(serverFile);
-        String actual = null;
-
-        ByteArrayInputStream bais = null;
-        InputStream in = null;
-        ByteArrayOutputStream out = null;
-        try
-        {
-            bais = new ByteArrayInputStream(response.getContentBytes());
-            if (compressionType.startsWith(GzipFilter.GZIP))
-            {
-                in = new GZIPInputStream(bais);
-            }
-            else if (compressionType.startsWith(GzipFilter.DEFLATE))
-            {
-                in = new InflaterInputStream(bais,new Inflater(true));
-            }
-            out = new ByteArrayOutputStream();
-            IO.copy(in,out);
-
-            actual = out.toString(encoding);
-            assertThat("Uncompressed contents",actual,equalTo(expected));
-        }
-        finally
-        {
-            IO.close(out);
-            IO.close(in);
-            IO.close(bais);
-        }
-
-        return response;
-    }
-
-    public HttpTester.Response assertIsResponseNotModified(String method, String requestedFilename, long ifmodifiedsince) throws Exception
-    {
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod(method);
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("Accept-Encoding",compressionType);
-        if (ifmodifiedsince > 0)
-            request.setHeader(HttpHeader.IF_MODIFIED_SINCE.asString(),DateGenerator.formatDate(ifmodifiedsince));
-        if (this.userAgent != null)
-            request.setHeader("User-Agent",this.userAgent);
-        request.setURI("/context/" + requestedFilename);
-
-        // Issue the request
-        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
-
-        Assert.assertThat(response.getStatus(),Matchers.equalTo(304));
-        Assert.assertThat(response.get("ETag"),Matchers.startsWith("W/"));
-
-        return response;
-    }
-
-    /**
-     * Makes sure that the response contains an unfiltered file contents.
-     * <p>
-     * This is used to test exclusions and passthroughs in the GzipFilter.
-     * <p>
-     * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter.
-     *
-     * @param requestedFilename
-     *            the filename used to on the GET request,.
-     * @param testResourceSha1Sum
-     *            the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended.
-     * @param expectedContentType
-     */
-    public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType) throws Exception
-    {
-        assertIsResponseNotGzipFiltered(requestedFilename,testResourceSha1Sum,expectedContentType,null);
-    }
-
-    /**
-     * Makes sure that the response contains an unfiltered file contents.
-     * <p>
-     * This is used to test exclusions and passthroughs in the GzipFilter.
-     * <p>
-     * An example is to test that it is possible to configure GzipFilter to not recompress content that shouldn't be compressed by the GzipFilter.
-     *
-     * @param requestedFilename
-     *            the filename used to on the GET request,.
-     * @param testResourceSha1Sum
-     *            the sha1sum file that contains the SHA1SUM checksum that will be used to verify that the response contents are what is intended.
-     * @param expectedContentType
-     * @param expectedContentEncoding
-     *            can be non-null in some circumstances, eg when dealing with pre-gzipped .svgz files
-     */
-    public void assertIsResponseNotGzipFiltered(String requestedFilename, String testResourceSha1Sum, String expectedContentType, String expectedContentEncoding)
-            throws Exception
-    {
-        HttpTester.Request request = HttpTester.newRequest();
-        HttpTester.Response response;
-
-        request.setMethod("GET");
-        request.setVersion("HTTP/1.0");
-        request.setHeader("Host","tester");
-        request.setHeader("Accept-Encoding",compressionType);
-        if (this.userAgent != null)
-            request.setHeader("User-Agent",this.userAgent);
-        request.setURI("/context/" + requestedFilename);
-
-        // Issue the request
-        response = HttpTester.parseResponse(tester.getResponses(request.generate()));
-
-        dumpHeaders(requestedFilename + " / Response Headers",response);
-
-        // Assert the response headers
-        String prefix = requestedFilename + " / Response";
-        Assert.assertThat(prefix + ".status",response.getStatus(),is(HttpServletResponse.SC_OK));
-        Assert.assertThat(prefix + ".header[Content-Length]",response.get("Content-Length"),notNullValue());
-        Assert.assertThat(prefix + ".header[Content-Encoding] (should not be recompressed by GzipFilter)",response.get("Content-Encoding"),
-                expectedContentEncoding == null?nullValue():notNullValue());
-        if (expectedContentEncoding != null)
-            Assert.assertThat(prefix + ".header[Content-Encoding]",response.get("Content-Encoding"),is(expectedContentEncoding));
-        Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.get("Content-Type"),notNullValue());
-        Assert.assertThat(prefix + ".header[Content-Type]",response.get("Content-Type"),is(expectedContentType));
-
-        Assert.assertThat(response.get("ETAG"),Matchers.startsWith("W/"));
-
-        ByteArrayInputStream bais = null;
-        DigestOutputStream digester = null;
-        try
-        {
-            MessageDigest digest = MessageDigest.getInstance("SHA1");
-            bais = new ByteArrayInputStream(response.getContentBytes());
-            digester = new DigestOutputStream(new NoOpOutputStream(),digest);
-            IO.copy(bais,digester);
-
-            String actualSha1Sum = Hex.asHex(digest.digest());
-            String expectedSha1Sum = loadExpectedSha1Sum(testResourceSha1Sum);
-            Assert.assertEquals(requestedFilename + " / SHA1Sum of content",expectedSha1Sum,actualSha1Sum);
-        }
-        finally
-        {
-            IO.close(digester);
-            IO.close(bais);
-        }
-    }
-
-    private void dumpHeaders(String prefix, HttpTester.Message message)
-    {
-        LOG.debug("dumpHeaders: {}",prefix);
-        Enumeration<String> names = message.getFieldNames();
-        while (names.hasMoreElements())
-        {
-            String name = names.nextElement();
-            String value = message.get(name);
-            LOG.debug("dumpHeaders:   {} = {}",name,value);
-        }
-    }
-
-    private String loadExpectedSha1Sum(String testResourceSha1Sum) throws IOException
-    {
-        File sha1File = MavenTestingUtils.getTestResourceFile(testResourceSha1Sum);
-        String contents = IO.readToString(sha1File);
-        Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
-        Matcher mat = pat.matcher(contents);
-        Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
-        return mat.group();
-    }
-
-    public HttpTester.Response executeRequest(String method, String path, int idleFor, TimeUnit idleUnit) throws Exception
-    {
-        HttpTester.Request request = HttpTester.newRequest();
-
-        request.setMethod(method);
-        request.setVersion("HTTP/1.1");
-        request.setHeader("Host","tester");
-        request.setHeader("Accept-Encoding",accept);
-        request.setHeader("Connection","close");
-
-        if (this.userAgent != null)
-        {
-            request.setHeader("User-Agent",this.userAgent);
-        }
-        
-        request.setURI(path);
-
-        // Issue the request
-        return HttpTester.parseResponse(tester.getResponses(request.generate(),idleFor,idleUnit));
-    }
-
-    public String readResponse(HttpTester.Response response) throws IOException, UnsupportedEncodingException
-    {
-        String actual = null;
-        InputStream in = null;
-        ByteArrayOutputStream out = null;
-        try
-        {
-            byte[] content = response.getContentBytes();
-            if (content != null)
-                actual = new String(response.getContentBytes(),encoding);
-            else
-                actual = "";
-        }
-        finally
-        {
-            IO.close(out);
-            IO.close(in);
-        }
-        return actual;
-    }
-
-    /**
-     * Generate string content of arbitrary length.
-     *
-     * @param length
-     *            the length of the string to generate.
-     * @return the string content.
-     */
-    public String generateContent(int length)
-    {
-        StringBuilder builder = new StringBuilder();
-        do
-        {
-            builder.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc.\n");
-            builder.append("Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque\n");
-            builder.append("habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n");
-            builder.append("Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam\n");
-            builder.append("at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate\n");
-            builder.append("velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum.\n");
-            builder.append("Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum\n");
-            builder.append("eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa\n");
-            builder.append("sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam\n");
-            builder.append("consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque.\n");
-            builder.append("Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse\n");
-            builder.append("et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.\n");
-        }
-        while (builder.length() < length);
-
-        // Make sure we are exactly at requested length. (truncate the extra)
-        if (builder.length() > length)
-        {
-            builder.setLength(length);
-        }
-
-        return builder.toString();
-    }
-
-    public String getEncoding()
-    {
-        return encoding;
-    }
-
-    /**
-     * Create a file on the server resource path of a specified filename and size.
-     *
-     * @param filename
-     *            the filename to create
-     * @param filesize
-     *            the file size to create (Note: this isn't suitable for creating large multi-megabyte files)
-     */
-    public File prepareServerFile(String filename, int filesize) throws IOException
-    {
-        File dir = testdir.getDir();
-        File testFile = new File(dir,filename);
-        // Make sure we have a uniq filename (to work around windows File.delete bug)
-        int i = 0;
-        while (testFile.exists())
-        {
-            testFile = new File(dir,(i++) + "-" + filename);
-        }
-
-        FileOutputStream fos = null;
-        ByteArrayInputStream in = null;
-        try
-        {
-            fos = new FileOutputStream(testFile,false);
-            in = new ByteArrayInputStream(generateContent(filesize).getBytes(encoding));
-            IO.copy(in,fos);
-            return testFile;
-        }
-        finally
-        {
-            IO.close(in);
-            IO.close(fos);
-        }
-    }
-
-    /**
-     * Copy a src/test/resource file into the server tree for eventual serving.
-     *
-     * @param filename
-     *            the filename to look for in src/test/resources
-     */
-    public void copyTestServerFile(String filename) throws IOException
-    {
-        File srcFile = MavenTestingUtils.getTestResourceFile(filename);
-        File testFile = testdir.getFile(filename);
-
-        IO.copy(srcFile,testFile);
-    }
-
-    /**
-     * Set the servlet that provides content for the GzipFilter in being tested.
-     *
-     * @param servletClass
-     *            the servlet that will provide content.
-     * @return the FilterHolder for configuring the GzipFilter's initParameters with
-     */
-    public FilterHolder setContentServlet(Class<? extends Servlet> servletClass) throws IOException
-    {
-        tester.setContextPath("/context");
-        tester.setResourceBase(testdir.getDir().getCanonicalPath());
-        ServletHolder servletHolder = tester.addServlet(servletClass,"/");
-        servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath());
-        servletHolder.setInitParameter("etags","true");
-
-        if (gzipFilterClass != null)
-        {
-            FilterHolder holder = tester.addFilter(gzipFilterClass,"/*",EnumSet.of(DispatcherType.REQUEST));
-            holder.setInitParameter("vary","Accept-Encoding");
-            return holder;
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    public Class<? extends Filter> getGzipFilterClass()
-    {
-        return gzipFilterClass;
-    }
-    
-    @Deprecated
-    public void setGzipFilterClass(Class<? extends Filter> gzipFilterClass)
-    {
-        this.gzipFilterClass = gzipFilterClass;
-    }
-
-    public void setEncoding(String encoding)
-    {
-        this.encoding = encoding;
-    }
-
-    public void setUserAgent(String ua)
-    {
-        this.userAgent = ua;
-    }
-
-    public void addMimeType(String extension, String mimetype)
-    {
-        this.tester.getContext().getMimeTypes().addMimeMapping(extension,mimetype);
-    }
-
-    /**
-     * Add an arbitrary filter to the test case.
-     * 
-     * @param holder
-     *            the filter to add
-     * @param pathSpec
-     *            the path spec for this filter
-     * @param dispatches
-     *            the set of {@link DispatcherType} to associate with this filter
-     */
-    public void addFilter(FilterHolder holder, String pathSpec, EnumSet<DispatcherType> dispatches) throws IOException
-    {
-        tester.addFilter(holder,pathSpec,dispatches);
-    }
-
-    public void start() throws Exception
-    {
-        Assert.assertThat("No servlet defined yet.  Did you use #setContentServlet()?",tester,notNullValue());
-        
-        if (LOG.isDebugEnabled())
-        {
-            tester.dumpStdErr();
-        }
-        tester.start();
-    }
-
-    public void stop()
-    {
-        // NOTE: Do not cleanup the testdir. Failures can't be diagnosed if you do that.
-        // IO.delete(testdir.getDir()):
-        try
-        {
-            tester.stop();
-        }
-        catch (Exception e)
-        {
-            // Don't toss this out into Junit as this would be the last exception
-            // that junit will report as being the cause of the test failure.
-            // when in reality, the earlier setup issue is the real cause.
-            e.printStackTrace(System.err);
-        }
-    }
-
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/Hex.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/Hex.java
deleted file mode 100644
index 5c9806a..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/Hex.java
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-public final class Hex
-{
-    private static final char[] hexcodes = "0123456789abcdef".toCharArray();
-
-    public static byte[] asByteArray(String id, int size)
-    {
-        if ((id.length() < 0) || (id.length() > (size * 2)))
-        {
-            throw new IllegalArgumentException(String.format("Invalid ID length of <%d> expected range of <0> to <%d>",id.length(),(size * 2)));
-        }
-
-        byte buf[] = new byte[size];
-        byte hex;
-        int len = id.length();
-
-        int idx = (int)Math.floor(((size * 2) - (double)len) / 2);
-        int i = 0;
-        if ((len % 2) != 0)
-        { // deal with odd numbered chars
-            i -= 1;
-        }
-
-        for (; i < len; i++)
-        {
-            hex = 0;
-            if (i >= 0)
-            {
-                hex = (byte)(Character.digit(id.charAt(i),16) << 4);
-            }
-            i++;
-            hex += (byte)(Character.digit(id.charAt(i),16));
-
-            buf[idx] = hex;
-            idx++;
-        }
-
-        return buf;
-    }
-
-    public static String asHex(byte buf[])
-    {
-        int len = buf.length;
-        char out[] = new char[len * 2];
-        for (int i = 0; i < len; i++)
-        {
-            out[i * 2] = hexcodes[(buf[i] & 0xF0) >> 4];
-            out[(i * 2) + 1] = hexcodes[(buf[i] & 0x0F)];
-        }
-        return String.valueOf(out);
-    }
-
-    private Hex()
-    {
-        /* prevent instantiation */
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/NoOpOutputStream.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/NoOpOutputStream.java
deleted file mode 100644
index 0886636..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/NoOpOutputStream.java
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * Stream that does nothing. (Used by SHA1SUM routines)
- */
-public class NoOpOutputStream extends OutputStream
-{
-    @Override
-    public void close() throws IOException
-    {
-        /* noop */
-    }
-    
-    @Override
-    public void flush() throws IOException
-    {
-        /* noop */
-    }
-    
-    @Override
-    public void write(byte[] b) throws IOException
-    {
-        /* noop */
-    }
-    
-    @Override
-    public void write(byte[] b, int off, int len) throws IOException
-    {
-        /* noop */
-    }
-    
-    @Override
-    public void write(int b) throws IOException
-    {
-        /* noop */
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/PassThruInputStream.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/PassThruInputStream.java
deleted file mode 100644
index 6f4bfd9..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/PassThruInputStream.java
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.FilterInputStream;
-import java.io.InputStream;
-
-/**
- * A simple pass-through input stream.
- * <p>
- * Used in some test cases where a proper resource open/close is needed for
- * some potentially optional layers of the input stream.
- */
-public class PassThruInputStream extends FilterInputStream
-{
-    public PassThruInputStream(InputStream in)
-    {
-        super(in);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestDirContentServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestDirContentServlet.java
deleted file mode 100644
index 58fdd4d..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestDirContentServlet.java
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-
-import org.eclipse.jetty.toolchain.test.PathAssert;
-import org.eclipse.jetty.util.IO;
-
-@SuppressWarnings("serial")
-public class TestDirContentServlet extends HttpServlet
-{
-    private File basedir;
-
-    @Override
-    public void init(ServletConfig config) throws ServletException
-    {
-        basedir = new File(config.getInitParameter("baseDir"));
-    }
-
-    public File getTestFile(String filename)
-    {
-        File testfile = new File(basedir,filename);
-        PathAssert.assertFileExists("Content File should exist",testfile);
-        return testfile;
-    }
-
-    protected byte[] loadContentFileBytes(final String fileName) throws IOException
-    {
-        String relPath = fileName;
-        relPath = relPath.replaceFirst("^/context/","");
-        relPath = relPath.replaceFirst("^/","");
-
-        File contentFile =  getTestFile(relPath);
-
-        FileInputStream in = null;
-        ByteArrayOutputStream out = null;
-        try
-        {
-            in = new FileInputStream(contentFile);
-            out = new ByteArrayOutputStream();
-            IO.copy(in,out);
-            return out.toByteArray();
-        }
-        finally
-        {
-            IO.close(out);
-            IO.close(in);
-        }
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java
deleted file mode 100644
index 8ed146c..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestMinGzipSizeServlet.java
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.MimeTypes;
-
-/**
- * Test servlet for testing against unusual minGzip configurable.
- */
-@SuppressWarnings("serial")
-public class TestMinGzipSizeServlet extends TestDirContentServlet
-{
-    private MimeTypes mimeTypes;
-
-    @Override
-    public void init(ServletConfig config) throws ServletException
-    {
-        super.init(config);
-        mimeTypes = new MimeTypes();
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        response.setContentLength(dataBytes.length);
-        response.setHeader("ETag","W/etag-"+fileName);
-        if (fileName.endsWith(".js"))
-        {
-            // intentionally long-form content type to test ";" splitting in code
-            response.setContentType("text/javascript; charset=utf-8");
-        }
-        else
-        {
-            String mime = mimeTypes.getMimeByExtension(fileName);
-            if (mime != null)
-                response.setContentType(mime);
-        }
-        ServletOutputStream out = response.getOutputStream();
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java
deleted file mode 100644
index b94223c..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletBufferTypeLengthWrite.java
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.HttpOutput;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) get stream
- *  2) set content type
- *  2) set content length
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletBufferTypeLengthWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        response.setContentLength(dataBytes.length);
-        
-        ((HttpOutput)out).write(ByteBuffer.wrap(dataBytes).asReadOnlyBuffer());
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java
deleted file mode 100644
index 3100d21..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthStreamTypeWrite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) set content length
- *  2) get stream
- *  3) set content type
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletLengthStreamTypeWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        response.setContentLength(dataBytes.length);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java
deleted file mode 100644
index b80c363..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletLengthTypeStreamWrite.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) set content length
- *  2) set content type
- *  3) get stream
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletLengthTypeStreamWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        response.setContentLength(dataBytes.length);
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java
deleted file mode 100644
index 13d0061..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWrite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) get stream
- *  2) set content length
- *  3) set content type
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletStreamLengthTypeWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        response.setContentLength(dataBytes.length);
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java
deleted file mode 100644
index 1939552..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamLengthTypeWriteWithFlush.java
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- * 
- * Using a real-world pattern of:
- * 
- * <pre>
- *  1) get stream
- *  2) set content length
- *  3) set content type
- *  4) write and flush
- * </pre>
- * 
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletStreamLengthTypeWriteWithFlush extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        // set content-length of uncompressed content (GzipFilter should handle this)
-        response.setContentLength(dataBytes.length);
-        
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        for ( int i = 0 ; i < dataBytes.length ; i++)
-        {
-            out.write(dataBytes[i]);
-            // flush using response object (not the stream itself)
-            response.flushBuffer();
-        }
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java
deleted file mode 100644
index 400c379..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletStreamTypeLengthWrite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) get stream
- *  2) set content type
- *  2) set content length
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletStreamTypeLengthWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        response.setContentLength(dataBytes.length);
-
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java
deleted file mode 100644
index 434254e..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeLengthStreamWrite.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) set content type
- *  2) set content length
- *  3) get stream
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletTypeLengthStreamWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        response.setContentLength(dataBytes.length);
-
-        ServletOutputStream out = response.getOutputStream();
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java
deleted file mode 100644
index b237c0a..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestServletTypeStreamLengthWrite.java
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * A sample servlet to serve static content, using a order of construction that has caused problems for
- * {@link GzipFilter} in the past.
- *
- * Using a real-world pattern of:
- *
- * <pre>
- *  1) set content type
- *  2) get stream
- *  3) set content length
- *  4) write
- * </pre>
- *
- * @see <a href="Eclipse Bug 354014">http://bugs.eclipse.org/354014</a>
- */
-@SuppressWarnings("serial")
-public class TestServletTypeStreamLengthWrite extends TestDirContentServlet
-{
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        if (fileName.endsWith("txt"))
-            response.setContentType("text/plain");
-        else if (fileName.endsWith("mp3"))
-            response.setContentType("audio/mpeg");
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        ServletOutputStream out = response.getOutputStream();
-
-        response.setContentLength(dataBytes.length);
-
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java
deleted file mode 100644
index d5953b7..0000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/TestStaticMimeTypeServlet.java
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.servlets.gzip;
-
-import java.io.IOException;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.MimeTypes;
-
-/**
- * Test servlet for testing against unusual MimeTypes and Content-Types.
- */
-@SuppressWarnings("serial")
-public class TestStaticMimeTypeServlet extends TestDirContentServlet
-{
-    private MimeTypes mimeTypes;
-
-    @Override
-    public void init(ServletConfig config) throws ServletException
-    {
-        super.init(config);
-        mimeTypes = new MimeTypes();
-        // Some real world, yet not terribly common, mime type mappings.
-        mimeTypes.addMimeMapping("bz2","application/bzip2");
-        mimeTypes.addMimeMapping("bmp","image/bmp");
-        mimeTypes.addMimeMapping("tga","application/tga");
-        mimeTypes.addMimeMapping("xcf","image/xcf");
-        mimeTypes.addMimeMapping("jp2","image/jpeg2000");
-
-        // Some of the other gzip mime-types seen in the wild.
-        // NOTE: Using oddball extensions just so that the calling request can specify
-        //       which strange mime type to use.
-        mimeTypes.addMimeMapping("x-gzip","application/x-gzip");
-        mimeTypes.addMimeMapping("x-gunzip","application/x-gunzip");
-        mimeTypes.addMimeMapping("gzipped","application/gzippped");
-        mimeTypes.addMimeMapping("gzip-compressed","application/gzip-compressed");
-        mimeTypes.addMimeMapping("x-compressed","application/x-compressed");
-        mimeTypes.addMimeMapping("x-compress","application/x-compress");
-        mimeTypes.addMimeMapping("gzipdoc","gzip/document");
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
-    {
-        String fileName = request.getServletPath();
-        byte[] dataBytes = loadContentFileBytes(fileName);
-
-        response.setContentLength(dataBytes.length);
-        response.setHeader("ETag","W/etag-"+fileName);
-
-        String mime = mimeTypes.getMimeByExtension(fileName);
-        if (mime == null)
-            response.setContentType("application/octet-stream");
-        else
-            response.setContentType(mime);
-
-        ServletOutputStream out = response.getOutputStream();
-        out.write(dataBytes);
-    }
-}
diff --git a/jetty-servlets/src/test/resources/jetty-logging.properties b/jetty-servlets/src/test/resources/jetty-logging.properties
index 6502639..3ceebb8 100644
--- a/jetty-servlets/src/test/resources/jetty-logging.properties
+++ b/jetty-servlets/src/test/resources/jetty-logging.properties
@@ -2,6 +2,5 @@
 #org.eclipse.jetty.LEVEL=DEBUG
 #org.eclipse.jetty.servlets.LEVEL=DEBUG
 #org.eclipse.jetty.servlet.ServletTester.LEVEL=DEBUG
-#org.eclipse.jetty.servlets.GzipFilter.LEVEL=DEBUG
 #org.eclipse.jetty.servlets.QoSFilter.LEVEL=DEBUG
 #org.eclipse.jetty.servlets.DoSFilter.LEVEL=DEBUG
diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml
deleted file mode 100644
index 7b54664..0000000
--- a/jetty-spdy/pom.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty</groupId>
-        <artifactId>jetty-project</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.eclipse.jetty.spdy</groupId>
-    <artifactId>spdy-parent</artifactId>
-    <packaging>pom</packaging>
-    <name>Jetty :: SPDY :: Parent</name>
-    <url>http://www.eclipse.org/jetty</url>
-
-    <modules>
-        <module>spdy-core</module>
-        <module>spdy-client</module>
-        <module>spdy-server</module>
-        <module>spdy-http-common</module>
-        <module>spdy-http-server</module>
-        <module>spdy-http-client-transport</module>
-        <module>spdy-example-webapp</module>
-        <module>spdy-alpn-tests</module>
-    </modules>
-
-    <profiles>
-      <profile>
-        <id>npn</id>
-        <activation>
-          <jdk>1.7</jdk>
-        </activation>
-        <modules>
-<!--
-          <module>spdy-npn-tests</module>
--->
-        </modules>
-      </profile>
-    </profiles>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-pmd-plugin</artifactId>
-                <configuration>
-                    <skip>true</skip>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.*;version="9.1"</Export-Package>
-                                <Import-Package>org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                                <_nouses>true</_nouses>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-jar-plugin</artifactId>
-              <configuration>
-                  <archive>
-                      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-                  </archive>
-              </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.toolchain</groupId>
-            <artifactId>jetty-test-helper</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-alpn-tests/pom.xml b/jetty-spdy/spdy-alpn-tests/pom.xml
deleted file mode 100644
index 3bca84b..0000000
--- a/jetty-spdy/spdy-alpn-tests/pom.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-alpn-tests</artifactId>
-    <name>Jetty :: SPDY :: ALPN Tests</name>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-dependency-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>copy</id>
-                        <phase>generate-resources</phase>
-                        <goals>
-                            <goal>copy</goal>
-                        </goals>
-                        <configuration>
-                            <artifactItems>
-                                <artifactItem>
-                                    <groupId>org.mortbay.jetty.alpn</groupId>
-                                    <artifactId>alpn-boot</artifactId>
-                                    <version>${alpn.version}</version>
-                                    <type>jar</type>
-                                    <overWrite>false</overWrite>
-                                    <outputDirectory>${project.build.directory}/alpn</outputDirectory>
-                                </artifactItem>
-                            </artifactItems>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.alpn</groupId>
-            <artifactId>alpn-api</artifactId>
-            <version>${alpn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-alpn-server</artifactId>
-            <version>${project.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <classifier>tests</classifier>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-    
-</project>
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java
deleted file mode 100644
index 767cec9..0000000
--- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNNegotiationTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-
-import org.eclipse.jetty.alpn.ALPN;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ALPNNegotiationTest extends AbstractALPNTest
-{
-    @Test
-    public void testClientAdvertisingHTTPServerSpeaksHTTP() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            ALPN.put(client, new ALPN.ClientProvider()
-            {
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public List<String> protocols()
-                {
-                    return Arrays.asList("http/1.1");
-                }
-
-                @Override
-                public void selected(String protocol)
-                {
-                    Assert.assertEquals("http/1.1", protocol);
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-
-    @Test
-    public void testClientAdvertisingMultipleProtocolsServerSpeaksHTTPWhenNegotiated() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            ALPN.put(client, new ALPN.ClientProvider()
-            {
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public List<String> protocols()
-                {
-                    return Arrays.asList("unknown/1.0", "http/1.1");
-                }
-
-                @Override
-                public void selected(String protocol)
-                {
-                    Assert.assertEquals("http/1.1", protocol);
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-
-    @Test
-    public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            ALPN.put(client, new ALPN.ClientProvider()
-            {
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public List<String> protocols()
-                {
-                    return null;
-                }
-
-                @Override
-                public void selected(String s)
-                {
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java
deleted file mode 100644
index 42e0e19..0000000
--- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/ALPNSynReplyTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.util.Arrays;
-import java.util.List;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.alpn.ALPN;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ALPNSynReplyTest extends AbstractALPNTest
-{
-    @Test
-    public void testGentleCloseDuringHandshake() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
-        sslEngine.setUseClientMode(true);
-        ALPN.put(sslEngine, new ALPN.ClientProvider()
-        {
-            @Override
-            public void unsupported()
-            {
-            }
-
-            @Override
-            public List<String> protocols()
-            {
-                return Arrays.asList("test");
-            }
-
-            @Override
-            public void selected(String protocol)
-            {
-            }
-        });
-        sslEngine.beginHandshake();
-
-        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
-        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-        encrypted.flip();
-
-        try (SocketChannel channel = SocketChannel.open(address))
-        {
-            // Send ClientHello, immediately followed by TLS Close Alert and then by FIN
-            channel.write(encrypted);
-            sslEngine.closeOutbound();
-            encrypted.clear();
-            sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-            encrypted.flip();
-            channel.write(encrypted);
-            channel.shutdownOutput();
-
-            // Read ServerHello from server
-            encrypted.clear();
-            int read = channel.read(encrypted);
-            encrypted.flip();
-            Assert.assertTrue(read > 0);
-            // Cannot decrypt, as the SSLEngine has been already closed
-
-            // Now if we read more, we should either read the TLS Close Alert, or directly -1
-            encrypted.clear();
-            read = channel.read(encrypted);
-            // Sending a TLS Close Alert during handshake results in an exception when
-            // unwrapping that the server react to by closing the connection abruptly.
-            Assert.assertTrue(read < 0);
-        }
-    }
-
-    @Test
-    public void testAbruptCloseDuringHandshake() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
-        sslEngine.setUseClientMode(true);
-        ALPN.put(sslEngine, new ALPN.ClientProvider()
-        {
-            @Override
-            public void unsupported()
-            {
-            }
-
-            @Override
-            public List<String> protocols()
-            {
-                return Arrays.asList("test");
-            }
-
-            @Override
-            public void selected(String s)
-            {
-            }
-        });
-        sslEngine.beginHandshake();
-
-        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
-        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-        encrypted.flip();
-
-        try (SocketChannel channel = SocketChannel.open(address))
-        {
-            // Send ClientHello, immediately followed by FIN (no TLS Close Alert)
-            channel.write(encrypted);
-            channel.shutdownOutput();
-
-            // Read ServerHello from server
-            encrypted.clear();
-            int read = channel.read(encrypted);
-            encrypted.flip();
-            Assert.assertTrue(read > 0);
-            ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
-            sslEngine.unwrap(encrypted, decrypted);
-
-            // Now if we read more, we should either read the TLS Close Alert, or directly -1
-            encrypted.clear();
-            read = channel.read(encrypted);
-            // Since we have close the connection abruptly, the server also does so
-            Assert.assertTrue(read < 0);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java b/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java
deleted file mode 100644
index 53a6c0b..0000000
--- a/jetty-spdy/spdy-alpn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractALPNTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-
-import org.eclipse.jetty.alpn.ALPN;
-import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Rule;
-
-public class AbstractALPNTest
-{
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    protected Server server;
-    protected SPDYServerConnector connector;
-    protected SPDYClient.Factory clientFactory;
-
-    protected InetSocketAddress prepare() throws Exception
-    {
-        server = new Server();
-        connector = new SPDYServerConnector(server, newSslContextFactory(), null, new ALPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"));
-        connector.setPort(0);
-        connector.setIdleTimeout(30000);
-        server.addConnector(connector);
-        server.start();
-
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setName(threadPool.getName() + "-client");
-        clientFactory = new SPDYClient.Factory(threadPool);
-        clientFactory.start();
-
-        ALPN.debug = true;
-
-        return new InetSocketAddress("localhost", connector.getLocalPort());
-    }
-
-    protected SslContextFactory newSslContextFactory()
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-        sslContextFactory.setProtocol("TLSv1");
-        sslContextFactory.setIncludeProtocols("TLSv1");
-        return sslContextFactory;
-    }
-
-    @After
-    public void dispose() throws Exception
-    {
-        clientFactory.stop();
-        server.stop();
-    }
-}
diff --git a/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties
deleted file mode 100644
index ead13ec..0000000
--- a/jetty-spdy/spdy-alpn-tests/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml
deleted file mode 100644
index 7b3bed1..0000000
--- a/jetty-spdy/spdy-client/pom.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-client</artifactId>
-    <name>Jetty :: SPDY :: Client Binding</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.client</bundle-symbolic-name>
-    </properties>
-
-    <url>http://www.eclipse.org/jetty</url>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.client;version="9.1"</Export-Package>
-                                <Import-Package>!org.eclipse.jetty.npn,!org.eclipse.jetty.alpn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-alpn-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.alpn</groupId>
-            <artifactId>alpn-api</artifactId>
-            <version>${alpn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.npn</groupId>
-            <artifactId>npn-api</artifactId>
-            <version>${npn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java
deleted file mode 100644
index 439b32a..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/FlowControlStrategyFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import org.eclipse.jetty.spdy.FlowControlStrategy;
-import org.eclipse.jetty.spdy.SPDYv3FlowControlStrategy;
-import org.eclipse.jetty.spdy.api.SPDY;
-
-public class FlowControlStrategyFactory
-{
-    private FlowControlStrategyFactory()
-    {
-    }
-
-    public static FlowControlStrategy newFlowControlStrategy(short version)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return new FlowControlStrategy.None();
-            case SPDY.V3:
-                return new SPDYv3FlowControlStrategy();
-            default:
-                throw new IllegalStateException();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java
deleted file mode 100644
index 10c2a13..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.NegotiatingClientConnection;
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class NPNClientConnection extends NegotiatingClientConnection implements NextProtoNego.ClientProvider
-{
-    private static final Logger LOG = Log.getLogger(NPNClientConnection.class);
-
-    private final String protocol;
-
-    public NPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map<String, Object> context, String protocol)
-    {
-        super(endPoint, executor, sslEngine, connectionFactory, context);
-        this.protocol = protocol;
-        NextProtoNego.put(sslEngine, this);
-    }
-
-    @Override
-    public boolean supports()
-    {
-        return true;
-    }
-
-    @Override
-    public void unsupported()
-    {
-        NextProtoNego.remove(getSSLEngine());
-        completed();
-    }
-
-    @Override
-    public String selectProtocol(List<String> protocols)
-    {
-        if (protocols.contains(protocol))
-        {
-            NextProtoNego.remove(getSSLEngine());
-            completed();
-            return protocol;
-        }
-        else
-        {
-            LOG.info("Could not negotiate protocol: server {} - client {}", protocols, protocol);
-            close();
-            return null;
-        }
-    }
-
-    @Override
-    public void close()
-    {
-        NextProtoNego.remove(getSSLEngine());
-        super.close();
-    }
-}
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java
deleted file mode 100644
index 2f23057..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
-import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
-
-public class NPNClientConnectionFactory extends NegotiatingClientConnectionFactory
-{
-    private final Executor executor;
-    private final String protocol;
-
-    public NPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol)
-    {
-        super(connectionFactory);
-        this.executor = executor;
-        this.protocol = protocol;
-    }
-
-    @Override
-    public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
-    {
-        return new NPNClientConnection(endPoint, executor, getClientConnectionFactory(),
-                (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol);
-    }
-}
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java
deleted file mode 100644
index c1b8ee5..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java
+++ /dev/null
@@ -1,440 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
-import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.io.SelectorManager;
-import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
-import org.eclipse.jetty.spdy.FlowControlStrategy;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.FuturePromise;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
-import org.eclipse.jetty.util.thread.Scheduler;
-
-/**
- * A {@link SPDYClient} allows applications to connect to one or more SPDY servers,
- * obtaining {@link Session} objects that can be used to send/receive SPDY frames.
- * <p/>
- * {@link SPDYClient} instances are created through a {@link Factory}:
- * <pre>
- * SPDYClient.Factory factory = new SPDYClient.Factory();
- * SPDYClient client = factory.newSPDYClient(SPDY.V3);
- * </pre>
- * and then used to connect to the server:
- * <pre>
- * FuturePromise&lt;Session&gt; promise = new FuturePromise&lt;&gt;();
- * client.connect("server.com", null, promise);
- * Session session = promise.get();
- * </pre>
- */
-public class SPDYClient
-{
-    private final short version;
-    private final Factory factory;
-    private volatile SocketAddress bindAddress;
-    private volatile long idleTimeout = -1;
-    private volatile int initialWindowSize;
-    private volatile boolean dispatchIO;
-    private volatile ClientConnectionFactory connectionFactory;
-
-    protected SPDYClient(short version, Factory factory)
-    {
-        this.version = version;
-        this.factory = factory;
-        setInitialWindowSize(65536);
-        setDispatchIO(true);
-    }
-
-    public short getVersion()
-    {
-        return version;
-    }
-
-    public Factory getFactory()
-    {
-        return factory;
-    }
-
-    /**
-     * Equivalent to:
-     * <pre>
-     * Future&lt;Session&gt; promise = new FuturePromise&lt;&gt;();
-     * connect(address, listener, promise);
-     * </pre>
-     *
-     * @param address  the address to connect to
-     * @param listener the session listener that will be notified of session events
-     * @return a {@link Session} when connected
-     */
-    public Session connect(SocketAddress address, SessionFrameListener listener) throws ExecutionException, InterruptedException
-    {
-        FuturePromise<Session> promise = new FuturePromise<>();
-        connect(address, listener, promise);
-        return promise.get();
-    }
-
-    /**
-     * Equivalent to:
-     * <pre>
-     * connect(address, listener, promise, null);
-     * </pre>
-     *
-     * @param address  the address to connect to
-     * @param listener the session listener that will be notified of session events
-     * @param promise  the promise notified of connection success/failure
-     */
-    public void connect(SocketAddress address, SessionFrameListener listener, Promise<Session> promise)
-    {
-        connect(address, listener, promise, new HashMap<String, Object>());
-    }
-
-    /**
-     * Connects to the given {@code address}, binding the given {@code listener} to session events,
-     * and notified the given {@code promise} of the connect result.
-     * <p/>
-     * If the connect operation is successful, the {@code promise} will be invoked with the {@link Session}
-     * object that applications can use to perform SPDY requests.
-     *
-     * @param address  the address to connect to
-     * @param listener the session listener that will be notified of session events
-     * @param promise  the promise notified of connection success/failure
-     * @param context  a context object passed to the {@link #getClientConnectionFactory() ConnectionFactory}
-     *                 for the creation of the connection
-     */
-    public void connect(final SocketAddress address, final SessionFrameListener listener, final Promise<Session> promise, Map<String, Object> context)
-    {
-        if (!factory.isStarted())
-            throw new IllegalStateException(Factory.class.getSimpleName() + " is not started");
-
-        try
-        {
-            SocketChannel channel = SocketChannel.open();
-            if (bindAddress != null)
-                channel.bind(bindAddress);
-            configure(channel);
-            channel.configureBlocking(false);
-
-            context.put(SslClientConnectionFactory.SSL_PEER_HOST_CONTEXT_KEY, ((InetSocketAddress)address).getHostString());
-            context.put(SslClientConnectionFactory.SSL_PEER_PORT_CONTEXT_KEY, ((InetSocketAddress)address).getPort());
-            context.put(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY, this);
-            context.put(SPDYClientConnectionFactory.SPDY_SESSION_LISTENER_CONTEXT_KEY, listener);
-            context.put(SPDYClientConnectionFactory.SPDY_SESSION_PROMISE_CONTEXT_KEY, promise);
-
-            if (channel.connect(address))
-                factory.selector.accept(channel, context);
-            else
-                factory.selector.connect(channel, context);
-        }
-        catch (IOException x)
-        {
-            promise.failed(x);
-        }
-    }
-
-    protected void configure(SocketChannel channel) throws IOException
-    {
-        channel.socket().setTcpNoDelay(true);
-    }
-
-    /**
-     * @return the address to bind the socket channel to
-     * @see #setBindAddress(SocketAddress)
-     */
-    public SocketAddress getBindAddress()
-    {
-        return bindAddress;
-    }
-
-    /**
-     * @param bindAddress the address to bind the socket channel to
-     * @see #getBindAddress()
-     */
-    public void setBindAddress(SocketAddress bindAddress)
-    {
-        this.bindAddress = bindAddress;
-    }
-
-    public long getIdleTimeout()
-    {
-        return idleTimeout;
-    }
-
-    public void setIdleTimeout(long idleTimeout)
-    {
-        this.idleTimeout = idleTimeout;
-    }
-
-    public int getInitialWindowSize()
-    {
-        return initialWindowSize;
-    }
-
-    public void setInitialWindowSize(int initialWindowSize)
-    {
-        this.initialWindowSize = initialWindowSize;
-    }
-
-    public boolean isDispatchIO()
-    {
-        return dispatchIO;
-    }
-
-    public void setDispatchIO(boolean dispatchIO)
-    {
-        this.dispatchIO = dispatchIO;
-    }
-
-    public ClientConnectionFactory getClientConnectionFactory()
-    {
-        return connectionFactory;
-    }
-
-    public void setClientConnectionFactory(ClientConnectionFactory connectionFactory)
-    {
-        this.connectionFactory = connectionFactory;
-    }
-
-    protected FlowControlStrategy newFlowControlStrategy()
-    {
-        return FlowControlStrategyFactory.newFlowControlStrategy(version);
-    }
-
-    public static class Factory extends ContainerLifeCycle
-    {
-        private final Queue<Session> sessions = new ConcurrentLinkedQueue<>();
-        private final Scheduler scheduler;
-        private final Executor executor;
-        private final ByteBufferPool bufferPool;
-        private final SslContextFactory sslContextFactory;
-        private final SelectorManager selector;
-        private final long idleTimeout;
-        private long connectTimeout;
-
-        public Factory()
-        {
-            this(null, null);
-        }
-
-        public Factory(SslContextFactory sslContextFactory)
-        {
-            this(null, null, sslContextFactory);
-        }
-
-        public Factory(Executor executor)
-        {
-            this(executor, null);
-        }
-
-        public Factory(Executor executor, Scheduler scheduler)
-        {
-            this(executor, scheduler, null);
-        }
-
-        public Factory(Executor executor, Scheduler scheduler, SslContextFactory sslContextFactory)
-        {
-            this(executor, scheduler, sslContextFactory, 30000);
-        }
-
-        public Factory(Executor executor, Scheduler scheduler, SslContextFactory sslContextFactory, long idleTimeout)
-        {
-            this(executor, scheduler, null, sslContextFactory, idleTimeout);
-        }
-
-        public Factory(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, SslContextFactory sslContextFactory, long idleTimeout)
-        {
-            this.idleTimeout = idleTimeout;
-            setConnectTimeout(15000);
-
-            if (executor == null)
-                executor = new QueuedThreadPool();
-            this.executor = executor;
-            addBean(executor);
-
-            if (scheduler == null)
-                scheduler = new ScheduledExecutorScheduler();
-            this.scheduler = scheduler;
-            addBean(scheduler);
-
-            if (bufferPool == null)
-                bufferPool = new MappedByteBufferPool();
-            this.bufferPool = bufferPool;
-            addBean(bufferPool);
-
-            this.sslContextFactory = sslContextFactory;
-            if (sslContextFactory != null)
-                addBean(sslContextFactory);
-
-            selector = new ClientSelectorManager(executor, scheduler);
-            selector.setConnectTimeout(getConnectTimeout());
-            addBean(selector);
-        }
-
-        public ByteBufferPool getByteBufferPool()
-        {
-            return bufferPool;
-        }
-
-        public Scheduler getScheduler()
-        {
-            return scheduler;
-        }
-
-        public Executor getExecutor()
-        {
-            return executor;
-        }
-
-        public SslContextFactory getSslContextFactory()
-        {
-            return sslContextFactory;
-        }
-
-        public long getConnectTimeout()
-        {
-            return connectTimeout;
-        }
-
-        public void setConnectTimeout(long connectTimeout)
-        {
-            this.connectTimeout = connectTimeout;
-        }
-
-        public SPDYClient newSPDYClient(short version)
-        {
-            return newSPDYClient(version, new NPNClientConnectionFactory(getExecutor(), new SPDYClientConnectionFactory(), "spdy/" + version));
-        }
-
-        public SPDYClient newSPDYClient(short version, NegotiatingClientConnectionFactory negotiatingFactory)
-        {
-            SPDYClient client = new SPDYClient(version, this);
-
-            ClientConnectionFactory connectionFactory = negotiatingFactory.getClientConnectionFactory();
-            if (sslContextFactory != null)
-                connectionFactory = new SslClientConnectionFactory(getSslContextFactory(), getByteBufferPool(), getExecutor(), negotiatingFactory);
-
-            client.setClientConnectionFactory(connectionFactory);
-            return client;
-        }
-
-        @Override
-        protected void doStop() throws Exception
-        {
-            closeConnections();
-            super.doStop();
-        }
-
-        boolean sessionOpened(Session session)
-        {
-            // Add sessions only if the factory is not stopping
-            return isRunning() && sessions.offer(session);
-        }
-
-        boolean sessionClosed(Session session)
-        {
-            // Remove sessions only if the factory is not stopping
-            // to avoid concurrent removes during iterations
-            return isRunning() && sessions.remove(session);
-        }
-
-        private void closeConnections()
-        {
-            for (Session session : sessions)
-                session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
-            sessions.clear();
-        }
-
-        public Collection<Session> getSessions()
-        {
-            return Collections.unmodifiableCollection(sessions);
-        }
-
-        @Override
-        protected void dumpThis(Appendable out) throws IOException
-        {
-            super.dumpThis(out);
-            dump(out, "", sessions);
-        }
-
-        private class ClientSelectorManager extends SelectorManager
-        {
-            private ClientSelectorManager(Executor executor, Scheduler scheduler)
-            {
-                super(executor, scheduler);
-            }
-
-            @Override
-            protected EndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
-            {
-                @SuppressWarnings("unchecked")
-                Map<String, Object> context = (Map<String, Object>)key.attachment();
-                SPDYClient client = (SPDYClient)context.get(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY);
-                long clientIdleTimeout = client.getIdleTimeout();
-                if (clientIdleTimeout < 0)
-                    clientIdleTimeout = idleTimeout;
-                return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), clientIdleTimeout);
-            }
-
-            @Override
-            public Connection newConnection(SocketChannel channel, EndPoint endPoint, Object attachment) throws IOException
-            {
-                @SuppressWarnings("unchecked")
-                Map<String, Object> context = (Map<String, Object>)attachment;
-                try
-                {
-                    SPDYClient client = (SPDYClient)context.get(SPDYClientConnectionFactory.SPDY_CLIENT_CONTEXT_KEY);
-                    return client.getClientConnectionFactory().newConnection(endPoint, context);
-                }
-                catch (Throwable x)
-                {
-                    @SuppressWarnings("unchecked")
-                    Promise<Session> promise = (Promise<Session>)context.get(SPDYClientConnectionFactory.SPDY_SESSION_PROMISE_CONTEXT_KEY);
-                    promise.failed(x);
-                    throw x;
-                }
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java
deleted file mode 100644
index dc66632..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClientConnectionFactory.java
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.FlowControlStrategy;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.StandardSession;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient.Factory;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Promise;
-
-public class SPDYClientConnectionFactory implements ClientConnectionFactory
-{
-    public static final String SPDY_CLIENT_CONTEXT_KEY = "spdy.client";
-    public static final String SPDY_SESSION_LISTENER_CONTEXT_KEY = "spdy.session.listener";
-    public static final String SPDY_SESSION_PROMISE_CONTEXT_KEY = "spdy.session.promise";
-
-    @Override
-    public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
-    {
-        SPDYClient client = (SPDYClient)context.get(SPDY_CLIENT_CONTEXT_KEY);
-        SPDYClient.Factory factory = client.getFactory();
-        ByteBufferPool byteBufferPool = factory.getByteBufferPool();
-        CompressionFactory compressionFactory = new StandardCompressionFactory();
-        Parser parser = new Parser(compressionFactory.newDecompressor());
-        Generator generator = new Generator(byteBufferPool, compressionFactory.newCompressor());
-
-        SPDYConnection connection = new ClientSPDYConnection(endPoint, byteBufferPool, parser, factory, client.isDispatchIO());
-
-        FlowControlStrategy flowControlStrategy = client.newFlowControlStrategy();
-
-        SessionFrameListener listener = (SessionFrameListener)context.get(SPDY_SESSION_LISTENER_CONTEXT_KEY);
-        StandardSession session = new StandardSession(client.getVersion(), byteBufferPool,
-                factory.getScheduler(), connection, endPoint, connection, 1, listener, generator, flowControlStrategy);
-
-        session.setWindowSize(client.getInitialWindowSize());
-        parser.addListener(session);
-        connection.setSession(session);
-
-        @SuppressWarnings("unchecked")
-        Promise<Session> promise = (Promise<Session>)context.get(SPDY_SESSION_PROMISE_CONTEXT_KEY);
-        promise.succeeded(session);
-
-        return connection;
-    }
-
-    private class ClientSPDYConnection extends SPDYConnection
-    {
-        private final Factory factory;
-
-        public ClientSPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Factory factory, boolean dispatchIO)
-        {
-            super(endPoint, bufferPool, parser, factory.getExecutor(), dispatchIO);
-            this.factory = factory;
-        }
-
-        @Override
-        public void onOpen()
-        {
-            super.onOpen();
-            factory.sessionOpened(getSession());
-        }
-
-        @Override
-        public void onClose()
-        {
-            super.onClose();
-            factory.sessionClosed(getSession());
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java
deleted file mode 100644
index 3a67198..0000000
--- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYConnection.java
+++ /dev/null
@@ -1,191 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.io.AbstractConnection;
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.RuntimeIOException;
-import org.eclipse.jetty.spdy.Controller;
-import org.eclipse.jetty.spdy.ISession;
-import org.eclipse.jetty.spdy.IdleListener;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class SPDYConnection extends AbstractConnection implements Controller, IdleListener
-{
-    private static final Logger LOG = Log.getLogger(SPDYConnection.class);
-    private final ByteBufferPool bufferPool;
-    private final Parser parser;
-    private final int bufferSize;
-    private volatile ISession session;
-    private volatile boolean idle = false;
-
-    public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, boolean dispatchIO)
-    {
-        this(endPoint, bufferPool, parser, executor, dispatchIO, 8192);
-    }
-
-    public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, boolean dispatchIO, int bufferSize)
-    {
-        // Since SPDY is multiplexed, onFillable() must never block while calling application code. In fact,
-        // the SPDY code always dispatches to a new thread when calling application code,
-        // so here we can safely pass false as last parameter, and avoid to dispatch to onFillable().
-        // The IO operation (read, parse, etc.) will not block and will be fast in almost all cases.
-        // Big uploads to a server, however, might occupy the Selector thread for a long time and
-        // therefore starve other connections, so by default dispatchIO is true.
-        super(endPoint, executor, dispatchIO);
-        this.bufferPool = bufferPool;
-        this.parser = parser;
-        onIdle(true);
-        this.bufferSize = bufferSize;
-    }
-
-    @Override
-    public void onOpen()
-    {
-        super.onOpen();
-        fillInterested();
-    }
-
-    @Override
-    public void onFillable()
-    {
-        ByteBuffer buffer = bufferPool.acquire(bufferSize, false);
-        boolean readMore = read(buffer) == 0;
-        bufferPool.release(buffer);
-        if (readMore)
-            fillInterested();
-    }
-
-    protected int read(ByteBuffer buffer)
-    {
-        EndPoint endPoint = getEndPoint();
-        while (true)
-        {
-            int filled = fill(endPoint, buffer);
-            if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled'
-                LOG.debug("Read {} bytes", filled);
-            if (filled == 0)
-            {
-                return 0;
-            }
-            else if (filled < 0)
-            {
-                shutdown(session);
-                return -1;
-            }
-            else
-            {
-                parser.parse(buffer);
-            }
-        }
-    }
-
-    private int fill(EndPoint endPoint, ByteBuffer buffer)
-    {
-        try
-        {
-            if (endPoint.isInputShutdown())
-                return -1;
-            return endPoint.fill(buffer);
-        }
-        catch (IOException x)
-        {
-            endPoint.close();
-            throw new RuntimeIOException(x);
-        }
-    }
-
-    @Override
-    public void write(final Callback callback, ByteBuffer... buffers)
-    {
-        EndPoint endPoint = getEndPoint();
-        endPoint.write(callback, buffers);
-    }
-
-    @Override
-    public void close()
-    {
-        goAway(session);
-    }
-
-    @Override
-    public void close(boolean onlyOutput)
-    {
-        EndPoint endPoint = getEndPoint();
-        // We need to gently close first, to allow
-        // SSL close alerts to be sent by Jetty
-        if (LOG.isDebugEnabled())
-            LOG.debug("Shutting down output {}", endPoint);
-        endPoint.shutdownOutput();
-        if (!onlyOutput)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Closing {}", endPoint);
-            endPoint.close();
-        }
-    }
-
-    @Override
-    public void onIdle(boolean idle)
-    {
-        this.idle = idle;
-    }
-
-    @Override
-    protected boolean onReadTimeout()
-    {
-        boolean idle = this.idle;
-        if (LOG.isDebugEnabled())
-            LOG.debug("Idle timeout on {}, idle={}", this, idle);
-        if (idle)
-            goAway(session);
-        return false;
-    }
-
-    protected void goAway(ISession session)
-    {
-        if (session != null)
-            session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
-    }
-
-    private void shutdown(ISession session)
-    {
-        if (session != null && !getEndPoint().isOutputShutdown())
-            session.shutdown();
-    }
-
-    protected ISession getSession()
-    {
-        return session;
-    }
-
-    public void setSession(ISession session)
-    {
-        this.session = session;
-    }
-}
diff --git a/jetty-spdy/spdy-core/pom.xml b/jetty-spdy/spdy-core/pom.xml
deleted file mode 100644
index 2cb325d..0000000
--- a/jetty-spdy/spdy-core/pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-core</artifactId>
-    <name>Jetty :: SPDY :: Core</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.core</bundle-symbolic-name>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-util</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-io</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java
deleted file mode 100644
index c97b579..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionDictionary.java
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-
-public class CompressionDictionary
-{
-    private static final byte[] DICTIONARY_V2 = ("" +
-            "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" +
-            "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" +
-            "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" +
-            "-agent10010120020120220320420520630030130230330430530630740040140240340440" +
-            "5406407408409410411412413414415416417500501502503504505accept-rangesageeta" +
-            "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" +
-            "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" +
-            "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" +
-            "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" +
-            "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" +
-            "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" +
-            "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" +
-            ".1statusversionurl" +
-            // Must be NUL terminated
-            "\u0000").getBytes();
-
-    private static final byte[] DICTIONARY_V3 = ("" +
-            "\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004head\u0000\u0000\u0000\u0004post" +
-            "\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006delete\u0000\u0000\u0000\u0005trace" +
-            "\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000\u000Eaccept-charset" +
-            "\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Faccept-language" +
-            "\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000\u0000\u0000\u0005allow" +
-            "\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-control" +
-            "\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000\u0000\u0010content-encoding" +
-            "\u0000\u0000\u0000\u0010content-language\u0000\u0000\u0000\u000Econtent-length" +
-            "\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000\u000Bcontent-md5" +
-            "\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type\u0000\u0000\u0000\u0004date" +
-            "\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expect\u0000\u0000\u0000\u0007expires" +
-            "\u0000\u0000\u0000\u0004from\u0000\u0000\u0000\u0004host\u0000\u0000\u0000\bif-match" +
-            "\u0000\u0000\u0000\u0011if-modified-since\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range" +
-            "\u0000\u0000\u0000\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified" +
-            "\u0000\u0000\u0000\blocation\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma" +
-            "\u0000\u0000\u0000\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization" +
-            "\u0000\u0000\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after" +
-            "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trailer" +
-            "\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000\u0000\u0000\nuser-agent" +
-            "\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via\u0000\u0000\u0000\u0007warning" +
-            "\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000\u0000\u0006method\u0000\u0000\u0000\u0003get" +
-            "\u0000\u0000\u0000\u0006status\u0000\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version" +
-            "\u0000\u0000\u0000\bHTTP/1.1\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public" +
-            "\u0000\u0000\u0000\nset-cookie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin" +
-            "100101201202205206300302303304305306307402405406407408409410411412413414415416417502504505" +
-            "203 Non-Authoritative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized" +
-            "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Unavailable" +
-            "Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Thu, Fri, Sat, Sun, GMT" +
-            "chunked,text/html,image/png,image/jpg,image/gif,application/xml,application/xhtml+xml,text/plain," +
-            "text/javascript,publicprivatemax-age=gzip,deflate,sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.")
-            .getBytes();
-
-    public static byte[] get(short version)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return DICTIONARY_V2;
-            case SPDY.V3:
-                return DICTIONARY_V3;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java
deleted file mode 100644
index 6955bbf..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/CompressionFactory.java
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.util.zip.ZipException;
-
-public interface CompressionFactory
-{
-    public Compressor newCompressor();
-
-    public Decompressor newDecompressor();
-
-    public interface Compressor
-    {
-        public void setInput(byte[] input);
-
-        public void setDictionary(byte[] dictionary);
-
-        public int compress(byte[] output);
-    }
-
-    public interface Decompressor
-    {
-        public void setDictionary(byte[] dictionary);
-
-        public void setInput(byte[] input);
-
-        public int decompress(byte[] output) throws ZipException;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java
deleted file mode 100644
index b636953..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Controller.java
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.util.Callback;
-
-public interface Controller
-{
-    public void write(Callback callback, ByteBuffer... buffers);
-
-    public void close(boolean onlyOutput);
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java
deleted file mode 100644
index d367b5e..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/FlowControlStrategy.java
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-
-// TODO: add methods that tell how much written and whether we're TCP congested ?
-public interface FlowControlStrategy
-{
-    public int getWindowSize(ISession session);
-
-    public void setWindowSize(ISession session, int windowSize);
-
-    public void onNewStream(ISession session, IStream stream);
-
-    public void onWindowUpdate(ISession session, IStream stream, int delta);
-
-    public void updateWindow(ISession session, IStream stream, int delta);
-
-    public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo);
-
-    public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta);
-
-    public static class None implements FlowControlStrategy
-    {
-        private volatile int windowSize;
-
-        public None()
-        {
-            this(65536);
-        }
-
-        public None(int windowSize)
-        {
-            this.windowSize = windowSize;
-        }
-
-        @Override
-        public int getWindowSize(ISession session)
-        {
-            return windowSize;
-        }
-
-        @Override
-        public void setWindowSize(ISession session, int windowSize)
-        {
-            this.windowSize = windowSize;
-        }
-
-        @Override
-        public void onNewStream(ISession session, IStream stream)
-        {
-            stream.updateWindowSize(windowSize);
-        }
-
-        @Override
-        public void onWindowUpdate(ISession session, IStream stream, int delta)
-        {
-        }
-
-        @Override
-        public void updateWindow(ISession session, IStream stream, int delta)
-        {
-        }
-
-        @Override
-        public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo)
-        {
-        }
-
-        @Override
-        public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta)
-        {
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java
deleted file mode 100644
index 9bb7125..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/Flusher.java
+++ /dev/null
@@ -1,266 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.jetty.spdy.StandardSession.FrameBytes;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.util.ArrayQueue;
-import org.eclipse.jetty.util.IteratingCallback;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class Flusher
-{
-    private static final Logger LOG = Log.getLogger(Flusher.class);
-
-    private final IteratingCallback callback = new FlusherCallback();
-    private final Object lock = new Object();
-    private final ArrayQueue<StandardSession.FrameBytes> queue = new ArrayQueue<>(ArrayQueue.DEFAULT_CAPACITY, ArrayQueue.DEFAULT_GROWTH, lock);
-    private final Controller controller;
-    private final int maxGather;
-    private Throwable failure;
-
-    public Flusher(Controller controller)
-    {
-        this(controller, 8);
-    }
-
-    public Flusher(Controller controller, int maxGather)
-    {
-        this.controller = controller;
-        this.maxGather = maxGather;
-    }
-
-    public void removeFrameBytesFromQueue(Stream stream)
-    {
-        synchronized (lock)
-        {
-            for (StandardSession.FrameBytes frameBytes : queue)
-                if (frameBytes.getStream() == stream)
-                    queue.remove(frameBytes);
-        }
-    }
-
-    public Throwable prepend(StandardSession.FrameBytes frameBytes)
-    {
-        synchronized (lock)
-        {
-            Throwable failure = this.failure;
-            if (failure == null)
-            {
-                // Scan from the front of the queue looking to skip higher priority messages
-                int index = 0;
-                int size = queue.size();
-                while (index < size)
-                {
-                    StandardSession.FrameBytes element = queue.getUnsafe(index);
-                    if (element.compareTo(frameBytes) <= 0)
-                        break;
-                    ++index;
-                }
-                queue.add(index, frameBytes);
-            }
-            return failure;
-        }
-    }
-
-    public Throwable append(StandardSession.FrameBytes frameBytes)
-    {
-        synchronized (lock)
-        {
-            Throwable failure = this.failure;
-            if (failure == null)
-            {
-                // Non DataFrameBytes are inserted last
-                queue.add(frameBytes);
-            }
-            return failure;
-        }
-    }
-
-    public Throwable append(StandardSession.DataFrameBytes frameBytes)
-    {
-        synchronized (lock)
-        {
-            Throwable failure = this.failure;
-            if (failure == null)
-            {
-                // DataFrameBytes are inserted by priority
-                int index = queue.size();
-                while (index > 0)
-                {
-                    StandardSession.FrameBytes element = queue.getUnsafe(index - 1);
-                    if (element.compareTo(frameBytes) >= 0)
-                        break;
-                    --index;
-                }
-                queue.add(index, frameBytes);
-            }
-            return failure;
-        }
-    }
-
-    public void flush()
-    {
-        callback.iterate();
-    }
-
-    public int getQueueSize()
-    {
-        synchronized (lock)
-        {
-            return queue.size();
-        }
-    }
-
-    private class FlusherCallback extends IteratingCallback
-    {
-        private final List<StandardSession.FrameBytes> active = new ArrayList<>(maxGather);
-        private final List<StandardSession.FrameBytes> succeeded = new ArrayList<>(maxGather);
-        private final Set<IStream> stalled = new HashSet<>();
-
-        @Override
-        protected Action process() throws Exception
-        {
-            synchronized (lock)
-            {
-                // Scan queue for data to write from first non stalled stream.
-                int index = 0; // The index of the first non-stalled frame.
-                int size = queue.size();
-                while (index < size)
-                {
-                    FrameBytes frameBytes = queue.getUnsafe(index);
-                    IStream stream = frameBytes.getStream();
-
-                    if (stream != null)
-                    {
-                        // Is it a frame belonging to an already stalled stream ?
-                        if (stalled.size() > 0 && stalled.contains(stream))
-                        {
-                            ++index;
-                            continue;
-                        }
-
-                        // Has the stream consumed all its flow control window ?
-                        if (stream.getWindowSize() <= 0)
-                        {
-                            stalled.add(stream);
-                            ++index;
-                            continue;
-                        }
-                    }
-
-                    // We will be possibly writing this frame, so take the frame off the queue.
-                    queue.remove(index);
-                    --size;
-
-                    // Has the stream been reset for this data frame ?
-                    if (stream != null && stream.isReset() && frameBytes instanceof StandardSession.DataFrameBytes)
-                    {
-                        // TODO: notify from within sync block !
-                        frameBytes.failed(new StreamException(frameBytes.getStream().getId(),
-                                StreamStatus.INVALID_STREAM, "Stream: " + frameBytes.getStream() + " is reset!"));
-                        continue;
-                    }
-
-                    active.add(frameBytes);
-                }
-                stalled.clear();
-
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Flushing {} of {} frame(s) in queue", active.size(), queue.size());
-            }
-
-            if (active.isEmpty())
-                return Action.IDLE;
-
-            // Get the bytes to write
-            ByteBuffer[] buffers = new ByteBuffer[active.size()];
-            for (int i = 0; i < buffers.length; i++)
-                buffers[i] = active.get(i).getByteBuffer();
-
-            if (controller != null)
-                controller.write(this, buffers);
-
-            // TODO: optimization
-            // If the callback completely immediately, it means that
-            // the connection is not congested, and therefore we can
-            // write more data without blocking.
-            // Therefore we should check this condition and increase
-            // the write window, which means two things: autotune the
-            // maxGather parameter, and/or autotune the buffer returned
-            // by FrameBytes.getByteBuffer() (see also comment there).
-
-            return Action.SCHEDULED;
-        }
-
-        @Override
-        protected void onCompleteSuccess()
-        {
-            // will never be called as process always returns SCHEDULED or IDLE
-            throw new IllegalStateException();
-        }
-
-        @Override
-        public void succeeded()
-        {
-            synchronized (lock)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Succeeded write of {}, q={}", active, queue.size());
-                succeeded.addAll(active);
-                active.clear();
-            }
-            // Notify outside the synchronized block.
-            for (FrameBytes frame : succeeded)
-                frame.succeeded();
-            succeeded.clear();
-            super.succeeded();
-        }
-
-        @Override
-        public void onCompleteFailure(Throwable x)
-        {
-            List<StandardSession.FrameBytes> failed = new ArrayList<>();
-            synchronized (lock)
-            {
-                failure = x;
-                if (LOG.isDebugEnabled())
-                {
-                    String logMessage = String.format("Failed write of %s, failing all %d frame(s) in queue", this, queue.size());
-                    LOG.debug(logMessage, x);
-                }
-                failed.addAll(active);
-                active.clear();
-                failed.addAll(queue);
-                queue.clear();
-            }
-            // Notify outside the synchronized block.
-            for (StandardSession.FrameBytes frame : failed)
-                frame.failed(x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java
deleted file mode 100644
index 23a5a47..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/ISession.java
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.util.Callback;
-
-public interface ISession extends Session
-{
-    public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback);
-
-    public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback);
-
-    /**
-     * <p>Gracefully shuts down this session.</p>
-     * <p>A special item is queued that will close the connection when it will be dequeued.</p>
-     */
-    public void shutdown();
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java
deleted file mode 100644
index 4358270..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IStream.java
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.util.Callback;
-
-/**
- * <p>The internal interface that represents a stream.</p>
- * <p>{@link IStream} contains additional methods used by a SPDY
- * implementation (and not by an application).</p>
- */
-public interface IStream extends Stream, Callback
-{
-    /**
-     * <p>Senders of data frames need to know the current window size
-     * to determine whether they can send more data.</p>
-     *
-     * @return the current window size for this stream.
-     * @see #updateWindowSize(int)
-     */
-    public int getWindowSize();
-
-    /**
-     * <p>Updates the window size for this stream by the given amount,
-     * that can be positive or negative.</p>
-     * <p>Senders and recipients of data frames update the window size,
-     * respectively, with negative values and positive values.</p>
-     *
-     * @param delta the signed amount the window size needs to be updated
-     * @see #getWindowSize()
-     */
-    public void updateWindowSize(int delta);
-
-    /**
-     * @param listener the stream frame listener associated to this stream
-     * as returned by {@link SessionFrameListener#onSyn(Stream, SynInfo)}
-     */
-    public void setStreamFrameListener(StreamFrameListener listener);
-
-    /**
-     * @return the stream frame listener associated to this stream
-     */
-    public StreamFrameListener getStreamFrameListener();
-
-    /**
-     * <p>A stream can be open, {@link #isHalfClosed() half closed} or
-     * {@link #isClosed() closed} and this method updates the close state
-     * of this stream.</p>
-     * <p>If the stream is open, calling this method with a value of true
-     * puts the stream into half closed state.</p>
-     * <p>If the stream is half closed, calling this method with a value
-     * of true puts the stream into closed state.</p>
-     *
-     * @param close whether the close state should be updated
-     * @param local whether the close is local or remote
-     */
-    public void updateCloseState(boolean close, boolean local);
-
-    /**
-     * <p>Processes the given control frame,
-     * for example by updating the stream's state or by calling listeners.</p>
-     *
-     * @param frame the control frame to process
-     * @see #process(DataInfo)
-     */
-    public void process(ControlFrame frame);
-
-    /**
-     * <p>Processes the given {@code dataInfo},
-     * for example by updating the stream's state or by calling listeners.</p>
-     *
-     * @param dataInfo the DataInfo to process
-     * @see #process(ControlFrame)
-     */
-    public void process(DataInfo dataInfo);
-
-    /**
-     * <p>Associate the given {@link IStream} to this {@link IStream}.</p>
-     *
-     * @param stream the stream to associate with this stream
-     */
-    public void associate(IStream stream);
-
-    /**
-     * <p>remove the given associated {@link IStream} from this stream</p>
-     *
-     * @param stream the stream to be removed
-     */
-    public void disassociate(IStream stream);
-
-    /**
-     * <p>Overrides Stream.getAssociatedStream() to return an instance of IStream instead of Stream
-     *
-     * @see Stream#getAssociatedStream()
-     */
-    @Override
-    public IStream getAssociatedStream();
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java
deleted file mode 100644
index ff190d4..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/IdleListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-public interface IdleListener
-{
-    public void onIdle(boolean idle);
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java
deleted file mode 100644
index 39d1311..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/PushSynInfo.java
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-
-/* ------------------------------------------------------------ */
-/**
- * <p>A subclass container of {@link SynInfo} for unidirectional streams</p>
- */
-public class PushSynInfo extends SynInfo
-{
-    public static final byte FLAG_UNIDIRECTIONAL = 2;
-    
-    private int associatedStreamId;
-    
-    public PushSynInfo(int associatedStreamId, PushInfo pushInfo){
-        super(pushInfo.getTimeout(), pushInfo.getUnit(), pushInfo.getHeaders(), pushInfo.isClose(), (byte)0);
-        this.associatedStreamId = associatedStreamId;
-    }
-    
-    /**
-     * @return the close and unidirectional flags as integer
-     * @see #FLAG_CLOSE
-     * @see #FLAG_UNIDIRECTIONAL
-     */
-    @Override
-    public byte getFlags()
-    {
-        byte flags = super.getFlags();
-        flags += FLAG_UNIDIRECTIONAL;
-        return flags;
-    }
-    
-    /**
-     * @return the id of the associated stream
-     */
-    public int getAssociatedStreamId()
-    {
-        return associatedStreamId;
-    }
-
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java
deleted file mode 100644
index fe37965..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SPDYv3FlowControlStrategy.java
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
-import org.eclipse.jetty.util.Callback;
-
-public class SPDYv3FlowControlStrategy implements FlowControlStrategy
-{
-    private volatile int windowSize;
-
-    @Override
-    public int getWindowSize(ISession session)
-    {
-        return windowSize;
-    }
-
-    @Override
-    public void setWindowSize(ISession session, int windowSize)
-    {
-        int prevWindowSize = this.windowSize;
-        this.windowSize = windowSize;
-        for (Stream stream : session.getStreams())
-            ((IStream)stream).updateWindowSize(windowSize - prevWindowSize);
-    }
-
-    @Override
-    public void onNewStream(ISession session, IStream stream)
-    {
-        stream.updateWindowSize(windowSize);
-    }
-
-    @Override
-    public void onWindowUpdate(ISession session, IStream stream, int delta)
-    {
-        if (stream != null)
-            stream.updateWindowSize(delta);
-    }
-
-    @Override
-    public void updateWindow(ISession session, IStream stream, int delta)
-    {
-        stream.updateWindowSize(delta);
-    }
-
-    @Override
-    public void onDataReceived(ISession session, IStream stream, DataInfo dataInfo)
-    {
-        // Do nothing
-    }
-
-    @Override
-    public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta)
-    {
-        // This is the algorithm for flow control.
-        // This method may be called multiple times with delta=1, but we only send a window
-        // update when the whole dataInfo has been consumed.
-        // Other policies may be to send window updates when consumed() is greater than
-        // a certain threshold, etc. but for now the policy is not pluggable for simplicity.
-        // Note that the frequency of window updates depends on the read buffer, that
-        // should not be too smaller than the window size to avoid frequent window updates.
-        // Therefore, a pluggable policy should be able to modify the read buffer capacity.
-        int length = dataInfo.length();
-        if (dataInfo.consumed() == length && !stream.isClosed() && length > 0)
-        {
-            WindowUpdateFrame windowUpdateFrame = new WindowUpdateFrame(session.getVersion(), stream.getId(), length);
-            session.control(stream, windowUpdateFrame, 0, TimeUnit.MILLISECONDS, Callback.Adapter.INSTANCE);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java
deleted file mode 100644
index 26bc843..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/SessionException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.SessionStatus;
-
-public class SessionException extends RuntimeException
-{
-    private final SessionStatus sessionStatus;
-
-    public SessionException(SessionStatus sessionStatus)
-    {
-        this.sessionStatus = sessionStatus;
-    }
-
-    public SessionException(SessionStatus sessionStatus, String message)
-    {
-        super(message);
-        this.sessionStatus = sessionStatus;
-    }
-
-    public SessionException(SessionStatus sessionStatus, Throwable cause)
-    {
-        super(cause);
-        this.sessionStatus = sessionStatus;
-    }
-
-    public SessionStatus getSessionStatus()
-    {
-        return sessionStatus;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java
deleted file mode 100644
index 35150cf..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardCompressionFactory.java
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.util.zip.DataFormatException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-import java.util.zip.ZipException;
-
-public class StandardCompressionFactory implements CompressionFactory
-{
-    @Override
-    public Compressor newCompressor()
-    {
-        return new StandardCompressor();
-    }
-
-    @Override
-    public Decompressor newDecompressor()
-    {
-        return new StandardDecompressor();
-    }
-
-    public static class StandardCompressor implements Compressor
-    {
-        private final Deflater deflater = new Deflater();
-
-        @Override
-        public void setInput(byte[] input)
-        {
-            deflater.setInput(input);
-        }
-
-        @Override
-        public void setDictionary(byte[] dictionary)
-        {
-            deflater.setDictionary(dictionary);
-        }
-
-        @Override
-        public int compress(byte[] output)
-        {
-            return deflater.deflate(output, 0, output.length, Deflater.SYNC_FLUSH);
-        }
-    }
-
-    public static class StandardDecompressor implements CompressionFactory.Decompressor
-    {
-        private final Inflater inflater = new Inflater();
-
-        @Override
-        public void setDictionary(byte[] dictionary)
-        {
-            inflater.setDictionary(dictionary);
-        }
-
-        @Override
-        public void setInput(byte[] input)
-        {
-            inflater.setInput(input);
-        }
-
-        @Override
-        public int decompress(byte[] output) throws ZipException
-        {
-            try
-            {
-                return inflater.inflate(output);
-            }
-            catch (DataFormatException x)
-            {
-                throw (ZipException)new ZipException().initCause(x);
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
deleted file mode 100644
index c03cb4b..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
+++ /dev/null
@@ -1,1303 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.InterruptedByTimeoutException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.PingInfo;
-import org.eclipse.jetty.spdy.api.PingResultInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDYException;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.CredentialFrame;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.spdy.frames.GoAwayFrame;
-import org.eclipse.jetty.spdy.frames.HeadersFrame;
-import org.eclipse.jetty.spdy.frames.PingFrame;
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-import org.eclipse.jetty.spdy.frames.SettingsFrame;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Atomics;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.FutureCallback;
-import org.eclipse.jetty.util.FuturePromise;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.component.Dumpable;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.Scheduler;
-
-public class StandardSession implements ISession, Parser.Listener, Dumpable
-{
-    private static final Logger LOG = Log.getLogger(Session.class);
-
-    private final Flusher flusher;
-    private final Map<String, Object> attributes = new ConcurrentHashMap<>();
-    private final List<Listener> listeners = new CopyOnWriteArrayList<>();
-    private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
-    private final ByteBufferPool bufferPool;
-    private final Scheduler scheduler;
-    private final short version;
-    private final Controller controller;
-    private final EndPoint endPoint;
-    private final IdleListener idleListener;
-    private final AtomicInteger streamIds;
-    private final AtomicInteger pingIds;
-    private final SessionFrameListener listener;
-    private final Generator generator;
-    private final AtomicBoolean goAwaySent = new AtomicBoolean();
-    private final AtomicBoolean goAwayReceived = new AtomicBoolean();
-    private final AtomicInteger lastStreamId = new AtomicInteger();
-    private final AtomicInteger localStreamCount = new AtomicInteger(0);
-    private final FlowControlStrategy flowControlStrategy;
-    private volatile int maxConcurrentLocalStreams = -1;
-
-    public StandardSession(short version, ByteBufferPool bufferPool, Scheduler scheduler,
-                           Controller controller, EndPoint endPoint, IdleListener idleListener, int initialStreamId,
-                           SessionFrameListener listener, Generator generator, FlowControlStrategy flowControlStrategy)
-    {
-        // TODO this should probably be an aggregate lifecycle
-        this.version = version;
-        this.bufferPool = bufferPool;
-        this.scheduler = scheduler;
-        this.controller = controller;
-        this.endPoint = endPoint;
-        this.idleListener = idleListener;
-        this.streamIds = new AtomicInteger(initialStreamId);
-        this.pingIds = new AtomicInteger(initialStreamId);
-        this.listener = listener;
-        this.generator = generator;
-        this.flowControlStrategy = flowControlStrategy;
-        this.flusher = new Flusher(controller);
-    }
-
-    @Override
-    public short getVersion()
-    {
-        return version;
-    }
-
-    @Override
-    public void addListener(Listener listener)
-    {
-        listeners.add(listener);
-    }
-
-    @Override
-    public void removeListener(Listener listener)
-    {
-        listeners.remove(listener);
-    }
-
-    @Override
-    public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        FuturePromise<Stream> result = new FuturePromise<>();
-        syn(synInfo, listener, result);
-        if (synInfo.getTimeout() > 0)
-            return result.get(synInfo.getTimeout(), synInfo.getUnit());
-        else
-            return result.get();
-    }
-
-    @Override
-    public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise)
-    {
-        // Synchronization is necessary.
-        // SPEC v3, 2.3.1 requires that the stream creation be monotonically crescent
-        // so we cannot allow thread1 to create stream1 and thread2 create stream3 and
-        // have stream3 hit the network before stream1, not only to comply with the spec
-        // but also because the compression context for the headers would be wrong, as the
-        // frame with a compression history will come before the first compressed frame.
-        int associatedStreamId = 0;
-        if (synInfo instanceof PushSynInfo)
-            associatedStreamId = ((PushSynInfo)synInfo).getAssociatedStreamId();
-
-        synchronized (this)
-        {
-            int streamId = streamIds.getAndAdd(2);
-            // TODO: for SPDYv3 we need to support the "slot" argument
-            SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders());
-            IStream stream = createStream(synStream, listener, true, promise);
-            if (stream == null)
-                return;
-            generateAndEnqueueControlFrame(stream, synStream, synInfo.getTimeout(), synInfo.getUnit(), stream);
-        }
-    }
-
-    @Override
-    public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        rst(rstInfo, result);
-        if (rstInfo.getTimeout() > 0)
-            result.get(rstInfo.getTimeout(), rstInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void rst(RstInfo rstInfo, Callback callback)
-    {
-        // SPEC v3, 2.2.2
-        if (goAwaySent.get())
-        {
-            complete(callback);
-        }
-        else
-        {
-            int streamId = rstInfo.getStreamId();
-            IStream stream = streams.get(streamId);
-            RstStreamFrame frame = new RstStreamFrame(version, streamId, rstInfo.getStreamStatus().getCode(version));
-            control(stream, frame, rstInfo.getTimeout(), rstInfo.getUnit(), callback);
-            if (stream != null)
-            {
-                stream.process(frame);
-                flusher.removeFrameBytesFromQueue(stream);
-                removeStream(stream);
-            }
-        }
-    }
-
-    @Override
-    public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        settings(settingsInfo, result);
-        if (settingsInfo.getTimeout() > 0)
-            result.get(settingsInfo.getTimeout(), settingsInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void settings(SettingsInfo settingsInfo, Callback callback)
-    {
-        SettingsFrame frame = new SettingsFrame(version, settingsInfo.getFlags(), settingsInfo.getSettings());
-        control(null, frame, settingsInfo.getTimeout(), settingsInfo.getUnit(), callback);
-    }
-
-    @Override
-    public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        FuturePromise<PingResultInfo> result = new FuturePromise<>();
-        ping(pingInfo, result);
-        if (pingInfo.getTimeout() > 0)
-            return result.get(pingInfo.getTimeout(), pingInfo.getUnit());
-        else
-            return result.get();
-    }
-
-    @Override
-    public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise)
-    {
-        int pingId = pingIds.getAndAdd(2);
-        PingInfoCallback pingInfoCallback = new PingInfoCallback(pingId, promise);
-        PingFrame frame = new PingFrame(version, pingId);
-        control(null, frame, pingInfo.getTimeout(), pingInfo.getUnit(), pingInfoCallback);
-    }
-
-    @Override
-    public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        goAway(goAwayInfo, SessionStatus.OK);
-    }
-
-    private void goAway(GoAwayInfo goAwayInfo, SessionStatus sessionStatus) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        goAway(sessionStatus, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), result);
-        if (goAwayInfo.getTimeout() > 0)
-            result.get(goAwayInfo.getTimeout(), goAwayInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void goAway(GoAwayInfo goAwayInfo, Callback callback)
-    {
-        goAway(SessionStatus.OK, goAwayInfo.getTimeout(), goAwayInfo.getUnit(), callback);
-    }
-
-    private void goAway(SessionStatus sessionStatus, long timeout, TimeUnit unit, Callback callback)
-    {
-        if (goAwaySent.compareAndSet(false, true))
-        {
-            if (!goAwayReceived.get())
-            {
-                GoAwayFrame frame = new GoAwayFrame(version, lastStreamId.get(), sessionStatus.getCode());
-                control(null, frame, timeout, unit, callback);
-                return;
-            }
-        }
-        complete(callback);
-    }
-
-    @Override
-    public Set<Stream> getStreams()
-    {
-        Set<Stream> result = new HashSet<>();
-        result.addAll(streams.values());
-        return result;
-    }
-
-    @Override
-    public IStream getStream(int streamId)
-    {
-        return streams.get(streamId);
-    }
-
-    @Override
-    public Object getAttribute(String key)
-    {
-        return attributes.get(key);
-    }
-
-    @Override
-    public void setAttribute(String key, Object value)
-    {
-        attributes.put(key, value);
-    }
-
-    @Override
-    public Object removeAttribute(String key)
-    {
-        return attributes.remove(key);
-    }
-
-    @Override
-    public InetSocketAddress getLocalAddress()
-    {
-        return endPoint.getLocalAddress();
-    }
-
-    @Override
-    public InetSocketAddress getRemoteAddress()
-    {
-        return endPoint.getRemoteAddress();
-    }
-
-    @Override
-    public void onControlFrame(ControlFrame frame)
-    {
-        notifyIdle(idleListener, false);
-        try
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Processing {}", frame);
-
-            if (goAwaySent.get())
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Skipped processing of {}", frame);
-                return;
-            }
-
-            switch (frame.getType())
-            {
-                case SYN_STREAM:
-                {
-                    onSyn((SynStreamFrame)frame);
-                    break;
-                }
-                case SYN_REPLY:
-                {
-                    onReply((SynReplyFrame)frame);
-                    break;
-                }
-                case RST_STREAM:
-                {
-                    onRst((RstStreamFrame)frame);
-                    break;
-                }
-                case SETTINGS:
-                {
-                    onSettings((SettingsFrame)frame);
-                    break;
-                }
-                case NOOP:
-                {
-                    // Just ignore it
-                    break;
-                }
-                case PING:
-                {
-                    onPing((PingFrame)frame);
-                    break;
-                }
-                case GO_AWAY:
-                {
-                    onGoAway((GoAwayFrame)frame);
-                    break;
-                }
-                case HEADERS:
-                {
-                    onHeaders((HeadersFrame)frame);
-                    break;
-                }
-                case WINDOW_UPDATE:
-                {
-                    onWindowUpdate((WindowUpdateFrame)frame);
-                    break;
-                }
-                case CREDENTIAL:
-                {
-                    onCredential((CredentialFrame)frame);
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        finally
-        {
-            notifyIdle(idleListener, true);
-        }
-    }
-
-    @Override
-    public void onDataFrame(DataFrame frame, ByteBuffer data)
-    {
-        notifyIdle(idleListener, false);
-        try
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Processing {}, {} data bytes", frame, data.remaining());
-
-            if (goAwaySent.get())
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Skipped processing of {}", frame);
-                return;
-            }
-
-            int streamId = frame.getStreamId();
-            IStream stream = streams.get(streamId);
-            if (stream == null)
-            {
-                RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Unknown stream {}", rstInfo);
-                rst(rstInfo, Callback.Adapter.INSTANCE);
-            }
-            else
-            {
-                processData(stream, frame, data);
-            }
-        }
-        finally
-        {
-            notifyIdle(idleListener, true);
-        }
-    }
-
-    private void notifyIdle(IdleListener listener, boolean idle)
-    {
-        if (listener != null)
-            listener.onIdle(idle);
-    }
-
-    private void processData(final IStream stream, DataFrame frame, ByteBuffer data)
-    {
-        ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose())
-        {
-            @Override
-            public void consume(int delta)
-            {
-                super.consume(delta);
-                flowControlStrategy.onDataConsumed(StandardSession.this, stream, this, delta);
-            }
-        };
-        flowControlStrategy.onDataReceived(this, stream, dataInfo);
-        stream.process(dataInfo);
-        if (stream.isClosed())
-            removeStream(stream);
-    }
-
-    @Override
-    public void onStreamException(StreamException x)
-    {
-        notifyOnFailure(listener, x); // TODO: notify StreamFrameListener if exists?
-        rst(new RstInfo(x.getStreamId(), x.getStreamStatus()), Callback.Adapter.INSTANCE);
-    }
-
-    @Override
-    public void onSessionException(SessionException x)
-    {
-        Throwable cause = x.getCause();
-        notifyOnFailure(listener, cause == null ? x : cause);
-        goAway(x.getSessionStatus(), 0, TimeUnit.SECONDS, Callback.Adapter.INSTANCE);
-    }
-
-    private void onSyn(final SynStreamFrame frame)
-    {
-        IStream stream = createStream(frame, null, false, new Promise.Adapter<Stream>()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                LOG.debug("Received: {} but creating new Stream failed: {}", frame, x.getMessage());
-            }
-        });
-        if (stream != null)
-            processSyn(listener, stream, frame);
-    }
-
-    private void processSyn(SessionFrameListener listener, IStream stream, SynStreamFrame frame)
-    {
-        stream.process(frame);
-        // Update the last stream id before calling the application (which may send a GO_AWAY)
-        updateLastStreamId(stream);
-        StreamFrameListener streamListener;
-        if (stream.isUnidirectional())
-        {
-            PushInfo pushInfo = new PushInfo(frame.getHeaders(), frame.isClose());
-            streamListener = notifyOnPush(stream.getAssociatedStream().getStreamFrameListener(), stream, pushInfo);
-        }
-        else
-        {
-            SynInfo synInfo = new SynInfo(frame.getHeaders(), frame.isClose(), frame.getPriority());
-            streamListener = notifyOnSyn(listener, stream, synInfo);
-        }
-        stream.setStreamFrameListener(streamListener);
-        // The onSyn() listener may have sent a frame that closed the stream
-        if (stream.isClosed())
-            removeStream(stream);
-    }
-
-    private IStream createStream(SynStreamFrame frame, StreamFrameListener listener, boolean local, Promise<Stream> promise)
-    {
-        IStream associatedStream = streams.get(frame.getAssociatedStreamId());
-        IStream stream = new StandardStream(frame.getStreamId(), frame.getPriority(), this, associatedStream,
-                scheduler, promise);
-        stream.setIdleTimeout(endPoint.getIdleTimeout());
-        flowControlStrategy.onNewStream(this, stream);
-
-        stream.updateCloseState(frame.isClose(), local);
-        stream.setStreamFrameListener(listener);
-
-        if (stream.isUnidirectional())
-        {
-            // Unidirectional streams are implicitly half closed
-            stream.updateCloseState(true, !local);
-            if (!stream.isClosed())
-                stream.getAssociatedStream().associate(stream);
-        }
-
-        int streamId = stream.getId();
-
-        if (local)
-        {
-            while (true)
-            {
-                int oldStreamCountValue = localStreamCount.get();
-                int maxConcurrentStreams = maxConcurrentLocalStreams;
-                if (maxConcurrentStreams > -1 && oldStreamCountValue >= maxConcurrentStreams)
-                {
-                    String message = String.format("Max concurrent local streams (%d) exceeded.",
-                            maxConcurrentStreams);
-                    LOG.debug(message);
-                    promise.failed(new SPDYException(message));
-                    return null;
-                }
-                if (localStreamCount.compareAndSet(oldStreamCountValue, oldStreamCountValue + 1))
-                    break;
-            }
-        }
-
-        if (streams.putIfAbsent(streamId, stream) != null)
-        {
-            String message = "Duplicate stream id " + streamId;
-            IllegalStateException duplicateIdException = new IllegalStateException(message);
-            promise.failed(duplicateIdException);
-            if (local)
-            {
-                localStreamCount.decrementAndGet();
-                throw duplicateIdException;
-            }
-            RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Duplicate stream, {}", rstInfo);
-            rst(rstInfo, Callback.Adapter.INSTANCE); // We don't care (too much) if the reset fails.
-            return null;
-        }
-        else
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Created {}", stream);
-            notifyStreamCreated(stream);
-            return stream;
-        }
-    }
-
-    private void notifyStreamCreated(IStream stream)
-    {
-        for (Listener listener : listeners)
-        {
-            if (listener instanceof StreamListener)
-            {
-                try
-                {
-                    ((StreamListener)listener).onStreamCreated(stream);
-                }
-                catch (Exception x)
-                {
-                    LOG.info("Exception while notifying listener " + listener, x);
-                }
-                catch (Error x)
-                {
-                    LOG.info("Exception while notifying listener " + listener, x);
-                    throw x;
-                }
-            }
-        }
-    }
-
-    private void removeStream(IStream stream)
-    {
-        if (stream.isUnidirectional())
-            stream.getAssociatedStream().disassociate(stream);
-
-        IStream removed = streams.remove(stream.getId());
-        if (removed != null)
-        {
-            assert removed == stream;
-
-            if (streamIds.get() % 2 == stream.getId() % 2)
-                localStreamCount.decrementAndGet();
-
-            if (LOG.isDebugEnabled())
-                LOG.debug("Removed {}", stream);
-            notifyStreamClosed(stream);
-        }
-    }
-
-    private void notifyStreamClosed(IStream stream)
-    {
-        for (Listener listener : listeners)
-        {
-            if (listener instanceof StreamListener)
-            {
-                try
-                {
-                    ((StreamListener)listener).onStreamClosed(stream);
-                }
-                catch (Exception x)
-                {
-                    LOG.info("Exception while notifying listener " + listener, x);
-                }
-                catch (Error x)
-                {
-                    LOG.info("Exception while notifying listener " + listener, x);
-                    throw x;
-                }
-            }
-        }
-    }
-
-    private void onReply(SynReplyFrame frame)
-    {
-        int streamId = frame.getStreamId();
-        IStream stream = streams.get(streamId);
-        if (stream == null)
-        {
-            RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Unknown stream {}", rstInfo);
-            rst(rstInfo, Callback.Adapter.INSTANCE);
-        }
-        else
-        {
-            processReply(stream, frame);
-        }
-    }
-
-    private void processReply(IStream stream, SynReplyFrame frame)
-    {
-        stream.process(frame);
-        if (stream.isClosed())
-            removeStream(stream);
-    }
-
-    private void onRst(RstStreamFrame frame)
-    {
-        IStream stream = streams.get(frame.getStreamId());
-
-        if (stream != null)
-            stream.process(frame);
-
-        RstInfo rstInfo = new RstInfo(frame.getStreamId(), StreamStatus.from(frame.getVersion(), frame.getStatusCode()));
-        notifyOnRst(listener, rstInfo);
-
-        if (stream != null)
-            removeStream(stream);
-    }
-
-    private void onSettings(SettingsFrame frame)
-    {
-        Settings.Setting windowSizeSetting = frame.getSettings().get(Settings.ID.INITIAL_WINDOW_SIZE);
-        if (windowSizeSetting != null)
-        {
-            int windowSize = windowSizeSetting.value();
-            setWindowSize(windowSize);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Updated session window size to {}", windowSize);
-        }
-        Settings.Setting maxConcurrentStreamsSetting = frame.getSettings().get(Settings.ID.MAX_CONCURRENT_STREAMS);
-        if (maxConcurrentStreamsSetting != null)
-        {
-            int maxConcurrentStreamsValue = maxConcurrentStreamsSetting.value();
-            maxConcurrentLocalStreams = maxConcurrentStreamsValue;
-            if (LOG.isDebugEnabled())
-                LOG.debug("Updated session maxConcurrentLocalStreams to {}", maxConcurrentStreamsValue);
-        }
-        SettingsInfo settingsInfo = new SettingsInfo(frame.getSettings(), frame.isClearPersisted());
-        notifyOnSettings(listener, settingsInfo);
-    }
-
-    private void onPing(PingFrame frame)
-    {
-        int pingId = frame.getPingId();
-        if (pingId % 2 == pingIds.get() % 2)
-        {
-            PingResultInfo pingResultInfo = new PingResultInfo(frame.getPingId());
-            notifyOnPing(listener, pingResultInfo);
-        }
-        else
-        {
-            control(null, frame, 0, TimeUnit.MILLISECONDS, Callback.Adapter.INSTANCE);
-        }
-    }
-
-    private void onGoAway(GoAwayFrame frame)
-    {
-        if (goAwayReceived.compareAndSet(false, true))
-        {
-            GoAwayResultInfo goAwayResultInfo = new GoAwayResultInfo(frame.getLastStreamId(), SessionStatus.from(frame.getStatusCode()));
-            notifyOnGoAway(listener, goAwayResultInfo);
-            // SPDY does not require to send back a response to a GO_AWAY.
-            // We notified the application of the last good stream id and
-            // tried our best to flush remaining data.
-        }
-    }
-
-    private void onHeaders(HeadersFrame frame)
-    {
-        int streamId = frame.getStreamId();
-        IStream stream = streams.get(streamId);
-        if (stream == null)
-        {
-            RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
-            if (LOG.isDebugEnabled())
-                LOG.debug("Unknown stream, {}", rstInfo);
-            rst(rstInfo, Callback.Adapter.INSTANCE);
-        }
-        else
-        {
-            processHeaders(stream, frame);
-        }
-    }
-
-    private void processHeaders(IStream stream, HeadersFrame frame)
-    {
-        stream.process(frame);
-        if (stream.isClosed())
-            removeStream(stream);
-    }
-
-    private void onWindowUpdate(WindowUpdateFrame frame)
-    {
-        int streamId = frame.getStreamId();
-        IStream stream = streams.get(streamId);
-        flowControlStrategy.onWindowUpdate(this, stream, frame.getWindowDelta());
-        flusher.flush();
-    }
-
-    private void onCredential(CredentialFrame frame)
-    {
-        LOG.warn("{} frame not yet supported", frame.getType());
-    }
-
-    protected void close()
-    {
-        // Check for null to support tests
-        if (controller != null)
-            controller.close(false);
-    }
-
-    private void notifyOnFailure(SessionFrameListener listener, Throwable x)
-    {
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking callback with {} on listener {}", x, listener);
-                listener.onFailure(this, x);
-            }
-        }
-        catch (Exception xx)
-        {
-            LOG.info("Exception while notifying listener " + listener, xx);
-        }
-        catch (Error xx)
-        {
-            LOG.info("Exception while notifying listener " + listener, xx);
-            throw xx;
-        }
-    }
-
-    private StreamFrameListener notifyOnPush(StreamFrameListener listener, Stream stream, PushInfo pushInfo)
-    {
-        try
-        {
-            if (listener == null)
-                return null;
-            if (LOG.isDebugEnabled())
-                LOG.debug("Invoking callback with {} on listener {}", pushInfo, listener);
-            return listener.onPush(stream, pushInfo);
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            return null;
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private StreamFrameListener notifyOnSyn(SessionFrameListener listener, Stream stream, SynInfo synInfo)
-    {
-        try
-        {
-            if (listener == null)
-                return null;
-            if (LOG.isDebugEnabled())
-                LOG.debug("Invoking callback with {} on listener {}", synInfo, listener);
-            return listener.onSyn(stream, synInfo);
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            return null;
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnRst(SessionFrameListener listener, RstInfo rstInfo)
-    {
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking callback with {} on listener {}", rstInfo, listener);
-                listener.onRst(this, rstInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnSettings(SessionFrameListener listener, SettingsInfo settingsInfo)
-    {
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking callback with {} on listener {}", settingsInfo, listener);
-                listener.onSettings(this, settingsInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnPing(SessionFrameListener listener, PingResultInfo pingResultInfo)
-    {
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking callback with {} on listener {}", pingResultInfo, listener);
-                listener.onPing(this, pingResultInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnGoAway(SessionFrameListener listener, GoAwayResultInfo goAwayResultInfo)
-    {
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking callback with {} on listener {}", goAwayResultInfo, listener);
-                listener.onGoAway(this, goAwayResultInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    @Override
-    public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback)
-    {
-        generateAndEnqueueControlFrame(stream, frame, timeout, unit, callback);
-    }
-
-    private void generateAndEnqueueControlFrame(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback)
-    {
-        try
-        {
-            // Synchronization is necessary, since we may have concurrent replies
-            // and those needs to be generated and enqueued atomically in order
-            // to maintain a correct compression context
-            ControlFrameBytes frameBytes;
-            Throwable throwable;
-            synchronized (this)
-            {
-                ByteBuffer buffer = generator.control(frame);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Queuing {} on {}", frame, stream);
-                frameBytes = new ControlFrameBytes(stream, callback, frame, buffer);
-                if (timeout > 0)
-                    frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
-
-                // Special handling for PING frames, they must be sent as soon as possible
-                if (ControlFrameType.PING == frame.getType())
-                    throwable = flusher.prepend(frameBytes);
-                else
-                    throwable = flusher.append(frameBytes);
-            }
-            // Flush MUST be done outside synchronized blocks
-            flush(frameBytes, throwable);
-        }
-        catch (Exception x)
-        {
-            notifyCallbackFailed(callback, x);
-        }
-    }
-
-    private void updateLastStreamId(IStream stream)
-    {
-        int streamId = stream.getId();
-        if (streamId % 2 != streamIds.get() % 2)
-            Atomics.updateMax(lastStreamId, streamId);
-    }
-
-    @Override
-    public void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Callback callback)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("Queuing {} on {}", dataInfo, stream);
-        DataFrameBytes frameBytes = new DataFrameBytes(stream, callback, dataInfo);
-        if (timeout > 0)
-            frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
-        flush(frameBytes, flusher.append(frameBytes));
-    }
-
-    @Override
-    public void shutdown()
-    {
-        CloseFrameBytes frameBytes = new CloseFrameBytes();
-        flush(frameBytes, flusher.append(frameBytes));
-    }
-
-    private void flush(FrameBytes frameBytes, Throwable throwable)
-    {
-        if (throwable != null)
-            frameBytes.failed(throwable);
-        else
-            flusher.flush();
-    }
-
-    private void complete(final Callback callback)
-    {
-        try
-        {
-            if (callback != null)
-                callback.succeeded();
-        }
-        catch (Throwable x)
-        {
-            LOG.info("Exception while notifying callback " + callback, x);
-        }
-    }
-
-    private void notifyCallbackFailed(Callback callback, Throwable failure)
-    {
-        try
-        {
-            if (callback != null)
-                callback.failed(failure);
-        }
-        catch (Throwable x)
-        {
-            LOG.info("Exception while notifying callback " + callback, x);
-        }
-    }
-
-    public int getWindowSize()
-    {
-        return flowControlStrategy.getWindowSize(this);
-    }
-
-    public void setWindowSize(int initialWindowSize)
-    {
-        flowControlStrategy.setWindowSize(this, initialWindowSize);
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s@%x{v%d,queueSize=%d,windowSize=%d,streams=%d}", getClass().getSimpleName(),
-                hashCode(), version, flusher.getQueueSize(), getWindowSize(), streams.size());
-    }
-
-    @Override
-    public String dump()
-    {
-        return ContainerLifeCycle.dump(this);
-    }
-
-    @Override
-    public void dump(Appendable out, String indent) throws IOException
-    {
-        ContainerLifeCycle.dumpObject(out, this);
-        ContainerLifeCycle.dump(out, indent, Collections.singletonList(controller), streams.values());
-    }
-
-    public interface FrameBytes extends Comparable<FrameBytes>, Callback
-    {
-        public IStream getStream();
-
-        public abstract ByteBuffer getByteBuffer();
-    }
-
-    abstract class AbstractFrameBytes implements FrameBytes, Runnable
-    {
-        private final IStream stream;
-        private final Callback callback;
-        protected volatile Scheduler.Task task;
-
-        protected AbstractFrameBytes(IStream stream, Callback callback)
-        {
-            this.stream = stream;
-            this.callback = Objects.requireNonNull(callback);
-        }
-
-        @Override
-        public IStream getStream()
-        {
-            return stream;
-        }
-
-        @Override
-        public int compareTo(FrameBytes that)
-        {
-            // FrameBytes may have or not have a related stream (for example, PING do not have a related stream)
-            // FrameBytes without related streams have higher priority
-            IStream thisStream = getStream();
-            IStream thatStream = that.getStream();
-            if (thisStream == null)
-                return thatStream == null ? 0 : -1;
-            if (thatStream == null)
-                return 1;
-            // If this.stream.priority > that.stream.priority => this.stream has less priority than that.stream
-            return thatStream.getPriority() - thisStream.getPriority();
-        }
-
-        private void cancelTask()
-        {
-            Scheduler.Task task = this.task;
-            if (task != null)
-                task.cancel();
-        }
-
-        @Override
-        public void run()
-        {
-            close();
-            failed(new InterruptedByTimeoutException());
-        }
-
-        @Override
-        public void succeeded()
-        {
-            cancelTask();
-            StandardSession.this.complete(callback);
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-            cancelTask();
-            notifyCallbackFailed(callback, x);
-        }
-    }
-
-    protected class ControlFrameBytes extends AbstractFrameBytes
-    {
-        private final ControlFrame frame;
-        private final ByteBuffer buffer;
-
-        private ControlFrameBytes(IStream stream, Callback callback, ControlFrame frame, ByteBuffer buffer)
-        {
-            super(stream, callback);
-            this.frame = frame;
-            this.buffer = buffer;
-        }
-
-        @Override
-        public ByteBuffer getByteBuffer()
-        {
-            return buffer;
-        }
-
-        @Override
-        public void succeeded()
-        {
-            bufferPool.release(buffer);
-
-            super.succeeded();
-
-            if (frame.getType() == ControlFrameType.GO_AWAY)
-            {
-                // After sending a GO_AWAY we need to hard close the connection.
-                // Recipients will know the last good stream id and act accordingly.
-                close();
-            }
-            IStream stream = getStream();
-            if (stream != null && stream.isClosed())
-                removeStream(stream);
-        }
-
-        @Override
-        public String toString()
-        {
-            return frame.toString();
-        }
-    }
-
-    protected class DataFrameBytes extends AbstractFrameBytes
-    {
-        private final DataInfo dataInfo;
-        private int size;
-        private volatile ByteBuffer buffer;
-
-        private DataFrameBytes(IStream stream, Callback handler, DataInfo dataInfo)
-        {
-            super(stream, handler);
-            this.dataInfo = dataInfo;
-        }
-
-        @Override
-        public ByteBuffer getByteBuffer()
-        {
-            try
-            {
-                IStream stream = getStream();
-                int windowSize = stream.getWindowSize();
-
-                // TODO: optimization
-                // Right now, we use the windowSize to chunk big buffers.
-                // However, if the window size is large, we may congest the
-                // connection, or favor one stream that does a big download,
-                // starving the other streams.
-                // Also, SPDY DATA frames have a maximum of 16 MiB size, which
-                // is not enforced here.
-                // We should have a configurable "preferredDataFrameSize"
-                // (or even better autotuning) that will allow to send chunks
-                // that will not starve other streams and small enough to
-                // not congest the connection, while avoiding to send too many
-                // TCP packets.
-                // See also comment in class Flusher.
-
-                size = dataInfo.available();
-                if (size > windowSize)
-                    size = windowSize;
-
-                buffer = generator.data(stream.getId(), size, dataInfo);
-                return buffer;
-            }
-            catch (Throwable x)
-            {
-                failed(x);
-                return null;
-            }
-        }
-
-        @Override
-        public void succeeded()
-        {
-            bufferPool.release(buffer);
-            IStream stream = getStream();
-            dataInfo.consume(size);
-            flowControlStrategy.updateWindow(StandardSession.this, stream, -size);
-            if (dataInfo.available() > 0)
-            {
-                // We have written a frame out of this DataInfo, but there is more to write.
-                // We need to keep the correct ordering of frames, to avoid that another
-                // DataInfo for the same stream is written before this one is finished.
-                flush(this, flusher.prepend(this));
-            }
-            else
-            {
-                super.succeeded();
-                stream.updateCloseState(dataInfo.isClose(), true);
-                if (stream.isClosed())
-                    removeStream(stream);
-            }
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), getStream());
-        }
-    }
-
-    protected class CloseFrameBytes extends AbstractFrameBytes
-    {
-        private CloseFrameBytes()
-        {
-            super(null, Callback.Adapter.INSTANCE);
-        }
-
-        @Override
-        public ByteBuffer getByteBuffer()
-        {
-            return BufferUtil.EMPTY_BUFFER;
-        }
-
-        @Override
-        public void succeeded()
-        {
-            super.succeeded();
-            close();
-        }
-    }
-
-    private static class PingInfoCallback extends PingResultInfo implements Callback
-    {
-        private final Promise<PingResultInfo> promise;
-
-        public PingInfoCallback(int pingId, Promise<PingResultInfo> promise)
-        {
-            super(pingId);
-            this.promise = promise;
-        }
-
-        @Override
-        public void succeeded()
-        {
-            if (promise != null)
-                promise.succeeded(this);
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-            if (promise != null)
-                promise.failed(x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java
deleted file mode 100644
index e5f5641..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardStream.java
+++ /dev/null
@@ -1,602 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.eclipse.jetty.io.IdleTimeout;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.HeadersFrame;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.FutureCallback;
-import org.eclipse.jetty.util.FuturePromise;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.Scheduler;
-
-public class StandardStream extends IdleTimeout implements IStream
-{
-    private static final Logger LOG = Log.getLogger(Stream.class);
-    private final Map<String, Object> attributes = new ConcurrentHashMap<>();
-    private final int id;
-    private final byte priority;
-    private final ISession session;
-    private final IStream associatedStream;
-    private final Promise<Stream> promise;
-    private final AtomicInteger windowSize = new AtomicInteger();
-    private final Set<Stream> pushedStreams = Collections.newSetFromMap(new ConcurrentHashMap<Stream, Boolean>());
-    private volatile StreamFrameListener listener;
-    private volatile OpenState openState = OpenState.SYN_SENT;
-    private volatile CloseState closeState = CloseState.OPENED;
-    private volatile boolean reset = false;
-
-    public StandardStream(int id, byte priority, ISession session, IStream associatedStream, Scheduler scheduler, Promise<Stream> promise)
-    {
-        super(scheduler);
-        this.id = id;
-        this.priority = priority;
-        this.session = session;
-        this.associatedStream = associatedStream;
-        this.promise = promise;
-    }
-
-    @Override
-    public int getId()
-    {
-        return id;
-    }
-
-    @Override
-    public IStream getAssociatedStream()
-    {
-        return associatedStream;
-    }
-
-    @Override
-    public Set<Stream> getPushedStreams()
-    {
-        return pushedStreams;
-    }
-
-    @Override
-    public void associate(IStream stream)
-    {
-        pushedStreams.add(stream);
-    }
-
-    @Override
-    public void disassociate(IStream stream)
-    {
-        pushedStreams.remove(stream);
-    }
-
-    @Override
-    public byte getPriority()
-    {
-        return priority;
-    }
-
-    @Override
-    protected void onIdleExpired(TimeoutException timeout)
-    {
-        StreamFrameListener listener = this.listener;
-        if (listener != null)
-            listener.onFailure(this, timeout);
-        // The stream is now gone, we must close it to
-        // avoid that its idle timeout is rescheduled.
-        close();
-    }
-
-    private void close()
-    {
-        closeState = CloseState.CLOSED;
-        onClose();
-    }
-
-    @Override
-    public boolean isOpen()
-    {
-        return !isClosed();
-    }
-
-    @Override
-    public int getWindowSize()
-    {
-        return windowSize.get();
-    }
-
-    @Override
-    public void updateWindowSize(int delta)
-    {
-        int size = windowSize.addAndGet(delta);
-        if (LOG.isDebugEnabled())
-            LOG.debug("Updated window size {} -> {} for {}", size - delta, size, this);
-    }
-
-    @Override
-    public ISession getSession()
-    {
-        return session;
-    }
-
-    @Override
-    public Object getAttribute(String key)
-    {
-        return attributes.get(key);
-    }
-
-    @Override
-    public void setAttribute(String key, Object value)
-    {
-        attributes.put(key, value);
-    }
-
-    @Override
-    public Object removeAttribute(String key)
-    {
-        return attributes.remove(key);
-    }
-
-    @Override
-    public void setStreamFrameListener(StreamFrameListener listener)
-    {
-        this.listener = listener;
-    }
-
-    @Override
-    public StreamFrameListener getStreamFrameListener()
-    {
-        return listener;
-    }
-
-    @Override
-    public void updateCloseState(boolean close, boolean local)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} close={} local={}", this, close, local);
-        if (close)
-        {
-            switch (closeState)
-            {
-                case OPENED:
-                {
-                    closeState = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED;
-                    break;
-                }
-                case LOCALLY_CLOSED:
-                {
-                    if (local)
-                        throw new IllegalStateException();
-                    else
-                        close();
-                    break;
-                }
-                case REMOTELY_CLOSED:
-                {
-                    if (local)
-                        close();
-                    else
-                        throw new IllegalStateException();
-                    break;
-                }
-                default:
-                {
-                    LOG.warn("Already CLOSED! {} local={}", this, local);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void process(ControlFrame frame)
-    {
-        notIdle();
-        switch (frame.getType())
-        {
-            case SYN_STREAM:
-            {
-                openState = OpenState.SYN_RECV;
-                break;
-            }
-            case SYN_REPLY:
-            {
-                openState = OpenState.REPLY_RECV;
-                SynReplyFrame synReply = (SynReplyFrame)frame;
-                updateCloseState(synReply.isClose(), false);
-                ReplyInfo replyInfo = new ReplyInfo(synReply.getHeaders(), synReply.isClose());
-                notifyOnReply(replyInfo);
-                break;
-            }
-            case HEADERS:
-            {
-                HeadersFrame headers = (HeadersFrame)frame;
-                updateCloseState(headers.isClose(), false);
-                HeadersInfo headersInfo = new HeadersInfo(headers.getHeaders(), headers.isClose(), headers.isResetCompression());
-                notifyOnHeaders(headersInfo);
-                break;
-            }
-            case RST_STREAM:
-            {
-                reset = true;
-                break;
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    @Override
-    public void process(DataInfo dataInfo)
-    {
-        notIdle();
-        // TODO: in v3 we need to send a rst instead of just ignoring
-        // ignore data frame if this stream is remotelyClosed already
-        if (isRemotelyClosed())
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Stream is remotely closed, ignoring {}", dataInfo);
-            return;
-        }
-
-        if (!canReceive())
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Protocol error receiving {}, resetting", dataInfo);
-            session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), Callback.Adapter.INSTANCE);
-            return;
-        }
-
-        updateCloseState(dataInfo.isClose(), false);
-        notifyOnData(dataInfo);
-    }
-
-    @Override
-    public void succeeded()
-    {
-        if (promise != null)
-            promise.succeeded(this);
-    }
-
-    @Override
-    public void failed(Throwable x)
-    {
-        if (promise != null)
-            promise.failed(x);
-    }
-
-    private void notifyOnReply(ReplyInfo replyInfo)
-    {
-        final StreamFrameListener listener = this.listener;
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking reply callback with {} on listener {}", replyInfo, listener);
-                listener.onReply(this, replyInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnHeaders(HeadersInfo headersInfo)
-    {
-        final StreamFrameListener listener = this.listener;
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking headers callback with {} on listener {}", headersInfo, listener);
-                listener.onHeaders(this, headersInfo);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    private void notifyOnData(DataInfo dataInfo)
-    {
-        final StreamFrameListener listener = this.listener;
-        try
-        {
-            if (listener != null)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoking data callback with {} on listener {}", dataInfo, listener);
-                listener.onData(this, dataInfo);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Invoked data callback with {} on listener {}", dataInfo, listener);
-            }
-        }
-        catch (Exception x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-        }
-        catch (Error x)
-        {
-            LOG.info("Exception while notifying listener " + listener, x);
-            throw x;
-        }
-    }
-
-    @Override
-    public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        FuturePromise<Stream> result = new FuturePromise<>();
-        push(pushInfo, result);
-        if (pushInfo.getTimeout() > 0)
-            return result.get(pushInfo.getTimeout(), pushInfo.getUnit());
-        else
-            return result.get();
-    }
-
-    @Override
-    public void push(PushInfo pushInfo, Promise<Stream> promise)
-    {
-        notIdle();
-        if (isClosed() || isReset())
-        {
-            close();
-            promise.failed(new StreamException(getId(), StreamStatus.STREAM_ALREADY_CLOSED,
-                    "Stream: " + this + " already closed or reset!"));
-            return;
-        }
-        PushSynInfo pushSynInfo = new PushSynInfo(getId(), pushInfo);
-        session.syn(pushSynInfo, null, new StreamPromise(promise));
-    }
-
-    @Override
-    public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        reply(replyInfo, result);
-        if (replyInfo.getTimeout() > 0)
-            result.get(replyInfo.getTimeout(), replyInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void reply(ReplyInfo replyInfo, Callback callback)
-    {
-        notIdle();
-        if (isUnidirectional())
-        {
-            close();
-            throw new IllegalStateException("Protocol violation: cannot send SYN_REPLY frames in unidirectional streams");
-        }
-        openState = OpenState.REPLY_SENT;
-        updateCloseState(replyInfo.isClose(), true);
-        SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders());
-        session.control(this, frame, replyInfo.getTimeout(), replyInfo.getUnit(), new StreamCallback(callback));
-    }
-
-    @Override
-    public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        data(dataInfo, result);
-        if (dataInfo.getTimeout() > 0)
-            result.get(dataInfo.getTimeout(), dataInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void data(DataInfo dataInfo, Callback callback)
-    {
-        notIdle();
-        if (!canSend())
-        {
-            session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback());
-            throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame");
-        }
-        if (isLocallyClosed())
-        {
-            session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback());
-            throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a locally closed stream");
-        }
-
-        // Cannot update the close state here, because the data that we send may
-        // be flow controlled, so we need the stream to update the window size.
-        session.data(this, dataInfo, dataInfo.getTimeout(), dataInfo.getUnit(), new StreamCallback(callback));
-    }
-
-    @Override
-    public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        FutureCallback result = new FutureCallback();
-        headers(headersInfo, result);
-        if (headersInfo.getTimeout() > 0)
-            result.get(headersInfo.getTimeout(), headersInfo.getUnit());
-        else
-            result.get();
-    }
-
-    @Override
-    public void headers(HeadersInfo headersInfo, Callback callback)
-    {
-        notIdle();
-        if (!canSend())
-        {
-            session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback());
-            throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame");
-        }
-        if (isLocallyClosed())
-        {
-            session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR), new StreamCallback());
-            throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream");
-        }
-
-        updateCloseState(headersInfo.isClose(), true);
-        HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders());
-        session.control(this, frame, headersInfo.getTimeout(), headersInfo.getUnit(), new StreamCallback(callback));
-    }
-
-    @Override
-    public boolean isUnidirectional()
-    {
-        return associatedStream != null;
-    }
-
-    @Override
-    public boolean isReset()
-    {
-        return reset;
-    }
-
-    @Override
-    public boolean isHalfClosed()
-    {
-        CloseState closeState = this.closeState;
-        return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.REMOTELY_CLOSED || closeState == CloseState.CLOSED;
-    }
-
-    @Override
-    public boolean isClosed()
-    {
-        return closeState == CloseState.CLOSED;
-    }
-
-    private boolean isLocallyClosed()
-    {
-        CloseState closeState = this.closeState;
-        return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.CLOSED;
-    }
-
-    private boolean isRemotelyClosed()
-    {
-        CloseState closeState = this.closeState;
-        return closeState == CloseState.REMOTELY_CLOSED || closeState == CloseState.CLOSED;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("stream=%d v%d windowSize=%d reset=%s prio=%d %s %s", getId(), session.getVersion(),
-                getWindowSize(), isReset(), priority, openState, closeState);
-    }
-
-    private boolean canSend()
-    {
-        OpenState openState = this.openState;
-        return openState == OpenState.SYN_SENT || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
-    }
-
-    private boolean canReceive()
-    {
-        OpenState openState = this.openState;
-        return openState == OpenState.SYN_RECV || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
-    }
-
-    private enum OpenState
-    {
-        SYN_SENT, SYN_RECV, REPLY_SENT, REPLY_RECV
-    }
-
-    private enum CloseState
-    {
-        OPENED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED
-    }
-
-    private class StreamCallback implements Callback
-    {
-        private final Callback callback;
-
-        private StreamCallback()
-        {
-            this(Callback.Adapter.INSTANCE);
-        }
-
-        private StreamCallback(Callback callback)
-        {
-            this.callback = callback;
-        }
-
-        @Override
-        public void succeeded()
-        {
-            callback.succeeded();
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-            close();
-            callback.failed(x);
-        }
-    }
-
-    private class StreamPromise implements Promise<Stream>
-    {
-        private final Promise<Stream> promise;
-
-        public StreamPromise(Promise<Stream> promise)
-        {
-            this.promise = promise;
-        }
-
-        @Override
-        public void succeeded(Stream result)
-        {
-            promise.succeeded(result);
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-            close();
-            promise.failed(x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java
deleted file mode 100644
index cb1c400..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StreamException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import org.eclipse.jetty.spdy.api.StreamStatus;
-
-public class StreamException extends RuntimeException
-{
-    private final int streamId;
-    private final StreamStatus streamStatus;
-
-    public StreamException(int streamId, StreamStatus streamStatus)
-    {
-        this.streamId = streamId;
-        this.streamStatus = streamStatus;
-    }
-
-    public StreamException(int streamId, StreamStatus streamStatus, String message)
-    {
-        super(message);
-        this.streamId = streamId;
-        this.streamStatus = streamStatus;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public StreamStatus getStreamStatus()
-    {
-        return streamStatus;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java
deleted file mode 100644
index 163f344..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ByteBufferDataInfo.java
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-
-/**
- * <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p>
- */
-public class ByteBufferDataInfo extends DataInfo
-{
-    private final ByteBuffer buffer;
-    private final int length;
-
-    public ByteBufferDataInfo(ByteBuffer buffer, boolean close)
-    {
-        this(0, TimeUnit.SECONDS, buffer, close);
-    }
-
-    public ByteBufferDataInfo(long timeout, TimeUnit unit, ByteBuffer buffer, boolean close)
-    {
-        super(timeout, unit, close);
-        this.buffer = buffer;
-        this.length = buffer.remaining();
-    }
-
-    @Override
-    public int length()
-    {
-        return length;
-    }
-
-    @Override
-    public int available()
-    {
-        return buffer.remaining();
-    }
-
-    @Override
-    public int readInto(ByteBuffer output)
-    {
-        int space = output.remaining();
-        if (available() > space)
-        {
-            int limit = buffer.limit();
-            buffer.limit(buffer.position() + space);
-            output.put(buffer);
-            buffer.limit(limit);
-        }
-        else
-        {
-            space = buffer.remaining();
-            output.put(buffer);
-        }
-        return space;
-    }
-
-    @Override
-    public int readInto(byte[] bytes, int offset, int length)
-    {
-        int available = available();
-        if (available < length)
-            length = available;
-        buffer.get(bytes, offset, length);
-        return length;
-    }
-
-    @Override
-    protected ByteBuffer allocate(int size)
-    {
-        return buffer.isDirect() ? ByteBuffer.allocateDirect(size) : super.allocate(size);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java
deleted file mode 100644
index 05cd88e..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/BytesDataInfo.java
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.TimeUnit;
-
-/**
- * <p>Specialized {@link DataInfo} for byte array content.</p>
- */
-public class BytesDataInfo extends DataInfo
-{
-    private final byte[] bytes;
-    private final int offset;
-    private final int length;
-    private int index;
-
-    public BytesDataInfo(byte[] bytes, boolean close)
-    {
-        this(0, TimeUnit.SECONDS, bytes, close);
-    }
-
-    public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, boolean close)
-    {
-        this(timeout, unit, bytes, 0, bytes.length, close);
-    }
-
-    public BytesDataInfo(long timeout, TimeUnit unit, byte[] bytes, int offset, int length, boolean close)
-    {
-        super(timeout, unit, close);
-        this.bytes = bytes;
-        this.offset = offset;
-        this.length = length;
-        this.index = offset;
-    }
-
-    @Override
-    public int length()
-    {
-        return length;
-    }
-
-    @Override
-    public int available()
-    {
-        return length - index + offset;
-    }
-
-    @Override
-    public int readInto(ByteBuffer output)
-    {
-        int space = output.remaining();
-        int chunk = Math.min(available(), space);
-        output.put(bytes, index, chunk);
-        index += chunk;
-        return chunk;
-    }
-
-    @Override
-    public int readInto(byte[] bytes, int offset, int length)
-    {
-        int chunk = Math.min(available(), length);
-        System.arraycopy(this.bytes, index, bytes, offset, chunk);
-        index += chunk;
-        return chunk;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java
deleted file mode 100644
index c2c1018..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/DataInfo.java
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * <p>A container for DATA frames metadata and content bytes.</p>
- * <p>Specialized subclasses (like {@link StringDataInfo}) may be used by applications
- * to send specific types of content.</p>
- * <p>Applications may send multiple instances of {@link DataInfo}, usually of the same
- * type, via {@link Stream#data(DataInfo)}. The last instance must have the
- * {@link #isClose() close flag} set, so that the client knows that no more content is
- * expected.</p>
- * <p>Receivers of {@link DataInfo} via {@link StreamFrameListener#onData(Stream, DataInfo)}
- * have two different APIs to read the data content bytes: a {@link #readInto(ByteBuffer) read}
- * API that does not interact with flow control, and a {@link #consumeInto(ByteBuffer) drain}
- * API that interacts with flow control.</p>
- * <p>Flow control is defined so that when the sender wants to sends a number of bytes larger
- * than the {@link Settings.ID#INITIAL_WINDOW_SIZE} value, it will stop sending as soon as it
- * has sent a number of bytes equal to the window size. The receiver has to <em>consume</em>
- * the data bytes that it received in order to tell the sender to send more bytes.</p>
- * <p>Consuming the data bytes can be done only via {@link #consumeInto(ByteBuffer)} or by a combination
- * of {@link #readInto(ByteBuffer)} and {@link #consume(int)} (possibly at different times).</p>
- */
-public abstract class DataInfo extends Info
-{
-    /**
-     * <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
-     *
-     * @see #isClose()
-     * @see #getFlags()
-     */
-    public final static byte FLAG_CLOSE = 1;
-
-    private final AtomicInteger consumed = new AtomicInteger();
-    private boolean close;
-
-    /**
-     * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
-     *
-     * @param close the value of the close flag
-     */
-    public DataInfo(boolean close)
-    {
-        setClose(close);
-    }
-
-    /**
-     * <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
-     *
-     * @param timeout
-     * @param unit
-     * @param close the value of the close flag
-     */
-    protected DataInfo(long timeout, TimeUnit unit, boolean close)
-    {
-        super(timeout, unit);
-        this.close = close;
-    }
-
-    /**
-     * @return the value of the close flag
-     * @see #setClose(boolean)
-     */
-    public boolean isClose()
-    {
-        return close;
-    }
-
-    /**
-     * @param close the value of the close flag
-     * @see #isClose()
-     */
-    public void setClose(boolean close)
-    {
-        this.close = close;
-    }
-
-    /**
-     * @return the close and compress flags as integer
-     * @see #FLAG_CLOSE
-     */
-    public byte getFlags()
-    {
-        return isClose() ? FLAG_CLOSE : 0;
-    }
-
-    /**
-     * @return the total number of content bytes
-     * @see #available()
-     */
-    public abstract int length();
-
-    /**
-     * <p>Returns the available content bytes that can be read via {@link #readInto(ByteBuffer)}.</p>
-     * <p>Each invocation to {@link #readInto(ByteBuffer)} modifies the value returned by this method,
-     * until no more content bytes are available.</p>
-     *
-     * @return the available content bytes
-     * @see #readInto(ByteBuffer)
-     */
-    public abstract int available();
-
-    /**
-     * <p>Copies the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p>
-     * <p>If the given {@link ByteBuffer} cannot contain the whole content of this {@link DataInfo}
-     * then after the read {@link #available()} will return a positive value, and further content
-     * may be retrieved by invoking again this method with a new output buffer.</p>
-     *
-     * @param output the {@link ByteBuffer} to copy the bytes into
-     * @return the number of bytes copied
-     * @see #available()
-     * @see #consumeInto(ByteBuffer)
-     */
-    public abstract int readInto(ByteBuffer output);
-
-    /**
-     * <p>Copies the content bytes of this {@link DataInfo} into the given byte array.</p>
-     * <p>If the given byte array cannot contain the whole content of this {@link DataInfo}
-     * then after the read {@link #available()} will return a positive value, and further content
-     * may be retrieved by invoking again this method with a new byte array.</p>
-     *
-     * @param bytes the byte array to copy the bytes into
-     * @param offset the index of the byte array to start copying
-     * @param length the number of bytes to copy
-     * @return the number of bytes copied
-     */
-    public abstract int readInto(byte[] bytes, int offset, int length);
-
-    /**
-     * <p>Reads and consumes the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p>
-     *
-     * @param output the {@link ByteBuffer} to copy the bytes into
-     * @return the number of bytes copied
-     * @see #consume(int)
-     */
-    public int consumeInto(ByteBuffer output)
-    {
-        int read = readInto(output);
-        consume(read);
-        return read;
-    }
-
-    /**
-     * <p>Reads and consumes the content bytes of this {@link DataInfo} into the given byte array,
-     * starting from index {@code offset} for {@code length} bytes.</p>
-     *
-     * @param bytes the byte array to copy the bytes into
-     * @param offset the offset of the byte array to start copying
-     * @param length the number of bytes to copy
-     * @return the number of bytes copied
-     */
-    public int consumeInto(byte[] bytes, int offset, int length)
-    {
-        int read = readInto(bytes, offset, length);
-        consume(read);
-        return read;
-    }
-
-    /**
-     * <p>Consumes the given number of bytes from this {@link DataInfo}.</p>
-     *
-     * @param delta the number of bytes consumed
-     */
-    public void consume(int delta)
-    {
-        if (delta < 0)
-            throw new IllegalArgumentException();
-        int read = length() - available();
-        int newConsumed = consumed() + delta;
-//        if (newConsumed > read)
-//            throw new IllegalStateException("Consuming without reading: consumed " + newConsumed + " but only read " + read);
-        consumed.addAndGet(delta);
-    }
-
-    /**
-     * @return the number of bytes consumed
-     */
-    public int consumed()
-    {
-        return consumed.get();
-    }
-
-    /**
-     *
-     * @param charset the charset used to convert the bytes
-     * @param consume whether to consume the content
-     * @return a String with the content of this {@link DataInfo}
-     */
-    public String asString(String charset, boolean consume)
-    {
-        return asString(Charset.forName(charset), consume);
-    }
-
-    /**
-     *
-     * @param charset the charset used to convert the bytes
-     * @param consume whether to consume the content
-     * @return a String with the content of this {@link DataInfo}
-     */
-    public String asString(Charset charset, boolean consume)
-    {
-        ByteBuffer buffer = asByteBuffer(consume);
-        return charset.decode(buffer).toString();
-    }
-
-    /**
-     * @return a byte array with the content of this {@link DataInfo}
-     * @param consume whether to consume the content
-     */
-    public byte[] asBytes(boolean consume)
-    {
-        ByteBuffer buffer = asByteBuffer(consume);
-        byte[] result = new byte[buffer.remaining()];
-        buffer.get(result);
-        return result;
-    }
-
-    /**
-     * @return a {@link ByteBuffer} with the content of this {@link DataInfo}
-     * @param consume whether to consume the content
-     */
-    public ByteBuffer asByteBuffer(boolean consume)
-    {
-        ByteBuffer buffer = allocate(available());
-        if (consume)
-            consumeInto(buffer);
-        else
-            readInto(buffer);
-        buffer.flip();
-        return buffer;
-    }
-
-    protected ByteBuffer allocate(int size)
-    {
-        return ByteBuffer.allocate(size);
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("DATA @%x available=%d consumed=%d close=%b", hashCode(), available(), consumed(), isClose());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java
deleted file mode 100644
index e97f6c5..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayInfo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A GoAwayInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in
- * future versions when we need to pass more info to the methods having a {@link GoAwayInfo} parameter.
- */
-public class GoAwayInfo extends Info
-{
-    public GoAwayInfo(long timeout, TimeUnit unit)
-    {
-        super(timeout, unit);
-    }
-
-    public GoAwayInfo()
-    {
-        super();
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java
deleted file mode 100644
index 42f17cc..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/GoAwayResultInfo.java
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-/**
- * <p>A container for GOAWAY frames metadata: the last good stream id and
- * the session status.</p>
- */
-public class GoAwayResultInfo
-{
-    private final int lastStreamId;
-    private final SessionStatus sessionStatus;
-
-    /**
-     * <p>Creates a new {@link GoAwayResultInfo} with the given last good stream id and session status</p>
-     *
-     * @param lastStreamId  the last good stream id
-     * @param sessionStatus the session status
-     */
-    public GoAwayResultInfo(int lastStreamId, SessionStatus sessionStatus)
-    {
-        this.lastStreamId = lastStreamId;
-        this.sessionStatus = sessionStatus;
-    }
-
-    /**
-     * @return the last good stream id
-     */
-    public int getLastStreamId()
-    {
-        return lastStreamId;
-    }
-
-    /**
-     * @return the session status
-     */
-    public SessionStatus getSessionStatus()
-    {
-        return sessionStatus;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java
deleted file mode 100644
index 2b5e5ce..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/HeadersInfo.java
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>A container for HEADERS frame metadata and headers.</p>
- */
-public class HeadersInfo extends Info
-{
-    /**
-     * <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p>
-     *
-     * @see #isClose()
-     * @see #getFlags()
-     */
-    public static final byte FLAG_CLOSE = 1;
-    /**
-     * <p>Flag that indicates that the compression of the stream must be reset.</p>
-     *
-     * @see #isResetCompression()
-     * @see #getFlags()
-     */
-    public static final byte FLAG_RESET_COMPRESSION = 2;
-
-    private final boolean close;
-    private final boolean resetCompression;
-    private final Fields headers;
-
-    /**
-     * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and no reset
-     * compression flag</p>
-     *
-     * @param headers the {@link Fields}
-     * @param close   the value of the close flag
-     */
-    public HeadersInfo(Fields headers, boolean close)
-    {
-        this(headers, close, false);
-    }
-
-    /**
-     * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset
-     * compression flag</p>
-     *
-     * @param headers          the {@link Fields}
-     * @param close            the value of the close flag
-     * @param resetCompression the value of the reset compression flag
-     */
-    public HeadersInfo(Fields headers, boolean close, boolean resetCompression)
-    {
-        this.headers = headers;
-        this.close = close;
-        this.resetCompression = resetCompression;
-    }
-
-    /**
-     * <p>Creates a new {@link HeadersInfo} instance with the given headers, the given close flag and the given reset
-     * compression flag</p>
-     *
-     * @param timeout          the operation's timeout
-     * @param unit             the timeout's unit
-     * @param headers          the {@link Fields}
-     * @param close            the value of the close flag
-     * @param resetCompression the value of the reset compression flag
-     */
-    public HeadersInfo(long timeout, TimeUnit unit, boolean close, boolean resetCompression, Fields headers)
-    {
-        super(timeout, unit);
-        this.close = close;
-        this.resetCompression = resetCompression;
-        this.headers = headers;
-    }
-
-    /**
-     * @return the value of the close flag
-     */
-    public boolean isClose()
-    {
-        return close;
-    }
-
-    /**
-     * @return the value of the reset compression flag
-     */
-    public boolean isResetCompression()
-    {
-        return resetCompression;
-    }
-
-    /**
-     * @return the {@link Fields}
-     */
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    /**
-     * @return the close and reset compression flags as integer
-     * @see #FLAG_CLOSE
-     * @see #FLAG_RESET_COMPRESSION
-     */
-    public byte getFlags()
-    {
-        byte flags = isClose() ? FLAG_CLOSE : 0;
-        flags += isResetCompression() ? FLAG_RESET_COMPRESSION : 0;
-        return flags;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("HEADER close=%b %s", close, headers);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java
deleted file mode 100644
index 315a957..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Info.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A base class for all *Info classes providing timeout and unit and api to access them
- */
-public class Info
-{
-    private final long timeout;
-    private final TimeUnit unit;
-
-    public Info(long timeout, TimeUnit unit)
-    {
-        this.timeout = timeout;
-        this.unit = unit;
-    }
-
-    public Info()
-    {
-        timeout = 0;
-        unit = TimeUnit.SECONDS;
-    }
-
-    public long getTimeout()
-    {
-        return timeout;
-    }
-
-    public TimeUnit getUnit()
-    {
-        return unit;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java
deleted file mode 100644
index 0cc6935..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingInfo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * A PingInfo container. Currently adding nothing to it's base class, but serves to keep the api unchanged in
- * future versions when we need to pass more info to the methods having a {@link PingInfo} parameter.
- */
-public class PingInfo extends Info
-{
-    public PingInfo(long timeout, TimeUnit unit)
-    {
-        super(timeout, unit);
-    }
-
-    public PingInfo()
-    {
-        this(0, TimeUnit.SECONDS);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java
deleted file mode 100644
index ef71eb3..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PingResultInfo.java
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-/**
- * <p>A container for PING frames data.</p>
- */
-public class PingResultInfo
-{
-    private final int pingId;
-
-    /**
-     * <p>Creates a {@link PingResultInfo} with the given ping id</p>
-     * @param pingId the ping id
-     */
-    public PingResultInfo(int pingId)
-    {
-        this.pingId = pingId;
-    }
-
-    /**
-     * @return the ping id
-     */
-    public int getPingId()
-    {
-        return pingId;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java
deleted file mode 100644
index 8f7598b..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/PushInfo.java
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>A container for PUSH_SYN_STREAM frames metadata and data.</p>
- */
-public class PushInfo extends Info
-{
-    /**
-     * <p>Flag that indicates that this {@link PushInfo} is the last frame in the stream.</p>
-     *
-     * @see #isClose()
-     * @see #getFlags()
-     */
-    public static final byte FLAG_CLOSE = 1;
-
-    private final boolean close;
-    private final Fields headers;
-
-    /**
-     * <p>Creates a {@link PushInfo} instance with the given headers and the given close flag,
-     * not unidirectional, without associated stream, and with default priority.</p>
-     *
-     * @param headers the {@link Fields}
-     * @param close the value of the close flag
-     */
-    public PushInfo(Fields headers, boolean close)
-    {
-        this(0, TimeUnit.SECONDS, headers, close);
-        // either builder or setters for timeout
-    }
-
-    /**
-     * <p>
-     * Creates a {@link PushInfo} instance with the given headers, the given close flag and with the given priority.
-     * </p>
-     * @param timeout the timeout value
-     * @param unit the TimeUnit of the timeout
-     * @param headers
- *            the {@link Fields}
-     * @param close
-     */
-    public PushInfo(long timeout, TimeUnit unit, Fields headers, boolean close)
-    {
-        super(timeout, unit);
-        this.close = close;
-        this.headers = headers;
-    }
-
-    /**
-     * @return the value of the close flag
-     */
-    public boolean isClose()
-    {
-        return close;
-    }
-
-    /**
-     * @return the {@link Fields}
-     */
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    /**
-     * @return the close flag as integer
-     * @see #FLAG_CLOSE
-     */
-    public byte getFlags()
-    {
-        return isClose() ? FLAG_CLOSE : 0;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("SYN push close=%b headers=%s", close, headers);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java
deleted file mode 100644
index 6586eeb..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/ReplyInfo.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>A container for SYN_REPLY frames metadata and headers.</p>
- */
-public class ReplyInfo extends Info
-{
-    /**
-     * <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p>
-     *
-     * @see #isClose()
-     * @see #getFlags()
-     */
-    public static final byte FLAG_CLOSE = 1;
-
-    private final Fields headers;
-    private final boolean close;
-
-    /**
-     * <p>Creates a new {@link ReplyInfo} instance with empty headers and the given close flag.</p>
-     *
-     * @param close the value of the close flag
-     */
-    public ReplyInfo(boolean close)
-    {
-        this(new Fields(), close);
-    }
-
-    /**
-     * <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p>
-     *
-     * @param headers the {@link Fields}
-     * @param close   the value of the close flag
-     */
-    public ReplyInfo(Fields headers, boolean close)
-    {
-        this(0, TimeUnit.SECONDS, headers, close);
-    }
-
-    /**
-     * <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p>
-     *
-     * @param timeout the timeout
-     * @param unit    the time unit for the timeout
-     * @param headers the {@link Fields}
-     * @param close   the value of the close flag
-     */
-    public ReplyInfo(long timeout, TimeUnit unit, Fields headers, boolean close)
-    {
-        super(timeout, unit);
-        this.headers = headers;
-        this.close = close;
-    }
-
-    /**
-     * @return the {@link Fields}
-     */
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    /**
-     * @return the value of the close flag
-     */
-    public boolean isClose()
-    {
-        return close;
-    }
-
-    /**
-     * @return the close and reset compression flags as integer
-     * @see #FLAG_CLOSE
-     */
-    public byte getFlags()
-    {
-        return isClose() ? FLAG_CLOSE : 0;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("REPLY close=%b %s", close, headers);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java
deleted file mode 100644
index bbf1fc9..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/RstInfo.java
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * <p>A container for RST_STREAM frames data: the stream id and the stream status.</p>
- */
-public class RstInfo extends Info
-{
-    private final int streamId;
-    private final StreamStatus streamStatus;
-
-    /**
-     * <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
-     *
-     * @param timeout      the operation's timeout
-     * @param unit         the timeout's unit
-     * @param streamId     the stream id
-     * @param streamStatus the stream status
-     */
-    public RstInfo(long timeout, TimeUnit unit, int streamId, StreamStatus streamStatus)
-    {
-        super(timeout, unit);
-        this.streamId = streamId;
-        this.streamStatus = streamStatus;
-    }
-
-    /**
-     * <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
-     *
-     * @param streamId
-     * @param streamStatus
-     */
-    public RstInfo(int streamId, StreamStatus streamStatus)
-    {
-        this(0, TimeUnit.SECONDS, streamId, streamStatus);
-    }
-
-    /**
-     * @return the stream id
-     */
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    /**
-     * @return the stream status
-     */
-    public StreamStatus getStreamStatus()
-    {
-        return streamStatus;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("RST stream=%d %s", streamId, streamStatus);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java
deleted file mode 100644
index 9374843..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDY.java
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-/**
- * <p>Helper class that holds useful SPDY constants.</p>
- */
-public class SPDY
-{
-    /**
-     * <p>Constant that indicates the version 2 of the SPDY protocol</p>
-     */
-    public static final short V2 = 2;
-
-    /**
-     * <p>Constant that indicates the version 3 of the SPDY protocol</p>
-     */
-    public static final short V3 = 3;
-
-    private SPDY()
-    {
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java
deleted file mode 100644
index 0df87c8..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SPDYException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-/**
- * <p>An unrecoverable exception that signals to the application that
- * something wrong happened.</p>
- */
-public class SPDYException extends RuntimeException
-{
-    public SPDYException()
-    {
-    }
-
-    public SPDYException(String message)
-    {
-        super(message);
-    }
-
-    public SPDYException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public SPDYException(Throwable cause)
-    {
-        super(cause);
-    }
-
-    public SPDYException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
-    {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java
deleted file mode 100644
index 5841551..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Session.java
+++ /dev/null
@@ -1,261 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.net.InetSocketAddress;
-import java.util.EventListener;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Promise;
-
-/**
- * <p>A {@link Session} represents the client-side endpoint of a SPDY connection to a single origin server.</p>
- * <p>Once a {@link Session} has been obtained, it can be used to open SPDY streams:</p>
- * <pre>
- * Session session = ...;
- * SynInfo synInfo = new SynInfo(true);
- * session.push(synInfo, new Stream.FrameListener.Adapter()
- * {
- *     public void onReply(Stream stream, ReplyInfo replyInfo)
- *     {
- *         // Stream reply received
- *     }
- * });
- * </pre>
- * <p>A {@link Session} is the active part of the endpoint, and by calling its API applications can generate
- * events on the connection; conversely {@link SessionFrameListener} is the passive part of the endpoint, and
- * has callbacks that are invoked when events happen on the connection.</p>
- *
- * @see SessionFrameListener
- */
-public interface Session
-{
-    /**
-     * @return the SPDY protocol version used by this session
-     */
-    public short getVersion();
-
-    /**
-     * <p>Registers the given {@code listener} to be notified of session events.</p>
-     *
-     * @param listener the listener to register
-     * @see #removeListener(Listener)
-     */
-    public void addListener(Listener listener);
-
-    /**
-     * <p>Deregisters the give {@code listener} from being notified of session events.</p>
-     *
-     * @param listener the listener to deregister
-     * @see #addListener(Listener)
-     */
-    public void removeListener(Listener listener);
-
-    /**
-     * <p>Sends a SYN_FRAME to create a new {@link Stream SPDY stream}.</p>
-     * <p>Callers may use the returned Stream for example, to send data frames.</p>
-     *
-     * @param synInfo  the metadata to send on stream creation
-     * @param listener the listener to invoke when events happen on the stream just created
-     * @return the stream that will be created
-     * @see #syn(SynInfo, StreamFrameListener, Promise)
-     */
-    public Stream syn(SynInfo synInfo, StreamFrameListener listener) throws ExecutionException, InterruptedException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a SYN_FRAME to create a new {@link Stream SPDY stream}.</p>
-     * <p>Callers may pass a non-null completion callback to be notified of when the
-     * stream has been created and use the stream, for example, to send data frames.</p>
-     *
-     *
-     * @param synInfo  the metadata to send on stream creation
-     * @param listener the listener to invoke when events happen on the stream just created
-     * @param promise  the completion callback that gets notified of stream creation
-     * @see #syn(SynInfo, StreamFrameListener)
-     */
-    public void syn(SynInfo synInfo, StreamFrameListener listener, Promise<Stream> promise);
-
-    /**
-     * <p>Sends synchronously a RST_STREAM to abort a stream.</p>
-     *
-     * @param rstInfo the metadata to reset the stream
-     * @see #rst(RstInfo, Callback)
-     */
-    public void rst(RstInfo rstInfo) throws InterruptedException, ExecutionException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a RST_STREAM to abort a stream.</p>
-     * <p>Callers may pass a non-null completion callback to be notified of when the
-     * reset has been actually sent.</p>
-     *
-     * @param rstInfo the metadata to reset the stream
-     * @param callback the completion callback that gets notified of reset's send
-     * @see #rst(RstInfo)
-     */
-    public void rst(RstInfo rstInfo, Callback callback);
-
-    /**
-     * <p>Sends synchronously a SETTINGS to configure the SPDY connection.</p>
-     *
-     * @param settingsInfo the metadata to send
-     * @see #settings(SettingsInfo, Callback)
-     */
-    public void settings(SettingsInfo settingsInfo) throws ExecutionException, InterruptedException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a SETTINGS to configure the SPDY connection.</p>
-     * <p>Callers may pass a non-null completion callback to be notified of when the
-     * settings has been actually sent.</p>
-     *
-     *
-     * @param settingsInfo the metadata to send
-     * @param callback      the completion callback that gets notified of settings' send
-     * @see #settings(SettingsInfo)
-     */
-    public void settings(SettingsInfo settingsInfo, Callback callback);
-
-    /**
-     * <p>Sends synchronously a PING, normally to measure round-trip time.</p>
-     *
-     * @see #ping(PingInfo, Promise)
-     * @param pingInfo
-     */
-    public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a PING, normally to measure round-trip time.</p>
-     * <p>Callers may pass a non-null completion callback to be notified of when the
-     * ping has been actually sent.</p>
-     *
-     * @param pingInfo
-     * @param promise the completion callback that gets notified of ping's send
-     * @see #ping(PingInfo)
-     */
-    public void ping(PingInfo pingInfo, Promise<PingResultInfo> promise);
-
-    /**
-     * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p>
-     *
-     * @see #goAway(GoAwayInfo, Callback)
-     * @param goAwayInfo
-     */
-    public void goAway(GoAwayInfo goAwayInfo) throws ExecutionException, InterruptedException, TimeoutException;
-
-    /**
-     * <p>Closes gracefully this session, sending a GO_AWAY frame and then closing the TCP connection.</p>
-     * <p>Callers may pass a non-null completion callback to be notified of when the
-     * go away has been actually sent.</p>
-     *
-     * @param goAwayInfo
-     * @param callback the completion callback that gets notified of go away's send
-     * @see #goAway(GoAwayInfo)
-     */
-    public void goAway(GoAwayInfo goAwayInfo, Callback callback);
-
-    /**
-     * @return a snapshot of the streams currently active in this session
-     * @see #getStream(int)
-     */
-    public Set<Stream> getStreams();
-
-    /**
-     * @param streamId the id of the stream to retrieve
-     * @return the stream with the given stream id
-     * @see #getStreams()
-     */
-    public Stream getStream(int streamId);
-
-    /**
-     * @param key the attribute key
-     * @return an arbitrary object associated with the given key to this session
-     * @see #setAttribute(String, Object)
-     */
-    public Object getAttribute(String key);
-
-    /**
-     * @param key   the attribute key
-     * @param value an arbitrary object to associate with the given key to this session
-     * @see #getAttribute(String)
-     * @see #removeAttribute(String)
-     */
-    public void setAttribute(String key, Object value);
-
-    /**
-     * @param key the attribute key
-     * @return the arbitrary object associated with the given key to this session
-     * @see #setAttribute(String, Object)
-     */
-    public Object removeAttribute(String key);
-
-    /**
-     * @return the local address of the underlying endpoint
-     */
-    public InetSocketAddress getLocalAddress();
-
-    /**
-     * @return the remote address of the underlying endpoint
-     */
-    public InetSocketAddress getRemoteAddress();
-
-    /**
-     * <p>Super interface for listeners with callbacks that are invoked on specific session events.</p>
-     */
-    public interface Listener extends EventListener
-    {
-    }
-
-    /**
-     * <p>Specialized listener that is invoked upon creation and removal of streams.</p>
-     */
-    public interface StreamListener extends Listener
-    {
-        /**
-         * <p>Callback invoked when a new SPDY stream is created.</p>
-         *
-         * @param stream the stream just created
-         */
-        public void onStreamCreated(Stream stream);
-
-        /**
-         * <p>Callback invoked when a SPDY stream is closed.</p>
-         *
-         * @param stream the stream just closed.
-         */
-        public void onStreamClosed(Stream stream);
-
-        /**
-         * <p>Empty implementation of {@link StreamListener}.</p>
-         */
-        public static class Adapter implements StreamListener
-        {
-            @Override
-            public void onStreamCreated(Stream stream)
-            {
-            }
-
-            @Override
-            public void onStreamClosed(Stream stream)
-            {
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java
deleted file mode 100644
index 0291d74..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionFrameListener.java
+++ /dev/null
@@ -1,163 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.EventListener;
-
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>A {@link SessionFrameListener} is the passive counterpart of a {@link Session} and receives events happening
- * on a SPDY session.</p>
- *
- * @see Session
- */
-public interface SessionFrameListener extends EventListener
-{
-    /**
-     * <p>Callback invoked when a request to create a stream has been received.</p>
-     * <p>Application code should implement this method and reply to the stream creation, eventually
-     * sending data:</p>
-     * <pre>
-     * public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-     * {
-     *     // Do something with the metadata contained in synInfo
-     *
-     *     if (stream.isHalfClosed()) // The other peer will not send data
-     *     {
-     *         stream.reply(new ReplyInfo(false));
-     *         stream.data(new StringDataInfo("foo", true));
-     *         return null; // Not interested in further stream events
-     *     }
-     *
-     *     ...
-     * }
-     * </pre>
-     * <p>Alternatively, if the stream creation requires reading data sent from the other peer:</p>
-     * <pre>
-     * public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-     * {
-     *     // Do something with the metadata contained in synInfo
-     *
-     *     if (!stream.isHalfClosed()) // The other peer will send data
-     *     {
-     *         stream.reply(new ReplyInfo(true));
-     *         return new Stream.FrameListener.Adapter() // Interested in stream events
-     *         {
-     *             public void onData(Stream stream, DataInfo dataInfo)
-     *             {
-     *                 // Do something with the incoming data in dataInfo
-     *             }
-     *         };
-     *     }
-     *
-     *     ...
-     * }
-     * </pre>
-     *
-     * @param stream  the stream just created
-     * @param synInfo the metadata sent on stream creation
-     * @return a listener for stream events, or null if there is no interest in being notified of stream events
-     */
-    public StreamFrameListener onSyn(Stream stream, SynInfo synInfo);
-
-    /**
-     * <p>Callback invoked when a stream error happens.</p>
-     *
-     * @param session the session
-     * @param rstInfo the metadata of the stream error
-     */
-    public void onRst(Session session, RstInfo rstInfo);
-
-    /**
-     * <p>Callback invoked when a request to configure the SPDY connection has been received.</p>
-     *
-     * @param session the session
-     * @param settingsInfo the metadata sent to configure
-     */
-    public void onSettings(Session session, SettingsInfo settingsInfo);
-
-    /**
-     * <p>Callback invoked when a ping request has completed its round-trip.</p>
-     *
-     * @param session the session
-     * @param pingResultInfo the metadata received
-     */
-    public void onPing(Session session, PingResultInfo pingResultInfo);
-
-    /**
-     * <p>Callback invoked when the other peer signals that it is closing the connection.</p>
-     *
-     * @param session the session
-     * @param goAwayResultInfo the metadata sent
-     */
-    public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo);
-
-    /**
-     * <p>Callback invoked when an exception is thrown during the processing of an event on a
-     * SPDY session.</p>
-     * <p>Examples of such conditions are invalid frames received, corrupted headers compression state, etc.</p>
-     *
-     * @param session the session
-     * @param x the exception that caused the event processing failure
-     */
-    public void onFailure(Session session, Throwable x);
-
-
-    /**
-     * <p>Empty implementation of {@link SessionFrameListener}</p>
-     */
-    public static class Adapter implements SessionFrameListener
-    {
-        private static final Logger logger = Log.getLogger(Adapter.class);
-
-        @Override
-        public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-        {
-            return null;
-        }
-
-        @Override
-        public void onRst(Session session, RstInfo rstInfo)
-        {
-        }
-
-        @Override
-        public void onSettings(Session session, SettingsInfo settingsInfo)
-        {
-        }
-
-        @Override
-        public void onPing(Session session, PingResultInfo pingResultInfo)
-        {
-        }
-
-        @Override
-        public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo)
-        {
-        }
-
-        @Override
-        public void onFailure(Session session, Throwable x)
-        {
-            logger.info("", x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java
deleted file mode 100644
index 09e2915..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SessionStatus.java
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * <p>An enumeration of session statuses.</p>
- */
-public enum SessionStatus
-{
-    /**
-     * <p>The session status indicating no errors</p>
-     */
-    OK(0),
-    /**
-     * <p>The session status indicating a protocol error</p>
-     */
-    PROTOCOL_ERROR(1);
-
-    /**
-     * @param code the session status code
-     * @return a {@link SessionStatus} from the given code,
-     * or null if no status exists
-     */
-    public static SessionStatus from(int code)
-    {
-        return Codes.codes.get(code);
-    }
-
-    private final int code;
-
-    private SessionStatus(int code)
-    {
-        this.code = code;
-        Codes.codes.put(code, this);
-    }
-
-    /**
-     * @return the code of this {@link SessionStatus}
-     */
-    public int getCode()
-    {
-        return code;
-    }
-
-    private static class Codes
-    {
-        private static final Map<Integer, SessionStatus> codes = new HashMap<>();
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java
deleted file mode 100644
index 1b09d32..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Settings.java
+++ /dev/null
@@ -1,228 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-public class Settings implements Iterable<Settings.Setting>
-{
-    private final Map<ID, Settings.Setting> settings;
-
-    public Settings()
-    {
-        settings = new HashMap<>();
-    }
-
-    public Settings(Settings original, boolean immutable)
-    {
-        Map<ID, Settings.Setting> copy = new HashMap<>(original.size());
-        copy.putAll(original.settings);
-        settings = immutable ? Collections.unmodifiableMap(copy) : copy;
-    }
-
-    public Setting get(ID id)
-    {
-        return settings.get(id);
-    }
-
-    public void put(Setting setting)
-    {
-        settings.put(setting.id(), setting);
-    }
-
-    public Setting remove(ID id)
-    {
-        return settings.remove(id);
-    }
-
-    public int size()
-    {
-        return settings.size();
-    }
-
-    public void clear()
-    {
-        settings.clear();
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-            return true;
-        if (obj == null || getClass() != obj.getClass())
-            return false;
-        Settings that = (Settings)obj;
-        return settings.equals(that.settings);
-    }
-
-    @Override
-    public int hashCode()
-    {
-        return settings.hashCode();
-    }
-
-    @Override
-    public Iterator<Setting> iterator()
-    {
-        return settings.values().iterator();
-    }
-
-    @Override
-    public String toString()
-    {
-        return settings.toString();
-    }
-
-    public static final class ID
-    {
-        public static final ID UPLOAD_BANDWIDTH = new ID(1);
-        public static final ID DOWNLOAD_BANDWIDTH = new ID(2);
-        public static final ID ROUND_TRIP_TIME = new ID(3);
-        public static final ID MAX_CONCURRENT_STREAMS = new ID(4);
-        public static final ID CURRENT_CONGESTION_WINDOW = new ID(5);
-        public static final ID DOWNLOAD_RETRANSMISSION_RATE = new ID(6);
-        public static final ID INITIAL_WINDOW_SIZE = new ID(7);
-
-        public synchronized static ID from(int code)
-        {
-            ID id = Codes.codes.get(code);
-            if (id == null)
-                id = new ID(code);
-            return id;
-        }
-
-        private final int code;
-
-        private ID(int code)
-        {
-            this.code = code;
-            Codes.codes.put(code, this);
-        }
-
-        public int code()
-        {
-            return code;
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.valueOf(code);
-        }
-
-        private static class Codes
-        {
-            private static final Map<Integer, ID> codes = new HashMap<>();
-        }
-    }
-
-    public static enum Flag
-    {
-        NONE((byte)0),
-        PERSIST((byte)1),
-        PERSISTED((byte)2);
-
-        public static Flag from(byte code)
-        {
-            return Codes.codes.get(code);
-        }
-
-        private final byte code;
-
-        private Flag(byte code)
-        {
-            this.code = code;
-            Codes.codes.put(code, this);
-        }
-
-        public byte code()
-        {
-            return code;
-        }
-
-        private static class Codes
-        {
-            private static final Map<Byte, Flag> codes = new HashMap<>();
-        }
-    }
-
-    public static class Setting
-    {
-        private final ID id;
-        private final Flag flag;
-        private final int value;
-
-        public Setting(ID id, int value)
-        {
-            this(id, Flag.NONE, value);
-        }
-
-        public Setting(ID id, Flag flag, int value)
-        {
-            this.id = id;
-            this.flag = flag;
-            this.value = value;
-        }
-
-        public ID id()
-        {
-            return id;
-        }
-
-        public Flag flag()
-        {
-            return flag;
-        }
-
-        public int value()
-        {
-            return value;
-        }
-
-        @Override
-        public boolean equals(Object obj)
-        {
-            if (this == obj)
-                return true;
-            if (obj == null || getClass() != obj.getClass())
-                return false;
-            Setting that = (Setting)obj;
-            return value == that.value && flag == that.flag && id == that.id;
-        }
-
-        @Override
-        public int hashCode()
-        {
-            int result = id.hashCode();
-            result = 31 * result + flag.hashCode();
-            result = 31 * result + value;
-            return result;
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("[id=%s,flags=%s:value=%d]", id(), flag(), value());
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java
deleted file mode 100644
index c607e1f..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SettingsInfo.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-public class SettingsInfo extends Info
-{
-    public static final byte CLEAR_PERSISTED = 1;
-
-    private final Settings settings;
-    private final boolean clearPersisted;
-
-    public SettingsInfo(Settings settings)
-    {
-        this(0, TimeUnit.SECONDS, settings, false);
-    }
-
-    public SettingsInfo(long timeout, TimeUnit unit, Settings settings, boolean clearPersisted)
-    {
-        super(timeout, unit);
-        this.settings = settings;
-        this.clearPersisted = clearPersisted;
-    }
-
-    public SettingsInfo(Settings settings, boolean clearPersisted)
-    {
-        this(0, TimeUnit.SECONDS, settings, clearPersisted);
-    }
-
-    public boolean isClearPersisted()
-    {
-        return clearPersisted;
-    }
-
-    public byte getFlags()
-    {
-        return isClearPersisted() ? CLEAR_PERSISTED : 0;
-    }
-
-    public Settings getSettings()
-    {
-        return settings;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java
deleted file mode 100644
index a75768b..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/Stream.java
+++ /dev/null
@@ -1,237 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.channels.WritePendingException;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Promise;
-
-/**
- * <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p> <p>Differently from
- * socket streams, where the input and output streams are permanently associated with the socket (and hence with the
- * connection that the socket represents), there can be multiple SPDY streams for a SPDY session.</p> <p>SPDY streams
- * may terminate without this implying that the SPDY session is terminated.</p> <p>If SPDY is used to transport the HTTP
- * protocol, then a SPDY stream maps to a HTTP request/response cycle, and after the request/response cycle is
- * completed, the stream is closed, and other streams may be opened. Differently from HTTP, though, multiple SPDY
- * streams may be opened concurrently on the same SPDY session.</p> <p>Like {@link Session}, {@link Stream} is the
- * active part and by calling its API applications can generate events on the stream; conversely, {@link
- * StreamFrameListener} is the passive part, and its callbacks are invoked when events happen on the stream.</p> <p>A
- * {@link Stream} can send multiple data frames one after the other but implementations use a flow control mechanism
- * that only sends the data frames if the other end has signalled that it can accept the frame.</p> <p>Data frames
- * should be sent sequentially only when the previous frame has been completely sent. The reason for this requirement is
- * to avoid potentially confusing code such as:</p>
- * <pre>
- * // WRONG CODE, DO NOT USE IT
- * final Stream stream = ...;
- * stream.data(StringDataInfo("chunk1", false), 5, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... });
- * stream.data(StringDataInfo("chunk2", true), 1, TimeUnit.SECONDS, new Handler&lt;Void&gt;() { ... });
- * </pre>
- * <p>where the second call to {@link #data(DataInfo, Callback)} has a timeout smaller than the previous call.</p>
- * <p>The behavior of such style of invocations is unspecified (it may even throw an exception - similar to {@link
- * WritePendingException}).</p> <p>The correct sending of data frames is the following:</p>
- * <pre>
- * final Stream stream = ...;
- * ...
- * // Blocking version
- * stream.data(new StringDataInfo("chunk1", false)).get(1, TimeUnit.SECONDS);
- * stream.data(new StringDataInfo("chunk2", true)).get(1, TimeUnit.SECONDS);
- *
- * // Asynchronous version
- * stream.data(new StringDataInfo("chunk1", false), 1, TimeUnit.SECONDS, new Handler.Adapter&lt;Void&gt;()
- * {
- *     public void completed(Void context)
- *     {
- *         stream.data(new StringDataInfo("chunk2", true));
- *     }
- * });
- * </pre>
- *
- * @see StreamFrameListener
- */
-public interface Stream
-{
-    /**
-     * @return the id of this stream
-     */
-    public int getId();
-
-    /**
-     * @return the priority of this stream
-     */
-    public byte getPriority();
-
-    /**
-     * @return the session this stream is associated to
-     */
-    public Session getSession();
-
-    /**
-     * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may use the
-     * returned future to get the pushstream once it got created</p>
-     *
-     * @param pushInfo the metadata to send on stream creation
-     * @return a future containing the stream once it got established
-     * @see #push(PushInfo, Promise)
-     */
-    public Stream push(PushInfo pushInfo) throws InterruptedException, ExecutionException, TimeoutException;
-
-    /**
-     * <p>Initiate a unidirectional spdy pushstream associated to this stream asynchronously<p> <p>Callers may pass a
-     * non-null completion promise to be notified of when the pushstream has been established.</p>
-     *
-     * @param pushInfo the metadata to send on stream creation
-     * @param promise the completion promise that gets notified once the pushstream is established
-     * @see #push(PushInfo)
-     */
-    public void push(PushInfo pushInfo, Promise<Stream> promise);
-
-    /**
-     * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may use the returned
-     * future to wait for the reply to be actually sent.</p>
-     *
-     * @param replyInfo the metadata to send
-     * @see #reply(ReplyInfo, Callback)
-     * @see SessionFrameListener#onSyn(Stream, SynInfo)
-     */
-    public void reply(ReplyInfo replyInfo) throws InterruptedException, ExecutionException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a SYN_REPLY frame in response to a SYN_STREAM frame.</p> <p>Callers may pass a non-null
-     * completion callback to be notified of when the reply has been actually sent.</p>
-     *
-     * @param replyInfo the metadata to send
-     * @param callback  the completion callback that gets notified of reply sent
-     * @see #reply(ReplyInfo)
-     */
-    public void reply(ReplyInfo replyInfo, Callback callback);
-
-    /**
-     * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY
-     * frame.</p> <p>Callers may use the returned future to wait for the data to be actually sent.</p>
-     *
-     * @param dataInfo the metadata to send
-     * @see #data(DataInfo, Callback)
-     * @see #reply(ReplyInfo)
-     */
-    public void data(DataInfo dataInfo) throws InterruptedException, ExecutionException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a DATA frame on this stream.</p> <p>DATA frames should always be sent after a SYN_REPLY
-     * frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the data has been actually
-     * sent.</p>
-     *
-     * @param dataInfo the metadata to send
-     * @param callback the completion callback that gets notified of data sent
-     * @see #data(DataInfo)
-     */
-    public void data(DataInfo dataInfo, Callback callback);
-
-    /**
-     * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a
-     * SYN_REPLY frame.</p> <p>Callers may use the returned future to wait for the headers to be actually sent.</p>
-     *
-     * @param headersInfo the metadata to send
-     * @see #headers(HeadersInfo, Callback)
-     * @see #reply(ReplyInfo)
-     */
-    public void headers(HeadersInfo headersInfo) throws InterruptedException, ExecutionException, TimeoutException;
-
-    /**
-     * <p>Sends asynchronously a HEADER frame on this stream.</p> <p>HEADERS frames should always be sent after a
-     * SYN_REPLY frame.</p> <p>Callers may pass a non-null completion callback to be notified of when the headers have
-     * been actually sent.</p>
-     *
-     * @param headersInfo the metadata to send
-     * @param callback    the completion callback that gets notified of headers sent
-     * @see #headers(HeadersInfo)
-     */
-    public void headers(HeadersInfo headersInfo, Callback callback);
-
-    /**
-     * @return whether this stream is unidirectional or not
-     */
-    public boolean isUnidirectional();
-
-    /**
-     * @return whether this stream has been reset
-     */
-    public boolean isReset();
-
-    /**
-     * @return whether this stream has been closed by both parties
-     * @see #isHalfClosed()
-     */
-    public boolean isClosed();
-
-    /**
-     * @return whether this stream has been closed by one party only
-     * @see #isClosed()
-     */
-    public boolean isHalfClosed();
-
-    /**
-     * @param key the attribute key
-     * @return an arbitrary object associated with the given key to this stream or null if no object can be found for
-     *         the given key.
-     * @see #setAttribute(String, Object)
-     */
-    public Object getAttribute(String key);
-
-    /**
-     * @param key   the attribute key
-     * @param value an arbitrary object to associate with the given key to this stream
-     * @see #getAttribute(String)
-     * @see #removeAttribute(String)
-     */
-    public void setAttribute(String key, Object value);
-
-    /**
-     * @param key the attribute key
-     * @return the arbitrary object associated with the given key to this stream
-     * @see #setAttribute(String, Object)
-     */
-    public Object removeAttribute(String key);
-
-    /**
-     * @return the associated parent stream or null if this is not an associated stream
-     */
-    public Stream getAssociatedStream();
-
-    /**
-     * @return associated child streams or an empty set if no associated streams exist
-     */
-    public Set<Stream> getPushedStreams();
-
-    /**
-     * Get the idle timeout set for this particular stream
-     * @return the idle timeout
-     */
-    public long getIdleTimeout();
-
-    /**
-     * Set an idle timeout for this stream
-     * @param timeout
-     */
-    public void setIdleTimeout(long timeout);
-
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java
deleted file mode 100644
index 08e41bc..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamFrameListener.java
+++ /dev/null
@@ -1,110 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.EventListener;
-
-/**
- * <p>A {@link StreamFrameListener} is the passive counterpart of a {@link Stream} and receives
- * events happening on a SPDY stream.</p>
- *
- * @see Stream
- */
-public interface StreamFrameListener extends EventListener
-{
-    /**
-     * <p>Callback invoked when a reply to a stream creation has been received.</p>
-     * <p>Application code may implement this method to send more data to the other end:</p>
-     * <pre>
-     * public void onReply(Stream stream, ReplyInfo replyInfo)
-     * {
-     *     stream.data(new StringDataInfo("content"), true);
-     * }
-     * </pre>
-     * @param stream the stream
-     * @param replyInfo the reply metadata
-     */
-    public void onReply(Stream stream, ReplyInfo replyInfo);
-
-    /**
-     * <p>Callback invoked when headers are received on a stream.</p>
-     *
-     * @param stream the stream
-     * @param headersInfo the headers metadata
-     */
-    public void onHeaders(Stream stream, HeadersInfo headersInfo);
-
-    /**
-     * <p>Callback invoked when a push syn has been received on a stream.</p>
-     *
-     * @param stream the push stream just created
-     * @param pushInfo the push metadata
-     * @return a listener for stream events or null if there is no interest in being notified of stream events
-     */
-    public StreamFrameListener onPush(Stream stream, PushInfo pushInfo);
-
-    /**
-     * <p>Callback invoked when data bytes are received on a stream.</p>
-     * <p>Implementers should be read or consume the content of the
-     * {@link DataInfo} before this method returns.</p>
-     *
-     * @param stream the stream
-     * @param dataInfo the data metadata
-     */
-    public void onData(Stream stream, DataInfo dataInfo);
-
-    /**
-     * <p>Callback invoked on errors.</p>
-     * @param stream the stream
-     * @param x the failure
-     */
-    public void onFailure(Stream stream, Throwable x);
-
-    /**
-     * <p>Empty implementation of {@link StreamFrameListener}</p>
-     */
-    public static class Adapter implements StreamFrameListener
-    {
-        @Override
-        public void onReply(Stream stream, ReplyInfo replyInfo)
-        {
-        }
-
-        @Override
-        public void onHeaders(Stream stream, HeadersInfo headersInfo)
-        {
-        }
-
-        @Override
-        public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-        {
-            return null;
-        }
-
-        @Override
-        public void onData(Stream stream, DataInfo dataInfo)
-        {
-        }
-
-        @Override
-        public void onFailure(Stream stream, Throwable x)
-        {
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java
deleted file mode 100644
index c18ab1f..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StreamStatus.java
+++ /dev/null
@@ -1,128 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * <p>An enumeration of stream statuses.</p>
- */
-public enum StreamStatus
-{
-    /**
-     * <p>The stream status indicating a protocol error</p>
-     */
-    PROTOCOL_ERROR(1, 1),
-    /**
-     * <p>The stream status indicating that the stream is not valid</p>
-     */
-    INVALID_STREAM(2, 2),
-    /**
-     * <p>The stream status indicating that the stream has been refused</p>
-     */
-    REFUSED_STREAM(3, 3),
-    /**
-     * <p>The stream status indicating that the implementation does not support the SPDY version of the stream</p>
-     */
-    UNSUPPORTED_VERSION(4, 4),
-    /**
-     * <p>The stream status indicating that the stream is no longer needed</p>
-     */
-    CANCEL_STREAM(5, 5),
-    /**
-     * <p>The stream status indicating an implementation error</p>
-     */
-    INTERNAL_ERROR(6, 6),
-    /**
-     * <p>The stream status indicating a flow control error</p>
-     */
-    FLOW_CONTROL_ERROR(7, 7),
-    /**
-     * <p>The stream status indicating a stream opened more than once</p>
-     */
-    STREAM_IN_USE(-1, 8),
-    /**
-     * <p>The stream status indicating data on a stream already closed</p>
-     */
-    STREAM_ALREADY_CLOSED(-1, 9),
-    /**
-     * <p>The stream status indicating credentials not valid</p>
-     */
-    INVALID_CREDENTIALS(-1, 10),
-    /**
-     * <p>The stream status indicating that the implementation could not support a frame too large</p>
-     */
-    FRAME_TOO_LARGE(-1, 11);
-
-    /**
-     * @param version the SPDY protocol version
-     * @param code the stream status code
-     * @return a {@link StreamStatus} from the given version and code,
-     * or null if no such status exists
-     */
-    public static StreamStatus from(short version, int code)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return Codes.v2Codes.get(code);
-            case SPDY.V3:
-                return Codes.v3Codes.get(code);
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private final int v2Code;
-    private final int v3Code;
-
-    private StreamStatus(int v2Code, int v3Code)
-    {
-        this.v2Code = v2Code;
-        if (v2Code >= 0)
-            Codes.v2Codes.put(v2Code, this);
-        this.v3Code = v3Code;
-        if (v3Code >= 0)
-            Codes.v3Codes.put(v3Code, this);
-    }
-
-    /**
-     * @param version the SPDY protocol version
-     * @return the stream status code
-     */
-    public int getCode(short version)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return v2Code;
-            case SPDY.V3:
-                return v3Code;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private static class Codes
-    {
-        private static final Map<Integer, StreamStatus> v2Codes = new HashMap<>();
-        private static final Map<Integer, StreamStatus> v3Codes = new HashMap<>();
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java
deleted file mode 100644
index 793c32a..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/StringDataInfo.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.TimeUnit;
-
-/**
- * <p>Specialized {@link DataInfo} for {@link String} content.</p>
- */
-public class StringDataInfo extends BytesDataInfo
-{
-    public StringDataInfo(String string, boolean close)
-    {
-        super(string.getBytes(StandardCharsets.UTF_8), close);
-    }
-
-    public StringDataInfo(long timeout, TimeUnit unit, String string, boolean close)
-    {
-        super(timeout, unit, string.getBytes(StandardCharsets.UTF_8), close);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java
deleted file mode 100644
index 26424c3..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/SynInfo.java
+++ /dev/null
@@ -1,128 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>A container for SYN_STREAM frames metadata and data.</p>
- */
-public class SynInfo extends Info
-{
-    /**
-     * <p>Flag that indicates that this {@link SynInfo} is the last frame in the stream.</p>
-     *
-     * @see #isClose()
-     * @see #getFlags()
-     */
-    public static final byte FLAG_CLOSE = 1;
-
-    private final boolean close;
-    private final byte priority;
-    private final Fields headers;
-
-    /**
-     * <p>Creates a {@link SynInfo} instance with the given headers and the given close flag,
-     * not unidirectional, without associated stream, and with default priority.</p>
-     *
-     * @param headers the {@link Fields}
-     * @param close the value of the close flag
-     */
-    public SynInfo(Fields headers, boolean close)
-    {
-        this(0, TimeUnit.SECONDS, headers, close, (byte)0);
-        // either builder or setters for timeout
-    }
-
-    /**
-     * <p>
-     * Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority.
-     * </p>
-     * @param headers
-     *            the {@link Fields}
-     * @param close
-     *            the value of the close flag
-     * @param priority
-     */
-    public SynInfo(Fields headers, boolean close, byte priority)
-    {
-        this(0, TimeUnit.SECONDS, headers, close, priority);
-    }
-
-    /**
-     * <p>
-     * Creates a {@link SynInfo} instance with the given headers, the given close flag and with the given priority.
-     * </p>
-     * @param timeout the timeout value
-     * @param unit the TimeUnit of the timeout
-     * @param headers
-     *            the {@link Fields}
-     * @param close
-     *            the value of the close flag
-     * @param priority
-     */
-    public SynInfo(long timeout, TimeUnit unit, Fields headers, boolean close, byte priority)
-    {
-        super(timeout, unit);
-        this.close = close;
-        this.priority = priority;
-        this.headers = headers;
-    }
-
-    /**
-     * @return the value of the close flag
-     */
-    public boolean isClose()
-    {
-        return close;
-    }
-
-    /**
-     * @return the priority
-     */
-    public byte getPriority()
-    {
-        return priority;
-    }
-
-    /**
-     * @return the {@link Fields}
-     */
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    /**
-     * @return the close flag as integer
-     * @see #FLAG_CLOSE
-     */
-    public byte getFlags()
-    {
-        return isClose() ? FLAG_CLOSE : 0;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("SYN close=%b headers=%s", close, headers);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java
deleted file mode 100644
index 69824ea..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/api/server/ServerSessionFrameListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api.server;
-
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-
-/**
- * <p>Specific, server-side, {@link SessionFrameListener}.</p>
- * <p>In addition to {@link SessionFrameListener}, this listener adds method
- * {@link #onConnect(Session)} that is called when a client first connects to the
- * server and may be used by a server-side application to send a SETTINGS frame
- * to configure the connection before the client can open any stream.</p>
- */
-public interface ServerSessionFrameListener extends SessionFrameListener
-{
-    /**
-     * <p>Callback invoked when a client opens a connection.</p>
-     *
-     * @param session the session
-     */
-    public void onConnect(Session session);
-
-    /**
-     * <p>Empty implementation of {@link ServerSessionFrameListener}</p>
-     */
-    public static class Adapter extends SessionFrameListener.Adapter implements ServerSessionFrameListener
-    {
-        @Override
-        public void onConnect(Session session)
-        {
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java
deleted file mode 100644
index 0ff4b6c..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrame.java
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-public abstract class ControlFrame
-{
-    public static final int HEADER_LENGTH = 8;
-
-    private final short version;
-    private final ControlFrameType type;
-    private final byte flags;
-
-    public ControlFrame(short version, ControlFrameType type, byte flags)
-    {
-        this.version = version;
-        this.type = type;
-        this.flags = flags;
-    }
-
-    public short getVersion()
-    {
-        return version;
-    }
-
-    public ControlFrameType getType()
-    {
-        return type;
-    }
-
-    public byte getFlags()
-    {
-        return flags;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s frame v%s", getType(), getVersion());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java
deleted file mode 100644
index 7ca6ec8..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/ControlFrameType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public enum ControlFrameType
-{
-    SYN_STREAM((short)1),
-    SYN_REPLY((short)2),
-    RST_STREAM((short)3),
-    SETTINGS((short)4),
-    NOOP((short)5),
-    PING((short)6),
-    GO_AWAY((short)7),
-    HEADERS((short)8),
-    WINDOW_UPDATE((short)9),
-    CREDENTIAL((short)10);
-
-    public static ControlFrameType from(short code)
-    {
-        return Codes.codes.get(code);
-    }
-
-    private final short code;
-
-    private ControlFrameType(short code)
-    {
-        this.code = code;
-        Codes.codes.put(code, this);
-    }
-
-    public short getCode()
-    {
-        return code;
-    }
-
-    private static class Codes
-    {
-        private static final Map<Short, ControlFrameType> codes = new HashMap<>();
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java
deleted file mode 100644
index 9788bc2..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/CredentialFrame.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.security.cert.Certificate;
-
-public class CredentialFrame extends ControlFrame
-{
-    private final short slot;
-    private final byte[] proof;
-    private final Certificate[] certificateChain;
-
-    public CredentialFrame(short version, short slot, byte[] proof, Certificate[] certificateChain)
-    {
-        super(version, ControlFrameType.CREDENTIAL, (byte)0);
-        this.slot = slot;
-        this.proof = proof;
-        this.certificateChain = certificateChain;
-    }
-
-    public short getSlot()
-    {
-        return slot;
-    }
-
-    public byte[] getProof()
-    {
-        return proof;
-    }
-
-    public Certificate[] getCertificateChain()
-    {
-        return certificateChain;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java
deleted file mode 100644
index d3689cd..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/DataFrame.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-
-public class DataFrame
-{
-    public static final int HEADER_LENGTH = 8;
-
-    private final int streamId;
-    private final byte flags;
-    private final int length;
-
-    public DataFrame(int streamId, byte flags, int length)
-    {
-        this.streamId = streamId;
-        this.flags = flags;
-        this.length = length;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public byte getFlags()
-    {
-        return flags;
-    }
-
-    public int getLength()
-    {
-        return length;
-    }
-
-    public boolean isClose()
-    {
-        return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("DATA frame stream=%d length=%d close=%b", getStreamId(), getLength(), isClose());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java
deleted file mode 100644
index 0471f75..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/GoAwayFrame.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.SessionStatus;
-
-public class GoAwayFrame extends ControlFrame
-{
-    private final int lastStreamId;
-    private final int statusCode;
-
-    public GoAwayFrame(short version, int lastStreamId, int statusCode)
-    {
-        super(version, ControlFrameType.GO_AWAY, (byte)0);
-        this.lastStreamId = lastStreamId;
-        this.statusCode = statusCode;
-    }
-
-    public int getLastStreamId()
-    {
-        return lastStreamId;
-    }
-
-    public int getStatusCode()
-    {
-        return statusCode;
-    }
-
-    @Override
-    public String toString()
-    {
-        SessionStatus sessionStatus = SessionStatus.from(getStatusCode());
-        return String.format("%s last_stream=%d status=%s", super.toString(), getLastStreamId(), sessionStatus == null ? getStatusCode() : sessionStatus);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java
deleted file mode 100644
index c1f9380..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/HeadersFrame.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.util.Fields;
-
-public class HeadersFrame extends ControlFrame
-{
-    private final int streamId;
-    private final Fields headers;
-
-    public HeadersFrame(short version, byte flags, int streamId, Fields headers)
-    {
-        super(version, ControlFrameType.HEADERS, flags);
-        this.streamId = streamId;
-        this.headers = headers;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    public boolean isClose()
-    {
-        return (getFlags() & HeadersInfo.FLAG_CLOSE) == HeadersInfo.FLAG_CLOSE;
-    }
-
-    public boolean isResetCompression()
-    {
-        return (getFlags() & HeadersInfo.FLAG_RESET_COMPRESSION) == HeadersInfo.FLAG_RESET_COMPRESSION;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s stream=%d close=%b reset_compression=%b", super.toString(), getStreamId(), isClose(), isResetCompression());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java
deleted file mode 100644
index 13881ba..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/NoOpFrame.java
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-
-public class NoOpFrame extends ControlFrame
-{
-    public NoOpFrame()
-    {
-        super(SPDY.V2, ControlFrameType.NOOP, (byte)0);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java
deleted file mode 100644
index 0032301..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/PingFrame.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-public class PingFrame extends ControlFrame
-{
-    private final int pingId;
-
-    public PingFrame(short version, int pingId)
-    {
-        super(version, ControlFrameType.PING, (byte)0);
-        this.pingId = pingId;
-    }
-
-    public int getPingId()
-    {
-        return pingId;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s ping=%d", super.toString(), getPingId());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java
deleted file mode 100644
index 3b6b983..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/RstStreamFrame.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.StreamStatus;
-
-public class RstStreamFrame extends ControlFrame
-{
-    private final int streamId;
-    private final int statusCode;
-
-    public RstStreamFrame(short version, int streamId, int statusCode)
-    {
-        super(version, ControlFrameType.RST_STREAM, (byte)0);
-        this.streamId = streamId;
-        this.statusCode = statusCode;
-    }
-    
-    public int getStreamId()
-    {
-        return streamId;
-    }
-    
-    public int getStatusCode()
-    {
-        return statusCode;
-    }
-    
-    @Override
-    public String toString()
-    {
-        StreamStatus streamStatus = StreamStatus.from(getVersion(), getStatusCode());
-        return String.format("%s stream=%d status=%s", super.toString(), getStreamId(), streamStatus == null ? getStatusCode() : streamStatus);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java
deleted file mode 100644
index 240c684..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SettingsFrame.java
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-
-public class SettingsFrame extends ControlFrame
-{
-    private final Settings settings;
-
-    public SettingsFrame(short version, byte flags, Settings settings)
-    {
-        super(version, ControlFrameType.SETTINGS, flags);
-        this.settings = settings;
-    }
-
-    public boolean isClearPersisted()
-    {
-        return (getFlags() & SettingsInfo.CLEAR_PERSISTED) == SettingsInfo.CLEAR_PERSISTED;
-    }
-
-    public Settings getSettings()
-    {
-        return settings;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s clear_persisted=%b settings=%s", super.toString(), isClearPersisted(), getSettings());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java
deleted file mode 100644
index 73cfb9c..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynReplyFrame.java
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.util.Fields;
-
-public class SynReplyFrame extends ControlFrame
-{
-    private final int streamId;
-    private final Fields headers;
-
-    public SynReplyFrame(short version, byte flags, int streamId, Fields headers)
-    {
-        super(version, ControlFrameType.SYN_REPLY, flags);
-        this.streamId = streamId;
-        this.headers = headers;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    public boolean isClose()
-    {
-        return (getFlags() & ReplyInfo.FLAG_CLOSE) == ReplyInfo.FLAG_CLOSE;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s stream=%d close=%b", super.toString(), getStreamId(), isClose());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java
deleted file mode 100644
index 98b65f3..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/SynStreamFrame.java
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import org.eclipse.jetty.spdy.PushSynInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.util.Fields;
-
-public class SynStreamFrame extends ControlFrame
-{
-    private final int streamId;
-    private final int associatedStreamId;
-    private final byte priority;
-    private final short slot;
-    private final Fields headers;
-
-    public SynStreamFrame(short version, byte flags, int streamId, int associatedStreamId, byte priority, short slot, Fields headers)
-    {
-        super(version, ControlFrameType.SYN_STREAM, flags);
-        this.streamId = streamId;
-        this.associatedStreamId = associatedStreamId;
-        this.priority = priority;
-        this.slot = slot;
-        this.headers = headers;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public int getAssociatedStreamId()
-    {
-        return associatedStreamId;
-    }
-
-    public byte getPriority()
-    {
-        return priority;
-    }
-
-    public short getSlot()
-    {
-        return slot;
-    }
-
-    public Fields getHeaders()
-    {
-        return headers;
-    }
-
-    public boolean isClose()
-    {
-        return (getFlags() & SynInfo.FLAG_CLOSE) == SynInfo.FLAG_CLOSE;
-    }
-
-    public boolean isUnidirectional()
-    {
-        return (getFlags() & PushSynInfo.FLAG_UNIDIRECTIONAL) == PushSynInfo.FLAG_UNIDIRECTIONAL;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s stream=%d close=%b", super.toString(), getStreamId(), isClose());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java
deleted file mode 100644
index f07b558..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/frames/WindowUpdateFrame.java
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-public class WindowUpdateFrame extends ControlFrame
-{
-    private final int streamId;
-    private final int windowDelta;
-
-    public WindowUpdateFrame(short version, int streamId, int windowDelta)
-    {
-        super(version, ControlFrameType.WINDOW_UPDATE, (byte)0);
-        this.streamId = streamId;
-        this.windowDelta = windowDelta;
-    }
-
-    public int getStreamId()
-    {
-        return streamId;
-    }
-
-    public int getWindowDelta()
-    {
-        return windowDelta;
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s stream=%d delta=%d", super.toString(), getStreamId(), getWindowDelta());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java
deleted file mode 100644
index 57381bc..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/ControlFrameGenerator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-
-public abstract class ControlFrameGenerator
-{
-    private final ByteBufferPool bufferPool;
-
-    protected ControlFrameGenerator(ByteBufferPool bufferPool)
-    {
-        this.bufferPool = bufferPool;
-    }
-
-    protected ByteBufferPool getByteBufferPool()
-    {
-        return bufferPool;
-    }
-
-    public abstract ByteBuffer generate(ControlFrame frame);
-
-    protected void generateControlFrameHeader(ControlFrame frame, int frameLength, ByteBuffer buffer)
-    {
-        buffer.putShort((short)(0x8000 + frame.getVersion()));
-        buffer.putShort(frame.getType().getCode());
-        int flagsAndLength = frame.getFlags();
-        flagsAndLength <<= 24;
-        flagsAndLength += frameLength;
-        buffer.putInt(flagsAndLength);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java
deleted file mode 100644
index 2ed6e20..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/CredentialGenerator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.CredentialFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class CredentialGenerator extends ControlFrameGenerator
-{
-    public CredentialGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        CredentialFrame credential = (CredentialFrame)frame;
-
-        byte[] proof = credential.getProof();
-
-        List<byte[]> certificates = serializeCertificates(credential.getCertificateChain());
-        int certificatesLength = 0;
-        for (byte[] certificate : certificates)
-            certificatesLength += certificate.length;
-
-        int frameBodyLength = 2 + 4 + proof.length + certificates.size() * 4 + certificatesLength;
-
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(credential, frameBodyLength, buffer);
-
-        buffer.putShort(credential.getSlot());
-        buffer.putInt(proof.length);
-        buffer.put(proof);
-        for (byte[] certificate : certificates)
-        {
-            buffer.putInt(certificate.length);
-            buffer.put(certificate);
-        }
-
-        buffer.flip();
-        return buffer;
-    }
-
-    private List<byte[]> serializeCertificates(Certificate[] certificates)
-    {
-        try
-        {
-            List<byte[]> result = new ArrayList<>(certificates.length);
-            for (Certificate certificate : certificates)
-                result.add(certificate.getEncoded());
-            return result;
-        }
-        catch (CertificateEncodingException x)
-        {
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java
deleted file mode 100644
index 6a3304f..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/DataFrameGenerator.java
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class DataFrameGenerator
-{
-    private final ByteBufferPool bufferPool;
-
-    public DataFrameGenerator(ByteBufferPool bufferPool)
-    {
-        this.bufferPool = bufferPool;
-    }
-
-    public ByteBuffer generate(int streamId, int length, DataInfo dataInfo)
-    {
-        ByteBuffer buffer = bufferPool.acquire(DataFrame.HEADER_LENGTH + length, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        buffer.limit(length + DataFrame.HEADER_LENGTH);
-        buffer.position(DataFrame.HEADER_LENGTH);
-        // Guaranteed to always be >= 0
-        int read = dataInfo.readInto(buffer);
-
-        buffer.putInt(0, streamId & 0x7F_FF_FF_FF);
-        buffer.putInt(4, read & 0x00_FF_FF_FF);
-
-        byte flags = dataInfo.getFlags();
-        if (dataInfo.available() > 0)
-            flags &= ~DataInfo.FLAG_CLOSE;
-        buffer.put(4, flags);
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java
deleted file mode 100644
index 0bc5382..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/Generator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-import java.util.EnumMap;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-
-public class Generator
-{
-    final static boolean useDirectBuffers=false;
-    private final EnumMap<ControlFrameType, ControlFrameGenerator> generators = new EnumMap<>(ControlFrameType.class);
-    private final DataFrameGenerator dataFrameGenerator;
-
-    public Generator(ByteBufferPool bufferPool, CompressionFactory.Compressor compressor)
-    {
-        HeadersBlockGenerator headersBlockGenerator = new HeadersBlockGenerator(compressor);
-        generators.put(ControlFrameType.SYN_STREAM, new SynStreamGenerator(bufferPool, headersBlockGenerator));
-        generators.put(ControlFrameType.SYN_REPLY, new SynReplyGenerator(bufferPool, headersBlockGenerator));
-        generators.put(ControlFrameType.RST_STREAM, new RstStreamGenerator(bufferPool));
-        generators.put(ControlFrameType.SETTINGS, new SettingsGenerator(bufferPool));
-        generators.put(ControlFrameType.NOOP, new NoOpGenerator(bufferPool));
-        generators.put(ControlFrameType.PING, new PingGenerator(bufferPool));
-        generators.put(ControlFrameType.GO_AWAY, new GoAwayGenerator(bufferPool));
-        generators.put(ControlFrameType.HEADERS, new HeadersGenerator(bufferPool, headersBlockGenerator));
-        generators.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateGenerator(bufferPool));
-        generators.put(ControlFrameType.CREDENTIAL, new CredentialGenerator(bufferPool));
-
-        dataFrameGenerator = new DataFrameGenerator(bufferPool);
-    }
-
-    public ByteBuffer control(ControlFrame frame)
-    {
-        ControlFrameGenerator generator = generators.get(frame.getType());
-        return generator.generate(frame);
-    }
-
-    public ByteBuffer data(int streamId, int length, DataInfo dataInfo)
-    {
-        return dataFrameGenerator.generate(streamId, length, dataInfo);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java
deleted file mode 100644
index 524862a..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/GoAwayGenerator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.GoAwayFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class GoAwayGenerator extends ControlFrameGenerator
-{
-    public GoAwayGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        GoAwayFrame goAway = (GoAwayFrame)frame;
-
-        int frameBodyLength = 8;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(goAway, frameBodyLength, buffer);
-
-        buffer.putInt(goAway.getLastStreamId() & 0x7F_FF_FF_FF);
-        writeStatusCode(goAway, buffer);
-
-        buffer.flip();
-        return buffer;
-    }
-
-    private void writeStatusCode(GoAwayFrame goAway, ByteBuffer buffer)
-    {
-        switch (goAway.getVersion())
-        {
-            case SPDY.V2:
-                break;
-            case SPDY.V3:
-                buffer.putInt(goAway.getStatusCode());
-                break;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java
deleted file mode 100644
index 9921f32..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersBlockGenerator.java
+++ /dev/null
@@ -1,150 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-import org.eclipse.jetty.spdy.CompressionDictionary;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.util.Fields;
-
-public class HeadersBlockGenerator
-{
-    private final CompressionFactory.Compressor compressor;
-    private boolean needsDictionary = true;
-
-    public HeadersBlockGenerator(CompressionFactory.Compressor compressor)
-    {
-        this.compressor = compressor;
-    }
-
-    public ByteBuffer generate(short version, Fields headers)
-    {
-        // TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using ByteBuffer ?
-        final Charset iso1 = StandardCharsets.ISO_8859_1;
-        ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.getSize() * 64);
-        writeCount(version, buffer, headers.getSize());
-        for (Fields.Field header : headers)
-        {
-            String name = header.getName().toLowerCase(Locale.ENGLISH);
-            byte[] nameBytes = name.getBytes(iso1);
-            writeNameLength(version, buffer, nameBytes.length);
-            buffer.write(nameBytes, 0, nameBytes.length);
-
-            // Most common path first
-            String value = header.getValue();
-            byte[] valueBytes = value.getBytes(iso1);
-            if (header.hasMultipleValues())
-            {
-                List<String> values = header.getValues();
-                for (int i = 1; i < values.size(); ++i)
-                {
-                    byte[] moreValueBytes = values.get(i).getBytes(iso1);
-                    byte[] newValueBytes = Arrays.copyOf(valueBytes,valueBytes.length + 1 + moreValueBytes.length);
-                    newValueBytes[valueBytes.length] = 0;
-                    System.arraycopy(moreValueBytes, 0, newValueBytes, valueBytes.length + 1, moreValueBytes.length);
-                    valueBytes = newValueBytes;
-                }
-            }
-
-            writeValueLength(version, buffer, valueBytes.length);
-            buffer.write(valueBytes, 0, valueBytes.length);
-        }
-
-        return compress(version, buffer.toByteArray());
-    }
-
-    private ByteBuffer compress(short version, byte[] bytes)
-    {
-        ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length);
-
-        // The headers compression context is per-session, so we need to synchronize
-        synchronized (compressor)
-        {
-            if (needsDictionary)
-            {
-                compressor.setDictionary(CompressionDictionary.get(version));
-                needsDictionary = false;
-            }
-
-            compressor.setInput(bytes);
-
-            // Compressed bytes may be bigger than input bytes, so we need to loop and accumulate them
-            // Beware that the minimum amount of bytes generated by the compressor is few bytes, so we
-            // need to use an output buffer that is big enough to exit the compress loop
-            buffer.reset();
-            int compressed;
-            byte[] output = new byte[Math.max(256, bytes.length)];
-            while (true)
-            {
-                // SPDY uses the SYNC_FLUSH mode
-                compressed = compressor.compress(output);
-                buffer.write(output, 0, compressed);
-                if (compressed < output.length)
-                    break;
-            }
-        }
-
-        return ByteBuffer.wrap(buffer.toByteArray());
-    }
-
-    private void writeCount(short version, ByteArrayOutputStream buffer, int value)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-            {
-                buffer.write((value & 0xFF_00) >>> 8);
-                buffer.write(value & 0x00_FF);
-                break;
-            }
-            case SPDY.V3:
-            {
-                buffer.write((value & 0xFF_00_00_00) >>> 24);
-                buffer.write((value & 0x00_FF_00_00) >>> 16);
-                buffer.write((value & 0x00_00_FF_00) >>> 8);
-                buffer.write(value & 0x00_00_00_FF);
-                break;
-            }
-            default:
-            {
-                // Here the version is trusted to be correct; if it's not
-                // then it's a bug rather than an application error
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    private void writeNameLength(short version, ByteArrayOutputStream buffer, int length)
-    {
-        writeCount(version, buffer, length);
-    }
-
-    private void writeValueLength(short version, ByteArrayOutputStream buffer, int length)
-    {
-        writeCount(version, buffer, length);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java
deleted file mode 100644
index afb9adb..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/HeadersGenerator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.HeadersFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class HeadersGenerator extends ControlFrameGenerator
-{
-    private final HeadersBlockGenerator headersBlockGenerator;
-
-    public HeadersGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator)
-    {
-        super(bufferPool);
-        this.headersBlockGenerator = headersBlockGenerator;
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        HeadersFrame headers = (HeadersFrame)frame;
-        short version = headers.getVersion();
-
-        ByteBuffer headersBuffer = headersBlockGenerator.generate(version, headers.getHeaders());
-
-        int frameBodyLength = 4;
-        if (frame.getVersion() == SPDY.V2)
-            frameBodyLength += 2;
-
-        int frameLength = frameBodyLength + headersBuffer.remaining();
-        if (frameLength > 0xFF_FF_FF)
-        {
-            // Too many headers, but unfortunately we have already modified the compression
-            // context, so we have no other choice than tear down the connection.
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers");
-        }
-
-        int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
-
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(headers, frameLength, buffer);
-
-        buffer.putInt(headers.getStreamId() & 0x7F_FF_FF_FF);
-        if (frame.getVersion() == SPDY.V2)
-            buffer.putShort((short)0);
-
-        buffer.put(headersBuffer);
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java
deleted file mode 100644
index cbf029c..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/NoOpGenerator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.NoOpFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class NoOpGenerator extends ControlFrameGenerator
-{
-    public NoOpGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        NoOpFrame noOp = (NoOpFrame)frame;
-
-        int frameBodyLength = 0;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(noOp, frameBodyLength, buffer);
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java
deleted file mode 100644
index c263a20..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/PingGenerator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.PingFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class PingGenerator extends ControlFrameGenerator
-{
-    public PingGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        PingFrame ping = (PingFrame)frame;
-
-        int frameBodyLength = 4;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(ping, frameBodyLength, buffer);
-
-        buffer.putInt(ping.getPingId());
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java
deleted file mode 100644
index d26ac8e..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/RstStreamGenerator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class RstStreamGenerator extends ControlFrameGenerator
-{
-    public RstStreamGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        RstStreamFrame rstStream = (RstStreamFrame)frame;
-
-        int frameBodyLength = 8;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(rstStream, frameBodyLength, buffer);
-
-        buffer.putInt(rstStream.getStreamId() & 0x7F_FF_FF_FF);
-        buffer.putInt(rstStream.getStatusCode());
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java
deleted file mode 100644
index 4c00dde..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SettingsGenerator.java
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.SettingsFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class SettingsGenerator extends ControlFrameGenerator
-{
-    public SettingsGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        SettingsFrame settingsFrame = (SettingsFrame)frame;
-
-        Settings settings = settingsFrame.getSettings();
-        int size = settings.size();
-        int frameBodyLength = 4 + 8 * size;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(settingsFrame, frameBodyLength, buffer);
-
-        buffer.putInt(size);
-
-        for (Settings.Setting setting : settings)
-        {
-            int id = setting.id().code();
-            byte flags = setting.flag().code();
-            int idAndFlags = convertIdAndFlags(frame.getVersion(), id, flags);
-            buffer.putInt(idAndFlags);
-            buffer.putInt(setting.value());
-        }
-
-        buffer.flip();
-        return buffer;
-    }
-
-    private int convertIdAndFlags(short version, int id, byte flags)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-            {
-                // In v2 the format is 24 bits of ID + 8 bits of flag
-                int idAndFlags = (id << 8) + (flags & 0xFF);
-                // A bug in the Chromium implementation forces v2 to have
-                // the 3 ID bytes little endian, so we swap first and third
-                int result = idAndFlags & 0x00_FF_00_FF;
-                result += (idAndFlags & 0xFF_00_00_00) >>> 16;
-                result += (idAndFlags & 0x00_00_FF_00) << 16;
-                return result;
-            }
-            case SPDY.V3:
-            {
-                // In v3 the format is 8 bits of flags + 24 bits of ID
-                return (flags << 24) + (id & 0xFF_FF_FF);
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java
deleted file mode 100644
index d9aaa79..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynReplyGenerator.java
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class SynReplyGenerator extends ControlFrameGenerator
-{
-    private final HeadersBlockGenerator headersBlockGenerator;
-
-    public SynReplyGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator)
-    {
-        super(bufferPool);
-        this.headersBlockGenerator = headersBlockGenerator;
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        SynReplyFrame synReply = (SynReplyFrame)frame;
-        short version = synReply.getVersion();
-
-        ByteBuffer headersBuffer = headersBlockGenerator.generate(version, synReply.getHeaders());
-
-        int frameBodyLength = getFrameDataLength(version);
-
-        int frameLength = frameBodyLength + headersBuffer.remaining();
-        if (frameLength > 0xFF_FF_FF)
-        {
-            // Too many headers, but unfortunately we have already modified the compression
-            // context, so we have no other choice than tear down the connection.
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers");
-        }
-
-        int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
-
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(synReply, frameLength, buffer);
-
-        buffer.putInt(synReply.getStreamId() & 0x7F_FF_FF_FF);
-        writeAdditional(version, buffer);
-
-        buffer.put(headersBuffer);
-
-        buffer.flip();
-        return buffer;
-    }
-
-    private int getFrameDataLength(short version)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return 6;
-            case SPDY.V3:
-                return 4;
-            default:
-                // Here the version is trusted to be correct; if it's not
-                // then it's a bug rather than an application error
-                throw new IllegalStateException();
-        }
-    }
-
-    private void writeAdditional(short version, ByteBuffer buffer)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                buffer.putShort((short)0);
-                break;
-            case SPDY.V3:
-                break;
-            default:
-                // Here the version is trusted to be correct; if it's not
-                // then it's a bug rather than an application error
-                throw new IllegalStateException();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java
deleted file mode 100644
index 7a4e8ee..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/SynStreamGenerator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class SynStreamGenerator extends ControlFrameGenerator
-{
-    private final HeadersBlockGenerator headersBlockGenerator;
-
-    public SynStreamGenerator(ByteBufferPool bufferPool, HeadersBlockGenerator headersBlockGenerator)
-    {
-        super(bufferPool);
-        this.headersBlockGenerator = headersBlockGenerator;
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        SynStreamFrame synStream = (SynStreamFrame)frame;
-        short version = synStream.getVersion();
-
-        ByteBuffer headersBuffer = headersBlockGenerator.generate(version, synStream.getHeaders());
-
-        int frameBodyLength = 10;
-
-        int frameLength = frameBodyLength + headersBuffer.remaining();
-        if (frameLength > 0xFF_FF_FF)
-        {
-            // Too many headers, but unfortunately we have already modified the compression
-            // context, so we have no other choice than tear down the connection.
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, "Too many headers");
-        }
-
-        int totalLength = ControlFrame.HEADER_LENGTH + frameLength;
-
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(synStream, frameLength, buffer);
-
-        int streamId = synStream.getStreamId();
-        buffer.putInt(streamId & 0x7F_FF_FF_FF);
-        buffer.putInt(synStream.getAssociatedStreamId() & 0x7F_FF_FF_FF);
-        writePriority(streamId, version, synStream.getPriority(), buffer);
-        buffer.put((byte)synStream.getSlot());
-
-        buffer.put(headersBuffer);
-
-        buffer.flip();
-        return buffer;
-    }
-
-    private void writePriority(int streamId, short version, byte priority, ByteBuffer buffer)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                priority <<= 6;
-                break;
-            case SPDY.V3:
-                priority <<= 5;
-                break;
-            default:
-                throw new StreamException(streamId, StreamStatus.UNSUPPORTED_VERSION);
-        }
-        buffer.put(priority);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java
deleted file mode 100644
index 5ce1699..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/generator/WindowUpdateGenerator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
-import org.eclipse.jetty.util.BufferUtil;
-
-public class WindowUpdateGenerator extends ControlFrameGenerator
-{
-    public WindowUpdateGenerator(ByteBufferPool bufferPool)
-    {
-        super(bufferPool);
-    }
-
-    @Override
-    public ByteBuffer generate(ControlFrame frame)
-    {
-        WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame;
-
-        int frameBodyLength = 8;
-        int totalLength = ControlFrame.HEADER_LENGTH + frameBodyLength;
-        ByteBuffer buffer = getByteBufferPool().acquire(totalLength, Generator.useDirectBuffers);
-        BufferUtil.clearToFill(buffer);
-        generateControlFrameHeader(windowUpdate, frameBodyLength, buffer);
-
-        buffer.putInt(windowUpdate.getStreamId() & 0x7F_FF_FF_FF);
-        buffer.putInt(windowUpdate.getWindowDelta() & 0x7F_FF_FF_FF);
-
-        buffer.flip();
-        return buffer;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java
deleted file mode 100644
index 9dccfcd..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameBodyParser.java
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-public abstract class ControlFrameBodyParser
-{
-    public abstract boolean parse(ByteBuffer buffer);
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java
deleted file mode 100644
index cfaf14a..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/ControlFrameParser.java
+++ /dev/null
@@ -1,213 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.util.EnumMap;
-
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-
-public abstract class ControlFrameParser
-{
-    private final EnumMap<ControlFrameType, ControlFrameBodyParser> parsers = new EnumMap<>(ControlFrameType.class);
-    private final ControlFrameBodyParser unknownParser = new UnknownControlFrameBodyParser(this);
-    private State state = State.VERSION;
-    private int cursor;
-    private short version;
-    private short type;
-    private byte flags;
-    private int length;
-    private ControlFrameBodyParser bodyParser;
-    private int bytesToSkip = 0;
-
-    public ControlFrameParser(CompressionFactory.Decompressor decompressor)
-    {
-        parsers.put(ControlFrameType.SYN_STREAM, new SynStreamBodyParser(decompressor, this));
-        parsers.put(ControlFrameType.SYN_REPLY, new SynReplyBodyParser(decompressor, this));
-        parsers.put(ControlFrameType.RST_STREAM, new RstStreamBodyParser(this));
-        parsers.put(ControlFrameType.SETTINGS, new SettingsBodyParser(this));
-        parsers.put(ControlFrameType.NOOP, new NoOpBodyParser(this));
-        parsers.put(ControlFrameType.PING, new PingBodyParser(this));
-        parsers.put(ControlFrameType.GO_AWAY, new GoAwayBodyParser(this));
-        parsers.put(ControlFrameType.HEADERS, new HeadersBodyParser(decompressor, this));
-        parsers.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateBodyParser(this));
-        parsers.put(ControlFrameType.CREDENTIAL, new CredentialBodyParser(this));
-    }
-
-    public short getVersion()
-    {
-        return version;
-    }
-
-    public byte getFlags()
-    {
-        return flags;
-    }
-
-    public int getLength()
-    {
-        return length;
-    }
-
-    public void skip(int bytesToSkip)
-    {
-        state = State.SKIP;
-        this.bytesToSkip = bytesToSkip;
-    }
-
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case VERSION:
-                {
-                    if (buffer.remaining() >= 2)
-                    {
-                        version = (short)(buffer.getShort() & 0x7F_FF);
-                        state = State.TYPE;
-                    }
-                    else
-                    {
-                        state = State.VERSION_BYTES;
-                        cursor = 2;
-                    }
-                    break;
-                }
-                case VERSION_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    version += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        version &= 0x7F_FF;
-                        state = State.TYPE;
-                    }
-                    break;
-                }
-                case TYPE:
-                {
-                    if (buffer.remaining() >= 2)
-                    {
-                        type = buffer.getShort();
-                        state = State.FLAGS;
-                    }
-                    else
-                    {
-                        state = State.TYPE_BYTES;
-                        cursor = 2;
-                    }
-                    break;
-                }
-                case TYPE_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    type += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                        state = State.FLAGS;
-                    break;
-                }
-                case FLAGS:
-                {
-                    flags = buffer.get();
-                    cursor = 3;
-                    state = State.LENGTH;
-                    break;
-                }
-                case LENGTH:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    length += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor > 0)
-                        break;
-
-                    ControlFrameType controlFrameType = ControlFrameType.from(type);
-
-                    // SPEC v3, 2.2.1: unrecognized control frames must be ignored
-                    if (controlFrameType == null)
-                        bodyParser = unknownParser;
-                    else
-                        bodyParser = parsers.get(controlFrameType);
-
-                    state = State.BODY;
-
-                    // We have to let it fall through the next switch:
-                    // the NOOP frame has no body and we cannot break
-                    // because the buffer may be consumed and we will
-                    // never enter the BODY case.
-                }
-                case BODY:
-                {
-                    if (bodyParser.parse(buffer))
-                    {
-                        reset();
-                        return true;
-                    }
-                    break;
-                }
-                case SKIP:
-                {
-                    int remaining = buffer.remaining();
-                    if (remaining >= bytesToSkip)
-                    {
-                        buffer.position(buffer.position() + bytesToSkip);
-                        reset();
-                        return true;
-                    }
-                    else
-                    {
-                        buffer.position(buffer.limit());
-                        bytesToSkip = bytesToSkip - remaining;
-                        return false;
-                    }
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    void reset()
-    {
-        state = State.VERSION;
-        cursor = 0;
-        version = 0;
-        type = 0;
-        flags = 0;
-        length = 0;
-        bodyParser = null;
-        bytesToSkip = 0;
-    }
-
-    protected abstract void onControlFrame(ControlFrame frame);
-
-    private enum State
-    {
-        VERSION, VERSION_BYTES, TYPE, TYPE_BYTES, FLAGS, LENGTH, BODY, SKIP
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java
deleted file mode 100644
index f511aed..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/CredentialBodyParser.java
+++ /dev/null
@@ -1,274 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.io.ByteArrayInputStream;
-import java.nio.ByteBuffer;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.CredentialFrame;
-
-public class CredentialBodyParser extends ControlFrameBodyParser
-{
-    private final List<Certificate> certificates = new ArrayList<>();
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.SLOT;
-    private int totalLength;
-    private int cursor;
-    private short slot;
-    private int proofLength;
-    private byte[] proof;
-    private int certificateLength;
-    private byte[] certificate;
-
-    public CredentialBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case SLOT:
-                {
-                    if (buffer.remaining() >= 2)
-                    {
-                        slot = buffer.getShort();
-                        checkSlotValid();
-                        state = State.PROOF_LENGTH;
-                    }
-                    else
-                    {
-                        state = State.SLOT_BYTES;
-                        cursor = 2;
-                    }
-                    break;
-                }
-                case SLOT_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    slot += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        checkSlotValid();
-                        state = State.PROOF_LENGTH;
-                    }
-                    break;
-                }
-                case PROOF_LENGTH:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        proofLength = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.PROOF;
-                    }
-                    else
-                    {
-                        state = State.PROOF_LENGTH_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case PROOF_LENGTH_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    proofLength += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        proofLength &= 0x7F_FF_FF_FF;
-                        state = State.PROOF;
-                    }
-                    break;
-                }
-                case PROOF:
-                {
-                    totalLength = controlFrameParser.getLength() - 2 - 4 - proofLength;
-                    proof = new byte[proofLength];
-                    if (buffer.remaining() >= proofLength)
-                    {
-                        buffer.get(proof);
-                        state = State.CERTIFICATE_LENGTH;
-                        if (totalLength == 0)
-                        {
-                            onCredential();
-                            return true;
-                        }
-                    }
-                    else
-                    {
-                        state = State.PROOF_BYTES;
-                        cursor = proofLength;
-                    }
-                    break;
-                }
-                case PROOF_BYTES:
-                {
-                    proof[proofLength - cursor] = buffer.get();
-                    --cursor;
-                    if (cursor == 0)
-                    {
-                        state = State.CERTIFICATE_LENGTH;
-                        if (totalLength == 0)
-                        {
-                            onCredential();
-                            return true;
-                        }
-                    }
-                    break;
-                }
-                case CERTIFICATE_LENGTH:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        certificateLength = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.CERTIFICATE;
-                    }
-                    else
-                    {
-                        state = State.CERTIFICATE_LENGTH_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case CERTIFICATE_LENGTH_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    certificateLength += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        certificateLength &= 0x7F_FF_FF_FF;
-                        state = State.CERTIFICATE;
-                    }
-                    break;
-                }
-                case CERTIFICATE:
-                {
-                    totalLength -= 4 + certificateLength;
-                    certificate = new byte[certificateLength];
-                    if (buffer.remaining() >= certificateLength)
-                    {
-                        buffer.get(certificate);
-                        if (onCertificate())
-                            return true;
-                    }
-                    else
-                    {
-                        state = State.CERTIFICATE_BYTES;
-                        cursor = certificateLength;
-                    }
-                    break;
-                }
-                case CERTIFICATE_BYTES:
-                {
-                    certificate[certificateLength - cursor] = buffer.get();
-                    --cursor;
-                    if (cursor == 0)
-                    {
-                        if (onCertificate())
-                            return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void checkSlotValid()
-    {
-        if (slot <= 0)
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR,
-                    "Invalid slot " + slot + " for " + ControlFrameType.CREDENTIAL + " frame");
-    }
-
-    private boolean onCertificate()
-    {
-        certificates.add(deserializeCertificate(certificate));
-        if (totalLength == 0)
-        {
-            onCredential();
-            return true;
-        }
-        else
-        {
-            certificateLength = 0;
-            state = State.CERTIFICATE_LENGTH;
-        }
-        return false;
-    }
-
-    private Certificate deserializeCertificate(byte[] bytes)
-    {
-        try
-        {
-            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
-            return certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
-        }
-        catch (CertificateException x)
-        {
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, x);
-        }
-    }
-
-    private void onCredential()
-    {
-        CredentialFrame frame = new CredentialFrame(controlFrameParser.getVersion(), slot,
-                Arrays.copyOf(proof, proof.length), certificates.toArray(new Certificate[certificates.size()]));
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        state = State.SLOT;
-        totalLength = 0;
-        cursor = 0;
-        slot = 0;
-        proofLength = 0;
-        proof = null;
-        certificateLength = 0;
-        certificate = null;
-        certificates.clear();
-    }
-
-    public enum State
-    {
-        SLOT, SLOT_BYTES, PROOF_LENGTH, PROOF_LENGTH_BYTES, PROOF, PROOF_BYTES,
-        CERTIFICATE_LENGTH, CERTIFICATE_LENGTH_BYTES, CERTIFICATE, CERTIFICATE_BYTES
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java
deleted file mode 100644
index 4bc025c..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/DataFrameParser.java
+++ /dev/null
@@ -1,155 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-
-public abstract class DataFrameParser
-{
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-    private byte flags;
-    private int length;
-
-    /**
-     * <p>Parses the given {@link ByteBuffer} for a data frame.</p>
-     *
-     * @param buffer the {@link ByteBuffer} to parse
-     * @return true if the data frame has been fully parsed, false otherwise
-     */
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.FLAGS;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                        state = State.FLAGS;
-                    break;
-                }
-                case FLAGS:
-                {
-                    flags = buffer.get();
-                    cursor = 3;
-                    state = State.LENGTH;
-                    break;
-                }
-                case LENGTH:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    length += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor > 0)
-                        break;
-                    state = State.DATA;
-                    // Fall down if length == 0: we can't loop because the buffer
-                    // may be empty but we need to invoke the application anyway
-                    if (length > 0)
-                        break;
-                }
-                case DATA:
-                {
-                    // Length can only be at most 3 bytes, which is 16_777_215 i.e. 16 MiB.
-                    // However, compliant clients should implement flow control, so it's
-                    // unlikely that we will get that 16 MiB chunk.
-                    // However, TCP may further split the flow control window, so we may
-                    // only have part of the data at this point.
-
-                    int size = Math.min(length, buffer.remaining());
-                    int limit = buffer.limit();
-                    buffer.limit(buffer.position() + size);
-                    ByteBuffer bytes = buffer.slice();
-                    buffer.limit(limit);
-                    buffer.position(buffer.position() + size);
-                    length -= size;
-                    if (length == 0)
-                    {
-                        onDataFrame(bytes);
-                        return true;
-                    }
-                    else
-                    {
-                        // We got only part of the frame data bytes,
-                        // so we generate a synthetic data frame
-                        onDataFragment(bytes);
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void onDataFrame(ByteBuffer bytes)
-    {
-        DataFrame frame = new DataFrame(streamId, flags, bytes.remaining());
-        onDataFrame(frame, bytes);
-        reset();
-    }
-
-    private void onDataFragment(ByteBuffer bytes)
-    {
-        DataFrame frame = new DataFrame(streamId, (byte)(flags & ~DataInfo.FLAG_CLOSE), bytes.remaining());
-        onDataFrame(frame, bytes);
-        // Do not reset, we're expecting more data
-    }
-
-    protected abstract void onDataFrame(DataFrame frame, ByteBuffer data);
-
-    private void reset()
-    {
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-        flags = 0;
-        length = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, FLAGS, LENGTH, DATA
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java
deleted file mode 100644
index 8ad18fb..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/GoAwayBodyParser.java
+++ /dev/null
@@ -1,159 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.frames.GoAwayFrame;
-
-public class GoAwayBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.LAST_GOOD_STREAM_ID;
-    private int cursor;
-    private int lastStreamId;
-    private int statusCode;
-
-    public GoAwayBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case LAST_GOOD_STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        lastStreamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        switch (controlFrameParser.getVersion())
-                        {
-                            case SPDY.V2:
-                            {
-                                onGoAway();
-                                return true;
-                            }
-                            case SPDY.V3:
-                            {
-                                state = State.STATUS_CODE;
-                                break;
-                            }
-                            default:
-                            {
-                                throw new IllegalStateException();
-                            }
-                        }
-                    }
-                    else
-                    {
-                        state = State.LAST_GOOD_STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case LAST_GOOD_STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    lastStreamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        lastStreamId &= 0x7F_FF_FF_FF;
-                        switch (controlFrameParser.getVersion())
-                        {
-                            case SPDY.V2:
-                            {
-                                onGoAway();
-                                return true;
-                            }
-                            case SPDY.V3:
-                            {
-                                state = State.STATUS_CODE;
-                                break;
-                            }
-                            default:
-                            {
-                                throw new IllegalStateException();
-                            }
-                        }
-                    }
-                    break;
-                }
-                case STATUS_CODE:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        statusCode = buffer.getInt();
-                        onGoAway();
-                        return true;
-                    }
-                    else
-                    {
-                        state = State.STATUS_CODE_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STATUS_CODE_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    statusCode += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        onGoAway();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void onGoAway()
-    {
-        GoAwayFrame frame = new GoAwayFrame(controlFrameParser.getVersion(), lastStreamId, statusCode);
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        state = State.LAST_GOOD_STREAM_ID;
-        cursor = 0;
-        lastStreamId = 0;
-        statusCode = 0;
-    }
-
-    private enum State
-    {
-        LAST_GOOD_STREAM_ID, LAST_GOOD_STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java
deleted file mode 100644
index 3c3d67f..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBlockParser.java
+++ /dev/null
@@ -1,230 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.zip.ZipException;
-
-import org.eclipse.jetty.spdy.CompressionDictionary;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-
-public abstract class HeadersBlockParser
-{
-    private final CompressionFactory.Decompressor decompressor;
-    private byte[] data;
-    private boolean needsDictionary = true;
-
-    protected HeadersBlockParser(CompressionFactory.Decompressor decompressor)
-    {
-        this.decompressor = decompressor;
-    }
-
-    public boolean parse(int streamId, short version, int length, ByteBuffer buffer)
-    {
-        // Need to be sure that all the compressed data has arrived
-        // Because SPDY uses SYNC_FLUSH mode, and the Java API
-        // does not expose when decompression is finished with this mode
-        // (but only when using NO_FLUSH), then we need to
-        // accumulate the compressed bytes until we have all of them
-
-        boolean accumulated = accumulate(length, buffer);
-        if (!accumulated)
-            return false;
-
-        byte[] compressedHeaders = data;
-        data = null;
-        ByteBuffer decompressedHeaders = decompress(version, compressedHeaders);
-
-        Charset iso1 = StandardCharsets.ISO_8859_1;
-        // We know the decoded bytes contain the full headers,
-        // so optimize instead of looping byte by byte
-        int count = readCount(version, decompressedHeaders);
-        for (int i = 0; i < count; ++i)
-        {
-            int nameLength = readNameLength(version, decompressedHeaders);
-            if (nameLength == 0)
-                throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid header name length");
-            byte[] nameBytes = new byte[nameLength];
-            decompressedHeaders.get(nameBytes);
-            String name = new String(nameBytes, iso1);
-
-            int valueLength = readValueLength(version, decompressedHeaders);
-            if (valueLength == 0)
-                throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid header value length");
-            byte[] valueBytes = new byte[valueLength];
-            decompressedHeaders.get(valueBytes);
-            String value = new String(valueBytes, iso1);
-            // Multi valued headers are separate by NUL
-            String[] values = value.split("\u0000");
-            // Check if there are multiple NULs (section 2.6.9)
-            for (String v : values)
-                if (v.length() == 0)
-                    throw new StreamException(streamId, StreamStatus.PROTOCOL_ERROR, "Invalid multi valued header");
-
-            onHeader(name, values);
-        }
-
-        return true;
-    }
-
-    private boolean accumulate(int length, ByteBuffer buffer)
-    {
-        int remaining = buffer.remaining();
-        if (data == null)
-        {
-            if (remaining < length)
-            {
-                data = new byte[remaining];
-                buffer.get(data);
-                return false;
-            }
-            else
-            {
-                data = new byte[length];
-                buffer.get(data);
-                return true;
-            }
-        }
-        else
-        {
-            int accumulated = data.length;
-            int needed = length - accumulated;
-            if (remaining < needed)
-            {
-                byte[] local = Arrays.copyOf(data,accumulated + remaining);
-                buffer.get(local, accumulated, remaining);
-                data = local;
-                return false;
-            }
-            else
-            {
-                byte[] local = Arrays.copyOf(data,length);
-                buffer.get(local, accumulated, needed);
-                data = local;
-                return true;
-            }
-        }
-    }
-
-    private int readCount(int version, ByteBuffer buffer)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return buffer.getShort();
-            case SPDY.V3:
-                return buffer.getInt();
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private int readNameLength(int version, ByteBuffer buffer)
-    {
-        return readCount(version, buffer);
-    }
-
-    private int readValueLength(int version, ByteBuffer buffer)
-    {
-        return readCount(version, buffer);
-    }
-
-    protected abstract void onHeader(String name, String[] values);
-
-    private ByteBuffer decompress(short version, byte[] compressed)
-    {
-        // Differently from compression, decompression always happens
-        // non-concurrently because we read and parse with a single
-        // thread, and therefore there is no need for synchronization.
-
-        try
-        {
-            byte[] decompressed = null;
-            byte[] buffer = new byte[compressed.length * 2];
-            decompressor.setInput(compressed);
-
-            while (true)
-            {
-                int count = decompressor.decompress(buffer);
-                if (count == 0)
-                {
-                    if (decompressed != null)
-                    {
-                        return ByteBuffer.wrap(decompressed);
-                    }
-                    else if (needsDictionary)
-                    {
-                        decompressor.setDictionary(CompressionDictionary.get(version));
-                        needsDictionary = false;
-                    }
-                    else
-                    {
-                        throw new IllegalStateException();
-                    }
-                }
-                else
-                {
-                    if (count < buffer.length)
-                    {
-                        if (decompressed == null)
-                        {
-                            // Only one pass was needed to decompress
-                            return ByteBuffer.wrap(buffer, 0, count);
-                        }
-                        else
-                        {
-                            // Last pass needed to decompress, merge decompressed bytes
-                            byte[] result = Arrays.copyOf(decompressed,decompressed.length+count);
-                            System.arraycopy(buffer, 0, result, decompressed.length, count);
-                            return ByteBuffer.wrap(result);
-                        }
-                    }
-                    else
-                    {
-                        if (decompressed == null)
-                        {
-                            decompressed = buffer;
-                            buffer = new byte[buffer.length];
-                        }
-                        else
-                        {
-                            byte[] result = Arrays.copyOf(decompressed,decompressed.length+buffer.length);
-                            System.arraycopy(buffer, 0, result, decompressed.length, buffer.length);
-                            decompressed = result;
-                        }
-                    }
-                }
-            }
-        }
-        catch (ZipException x)
-        {
-            // We had a compression problem, and since the compression context
-            // is per-connection, we need to tear down the connection
-            throw new SessionException(SessionStatus.PROTOCOL_ERROR, x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java
deleted file mode 100644
index 47dfe2c..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/HeadersBodyParser.java
+++ /dev/null
@@ -1,173 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.HeadersFrame;
-import org.eclipse.jetty.util.Fields;
-
-public class HeadersBodyParser extends ControlFrameBodyParser
-{
-    private final Fields headers = new Fields();
-    private final ControlFrameParser controlFrameParser;
-    private final HeadersBlockParser headersBlockParser;
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-
-    public HeadersBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-        this.headersBlockParser = new HeadersHeadersBlockParser(decompressor);
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.ADDITIONAL;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        streamId &= 0x7F_FF_FF_FF;
-                        state = State.ADDITIONAL;
-                    }
-                    break;
-                }
-                case ADDITIONAL:
-                {
-                    switch (controlFrameParser.getVersion())
-                    {
-                        case SPDY.V2:
-                        {
-                            if (buffer.remaining() >= 2)
-                            {
-                                buffer.getShort();
-                                state = State.HEADERS;
-                            }
-                            else
-                            {
-                                state = State.ADDITIONAL_BYTES;
-                                cursor = 2;
-                            }
-                            break;
-                        }
-                        case SPDY.V3:
-                        {
-                            state = State.HEADERS;
-                            break;
-                        }
-                        default:
-                        {
-                            throw new IllegalStateException();
-                        }
-                    }
-                    break;
-                }
-                case ADDITIONAL_BYTES:
-                {
-                    assert controlFrameParser.getVersion() == SPDY.V2;
-                    buffer.get();
-                    --cursor;
-                    if (cursor == 0)
-                        state = State.HEADERS;
-                    break;
-                }
-                case HEADERS:
-                {
-                    short version = controlFrameParser.getVersion();
-                    int length = controlFrameParser.getLength() - 4;
-                    if (version == SPDY.V2)
-                        length -= 2;
-                    if (headersBlockParser.parse(streamId, version, length, buffer))
-                    {
-                        byte flags = controlFrameParser.getFlags();
-                        if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
-                            throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS);
-
-                        HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Fields(headers, true));
-                        controlFrameParser.onControlFrame(frame);
-
-                        reset();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void reset()
-    {
-        headers.clear();
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
-    }
-
-    private class HeadersHeadersBlockParser extends HeadersBlockParser
-    {
-        public HeadersHeadersBlockParser(CompressionFactory.Decompressor decompressor)
-        {
-            super(decompressor);
-        }
-
-        @Override
-        protected void onHeader(String name, String[] values)
-        {
-            for (String value : values)
-                headers.add(name, value);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java
deleted file mode 100644
index 636ddc3..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/NoOpBodyParser.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.frames.NoOpFrame;
-
-public class NoOpBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-
-    public NoOpBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        NoOpFrame frame = new NoOpFrame();
-        controlFrameParser.onControlFrame(frame);
-        return true;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java
deleted file mode 100644
index 378f256..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/Parser.java
+++ /dev/null
@@ -1,240 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.util.EventListener;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class Parser
-{
-    private static final Logger logger = Log.getLogger(Parser.class);
-    private final List<Listener> listeners = new CopyOnWriteArrayList<>();
-    private final ControlFrameParser controlFrameParser;
-    private final DataFrameParser dataFrameParser;
-    private State state = State.CONTROL_BIT;
-
-    public Parser(CompressionFactory.Decompressor decompressor)
-    {
-        // It is important to allocate one decompression context per
-        // SPDY session for the control frames (to decompress the headers)
-        controlFrameParser = new ControlFrameParser(decompressor)
-        {
-            @Override
-            protected void onControlFrame(ControlFrame frame)
-            {
-                logger.debug("Parsed {}", frame);
-                notifyControlFrame(frame);
-            }
-        };
-        dataFrameParser = new DataFrameParser()
-        {
-            @Override
-            protected void onDataFrame(DataFrame frame, ByteBuffer data)
-            {
-                logger.debug("Parsed {}, {} data bytes", frame, data.remaining());
-                notifyDataFrame(frame, data);
-            }
-        };
-    }
-
-    public void addListener(Listener listener)
-    {
-        listeners.add(listener);
-    }
-
-    public void removeListener(Listener listener)
-    {
-        listeners.remove(listener);
-    }
-
-    protected void notifyControlFrame(ControlFrame frame)
-    {
-        for (Listener listener : listeners)
-        {
-            try
-            {
-                listener.onControlFrame(frame);
-            }
-            catch (Exception x)
-            {
-                logger.info("Exception while notifying listener " + listener, x);
-            }
-        }
-    }
-
-    protected void notifyDataFrame(DataFrame frame, ByteBuffer data)
-    {
-        for (Listener listener : listeners)
-        {
-            try
-            {
-                listener.onDataFrame(frame, data);
-            }
-            catch (Exception x)
-            {
-                logger.info("Exception while notifying listener " + listener, x);
-            }
-        }
-    }
-
-    protected void notifyStreamException(StreamException x)
-    {
-        for (Listener listener : listeners)
-        {
-            try
-            {
-                listener.onStreamException(x);
-            }
-            catch (Exception xx)
-            {
-                logger.debug("Could not notify listener " + listener, xx);
-            }
-        }
-    }
-
-    protected void notifySessionException(SessionException x)
-    {
-        logger.debug("SPDY session exception", x);
-        for (Listener listener : listeners)
-        {
-            try
-            {
-                listener.onSessionException(x);
-            }
-            catch (Exception xx)
-            {
-                logger.debug("Could not notify listener " + listener, xx);
-            }
-        }
-    }
-
-    public void parse(ByteBuffer buffer)
-    {
-        logger.debug("Parsing {} bytes", buffer.remaining());
-        try
-        {
-            while (buffer.hasRemaining())
-            {
-                try
-                {
-                    switch (state)
-                    {
-                        case CONTROL_BIT:
-                        {
-                            // We must only peek the first byte and not advance the buffer
-                            // because the 7 least significant bits may be relevant in data frames
-                            int currByte = buffer.get(buffer.position());
-                            boolean isControlFrame = (currByte & 0x80) == 0x80;
-                            state = isControlFrame ? State.CONTROL_FRAME : State.DATA_FRAME;
-                            break;
-                        }
-                        case CONTROL_FRAME:
-                        {
-                            if (controlFrameParser.parse(buffer))
-                                reset();
-                            break;
-                        }
-                        case DATA_FRAME:
-                        {
-                            if (dataFrameParser.parse(buffer))
-                                reset();
-                            break;
-                        }
-                        default:
-                        {
-                            throw new IllegalStateException();
-                        }
-                    }
-                }
-                catch (StreamException x)
-                {
-                    notifyStreamException(x);
-                }
-            }
-        }
-        catch (SessionException x)
-        {
-            notifySessionException(x);
-        }
-        catch (Throwable x)
-        {
-            notifySessionException(new SessionException(SessionStatus.PROTOCOL_ERROR, x));
-        }
-        finally
-        {
-            // Be sure to consume after exceptions
-            buffer.position(buffer.limit());
-        }
-    }
-
-    private void reset()
-    {
-        state = State.CONTROL_BIT;
-    }
-
-    public interface Listener extends EventListener
-    {
-        public void onControlFrame(ControlFrame frame);
-
-        public void onDataFrame(DataFrame frame, ByteBuffer data);
-
-        public void onStreamException(StreamException x);
-
-        public void onSessionException(SessionException x);
-
-        public static class Adapter implements Listener
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-            }
-
-            @Override
-            public void onDataFrame(DataFrame frame, ByteBuffer data)
-            {
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-            }
-
-            @Override
-            public void onSessionException(SessionException x)
-            {
-            }
-        }
-    }
-
-    private enum State
-    {
-        CONTROL_BIT, CONTROL_FRAME, DATA_FRAME
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java
deleted file mode 100644
index ad4a596..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/PingBodyParser.java
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.frames.PingFrame;
-
-public class PingBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.PING_ID;
-    private int cursor;
-    private int pingId;
-
-    public PingBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case PING_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        pingId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        onPing();
-                        return true;
-                    }
-                    else
-                    {
-                        state = State.PING_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case PING_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    pingId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        onPing();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void onPing()
-    {
-        PingFrame frame = new PingFrame(controlFrameParser.getVersion(), pingId);
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        state = State.PING_ID;
-        cursor = 0;
-        pingId = 0;
-    }
-
-    private enum State
-    {
-        PING_ID, PING_ID_BYTES
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java
deleted file mode 100644
index 175fea3..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/RstStreamBodyParser.java
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-
-public class RstStreamBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-    private int statusCode;
-
-    public RstStreamBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.STATUS_CODE;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        streamId &= 0x7F_FF_FF_FF;
-                        state = State.STATUS_CODE;
-                    }
-                    break;
-                }
-                case STATUS_CODE:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        statusCode = buffer.getInt();
-                        onRstStream();
-                        return true;
-                    }
-                    else
-                    {
-                        state = State.STATUS_CODE_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STATUS_CODE_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    statusCode += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        onRstStream();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void onRstStream()
-    {
-        // TODO: check that statusCode is not 0
-        RstStreamFrame frame = new RstStreamFrame(controlFrameParser.getVersion(), streamId, statusCode);
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-        statusCode = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, STATUS_CODE, STATUS_CODE_BYTES
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java
deleted file mode 100644
index bb9623a..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SettingsBodyParser.java
+++ /dev/null
@@ -1,200 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.frames.SettingsFrame;
-
-public class SettingsBodyParser extends ControlFrameBodyParser
-{
-    private final Settings settings = new Settings();
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.COUNT;
-    private int cursor;
-    private int count;
-    private int idAndFlags;
-    private int value;
-
-    public SettingsBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case COUNT:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        count = buffer.getInt();
-                        state = State.ID_FLAGS;
-                    }
-                    else
-                    {
-                        state = State.COUNT_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case COUNT_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    count += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                        state = State.ID_FLAGS;
-                    break;
-                }
-                case ID_FLAGS:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        idAndFlags = convertIdAndFlags(controlFrameParser.getVersion(), buffer.getInt());
-                        state = State.VALUE;
-                    }
-                    else
-                    {
-                        state = State.ID_FLAGS_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case ID_FLAGS_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    value += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        idAndFlags = convertIdAndFlags(controlFrameParser.getVersion(), value);
-                        state = State.VALUE;
-                    }
-                    break;
-                }
-                case VALUE:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        value = buffer.getInt();
-                        if (onPair())
-                            return true;
-                    }
-                    else
-                    {
-                        state = State.VALUE_BYTES;
-                        cursor = 4;
-                        value = 0;
-                    }
-                    break;
-                }
-                case VALUE_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    value += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        if (onPair())
-                            return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private int convertIdAndFlags(short version, int idAndFlags)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-            {
-                // A bug in the Chromium implementation forces v2 to have
-                // 3 ID bytes little endian + 1 byte of flags
-                // Here we normalize this to conform with v3, which is
-                // 1 bytes of flag + 3 ID bytes big endian
-                int result = (idAndFlags & 0x00_00_00_FF) << 24;
-                result += (idAndFlags & 0x00_00_FF_00) << 8;
-                result += (idAndFlags & 0x00_FF_00_00) >>> 8;
-                result += (idAndFlags & 0xFF_00_00_00) >>> 24;
-                return result;
-            }
-            case SPDY.V3:
-            {
-                return idAndFlags;
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    private boolean onPair()
-    {
-        int id = idAndFlags & 0x00_FF_FF_FF;
-        byte flags = (byte)((idAndFlags & 0xFF_00_00_00) >>> 24);
-        settings.put(new Settings.Setting(Settings.ID.from(id), Settings.Flag.from(flags), value));
-        state = State.ID_FLAGS;
-        idAndFlags = 0;
-        value = 0;
-        --count;
-        if (count == 0)
-        {
-            onSettings();
-            return true;
-        }
-        return false;
-    }
-
-    private void onSettings()
-    {
-        SettingsFrame frame = new SettingsFrame(controlFrameParser.getVersion(), controlFrameParser.getFlags(), new Settings(settings, true));
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        settings.clear();
-        state = State.COUNT;
-        cursor = 0;
-        count = 0;
-        idAndFlags = 0;
-        value = 0;
-    }
-
-    private enum State
-    {
-        COUNT, COUNT_BYTES, ID_FLAGS, ID_FLAGS_BYTES, VALUE, VALUE_BYTES
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java
deleted file mode 100644
index 8b35f30..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynReplyBodyParser.java
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.util.Fields;
-
-public class SynReplyBodyParser extends ControlFrameBodyParser
-{
-    private final Fields headers = new Fields();
-    private final ControlFrameParser controlFrameParser;
-    private final HeadersBlockParser headersBlockParser;
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-
-    public SynReplyBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-        this.headersBlockParser = new SynReplyHeadersBlockParser(decompressor);
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.ADDITIONAL;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        streamId &= 0x7F_FF_FF_FF;
-                        state = State.ADDITIONAL;
-                    }
-                    break;
-                }
-                case ADDITIONAL:
-                {
-                    switch (controlFrameParser.getVersion())
-                    {
-                        case SPDY.V2:
-                        {
-                            if (buffer.remaining() >= 2)
-                            {
-                                buffer.getShort();
-                                state = State.HEADERS;
-                            }
-                            else
-                            {
-                                state = State.ADDITIONAL_BYTES;
-                                cursor = 2;
-                            }
-                            break;
-                        }
-                        case SPDY.V3:
-                        {
-                            state = State.HEADERS;
-                            break;
-                        }
-                        default:
-                        {
-                            throw new IllegalStateException();
-                        }
-                    }
-                    break;
-                }
-                case ADDITIONAL_BYTES:
-                {
-                    assert controlFrameParser.getVersion() == SPDY.V2;
-                    buffer.get();
-                    --cursor;
-                    if (cursor == 0)
-                        state = State.HEADERS;
-                    break;
-                }
-                case HEADERS:
-                {
-                    short version = controlFrameParser.getVersion();
-                    int length = controlFrameParser.getLength() - getSynReplyDataLength(version);
-                    if (headersBlockParser.parse(streamId, version, length, buffer))
-                    {
-                        byte flags = controlFrameParser.getFlags();
-                        if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
-                            throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
-
-                        SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Fields(headers, true));
-                        controlFrameParser.onControlFrame(frame);
-
-                        reset();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private int getSynReplyDataLength(short version)
-    {
-        switch (version)
-        {
-            case 2:
-                return 6;
-            case 3:
-                return 4;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private void reset()
-    {
-        headers.clear();
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, ADDITIONAL, ADDITIONAL_BYTES, HEADERS
-    }
-
-    private class SynReplyHeadersBlockParser extends HeadersBlockParser
-    {
-        public SynReplyHeadersBlockParser(CompressionFactory.Decompressor decompressor)
-        {
-            super(decompressor);
-        }
-
-        @Override
-        protected void onHeader(String name, String[] values)
-        {
-            for (String value : values)
-                headers.add(name, value);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java
deleted file mode 100644
index 6b28214..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/SynStreamBodyParser.java
+++ /dev/null
@@ -1,236 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.PushSynInfo;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.util.Fields;
-
-public class SynStreamBodyParser extends ControlFrameBodyParser
-{
-    private final Fields headers = new Fields();
-    private final ControlFrameParser controlFrameParser;
-    private final HeadersBlockParser headersBlockParser;
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-    private int associatedStreamId;
-    private byte priority;
-    private short slot;
-
-    public SynStreamBodyParser(CompressionFactory.Decompressor decompressor, ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-        this.headersBlockParser = new SynStreamHeadersBlockParser(decompressor);
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.ASSOCIATED_STREAM_ID;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        streamId &= 0x7F_FF_FF_FF;
-                        state = State.ASSOCIATED_STREAM_ID;
-                    }
-                    break;
-                }
-                case ASSOCIATED_STREAM_ID:
-                {
-                    // Now we know the streamId, we can do the version check
-                    // and if it is wrong, issue a RST_STREAM
-                    try
-                    {
-                        checkVersion(controlFrameParser.getVersion(), streamId);
-                    }
-                    catch (StreamException e)
-                    {
-                        // We've already read 4 bytes of the streamId which are part of controlFrameParser.getLength
-                        // so we need to substract those from the bytesToSkip.
-                        int bytesToSkip = controlFrameParser.getLength() - 4;
-                        int remaining = buffer.remaining();
-                        if (remaining >= bytesToSkip)
-                        {
-                            buffer.position(buffer.position() + bytesToSkip);
-                            controlFrameParser.reset();
-                            reset();
-                        }
-                        else
-                        {
-                            int bytesToSkipInNextBuffer = bytesToSkip - remaining;
-                            buffer.position(buffer.limit());
-                            controlFrameParser.skip(bytesToSkipInNextBuffer);
-                            reset();
-                        }
-                        throw e;
-                    }
-                    if (buffer.remaining() >= 4)
-                    {
-                        associatedStreamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.PRIORITY;
-                    }
-                    else
-                    {
-                        state = State.ASSOCIATED_STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case ASSOCIATED_STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    associatedStreamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        associatedStreamId &= 0x7F_FF_FF_FF;
-                        state = State.PRIORITY;
-                    }
-                    break;
-                }
-                case PRIORITY:
-                {
-                    byte currByte = buffer.get();
-                    ++cursor;
-                    if (cursor == 1)
-                    {
-                        priority = readPriority(controlFrameParser.getVersion(), currByte);
-                    }
-                    else
-                    {
-                        slot = (short)(currByte & 0xFF);
-                        cursor = 0;
-                        state = State.HEADERS;
-                    }
-                    break;
-                }
-                case HEADERS:
-                {
-                    short version = controlFrameParser.getVersion();
-                    int length = controlFrameParser.getLength() - 10;
-                    if (headersBlockParser.parse(streamId, version, length, buffer))
-                    {
-                        byte flags = controlFrameParser.getFlags();
-                        if (flags > (SynInfo.FLAG_CLOSE | PushSynInfo.FLAG_UNIDIRECTIONAL))
-                            throw new IllegalArgumentException("Invalid flag " + flags + " for frame " +
-                                    ControlFrameType.SYN_STREAM);
-
-                        SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId,
-                                priority, slot, new Fields(headers, false));
-                        controlFrameParser.onControlFrame(frame);
-
-                        reset();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void checkVersion(short version, int streamId)
-    {
-        if (version != SPDY.V2 && version != SPDY.V3)
-            throw new StreamException(streamId, StreamStatus.UNSUPPORTED_VERSION);
-    }
-
-    private byte readPriority(short version, byte currByte)
-    {
-        // Right shift retains the sign bit when operated on a byte,
-        // so we use an int to perform the shifts
-        switch (version)
-        {
-            case SPDY.V2:
-                int p2 = currByte & 0b1100_0000;
-                p2 >>>= 6;
-                return (byte)p2;
-            case SPDY.V3:
-                int p3 = currByte & 0b1110_0000;
-                p3 >>>= 5;
-                return (byte)p3;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private void reset()
-    {
-        headers.clear();
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-        associatedStreamId = 0;
-        priority = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, ASSOCIATED_STREAM_ID, ASSOCIATED_STREAM_ID_BYTES, PRIORITY, HEADERS
-    }
-
-    private class SynStreamHeadersBlockParser extends HeadersBlockParser
-    {
-        public SynStreamHeadersBlockParser(CompressionFactory.Decompressor decompressor)
-        {
-            super(decompressor);
-        }
-
-        @Override
-        protected void onHeader(String name, String[] values)
-        {
-            for (String value : values)
-                headers.add(name, value);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java
deleted file mode 100644
index 2f7a008..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameBodyParser.java
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-public class UnknownControlFrameBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.BODY;
-    private int remaining;
-
-    public UnknownControlFrameBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        switch (state)
-        {
-            case BODY:
-            {
-                remaining = controlFrameParser.getLength();
-                state = State.CONSUME;
-                // Fall down
-            }
-            case CONSUME:
-            {
-                int consume = Math.min(remaining, buffer.remaining());
-                buffer.position(buffer.position() + consume);
-                remaining -= consume;
-                if (remaining > 0)
-                    return false;
-                reset();
-                return true;
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    private void reset()
-    {
-        state = State.BODY;
-        remaining = 0;
-    }
-
-    private enum State
-    {
-        BODY, CONSUME
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java
deleted file mode 100644
index f55ecd4..0000000
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/parser/WindowUpdateBodyParser.java
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
-
-public class WindowUpdateBodyParser extends ControlFrameBodyParser
-{
-    private final ControlFrameParser controlFrameParser;
-    private State state = State.STREAM_ID;
-    private int cursor;
-    private int streamId;
-    private int windowDelta;
-
-    public WindowUpdateBodyParser(ControlFrameParser controlFrameParser)
-    {
-        this.controlFrameParser = controlFrameParser;
-    }
-
-    @Override
-    public boolean parse(ByteBuffer buffer)
-    {
-        while (buffer.hasRemaining())
-        {
-            switch (state)
-            {
-                case STREAM_ID:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        streamId = buffer.getInt() & 0x7F_FF_FF_FF;
-                        state = State.WINDOW_DELTA;
-                    }
-                    else
-                    {
-                        state = State.STREAM_ID_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case STREAM_ID_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    streamId += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        streamId &= 0x7F_FF_FF_FF;
-                        state = State.WINDOW_DELTA;
-                    }
-                    break;
-                }
-                case WINDOW_DELTA:
-                {
-                    if (buffer.remaining() >= 4)
-                    {
-                        windowDelta = buffer.getInt() & 0x7F_FF_FF_FF;
-                        onWindowUpdate();
-                        return true;
-                    }
-                    else
-                    {
-                        state = State.WINDOW_DELTA_BYTES;
-                        cursor = 4;
-                    }
-                    break;
-                }
-                case WINDOW_DELTA_BYTES:
-                {
-                    byte currByte = buffer.get();
-                    --cursor;
-                    windowDelta += (currByte & 0xFF) << 8 * cursor;
-                    if (cursor == 0)
-                    {
-                        windowDelta &= 0x7F_FF_FF_FF;
-                        onWindowUpdate();
-                        return true;
-                    }
-                    break;
-                }
-                default:
-                {
-                    throw new IllegalStateException();
-                }
-            }
-        }
-        return false;
-    }
-
-    private void onWindowUpdate()
-    {
-        WindowUpdateFrame frame = new WindowUpdateFrame(controlFrameParser.getVersion(), streamId, windowDelta);
-        controlFrameParser.onControlFrame(frame);
-        reset();
-    }
-
-    private void reset()
-    {
-        state = State.STREAM_ID;
-        cursor = 0;
-        streamId = 0;
-        windowDelta = 0;
-    }
-
-    private enum State
-    {
-        STREAM_ID, STREAM_ID_BYTES, WINDOW_DELTA, WINDOW_DELTA_BYTES;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java
deleted file mode 100644
index 969d72e..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/AsyncTimeoutTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.ByteArrayEndPoint;
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SPDYException;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.toolchain.test.AdvancedRunner;
-import org.eclipse.jetty.toolchain.test.annotation.Slow;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.thread.Scheduler;
-import org.eclipse.jetty.util.thread.TimerScheduler;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AdvancedRunner.class)
-//TODO: Uncomment comment lines and reimplement tests to fit new design
-@Ignore("Doesn't work with new Flusher class, needs to be rewritten")
-public class AsyncTimeoutTest
-{
-    EndPoint endPoint = new ByteArrayEndPoint();
-
-    @Slow
-    @Test
-    public void testAsyncTimeoutInControlFrames() throws Exception
-    {
-        final long timeout = 1000;
-        final TimeUnit unit = TimeUnit.MILLISECONDS;
-
-        ByteBufferPool bufferPool = new MappedByteBufferPool();
-        Executor threadPool = Executors.newCachedThreadPool();
-        Scheduler scheduler = new TimerScheduler();
-        scheduler.start(); // TODO need to use jetty lifecycles better here
-        Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor());
-        Session session = new StandardSession(SPDY.V2, bufferPool, scheduler, new TestController(),
-                endPoint, null, 1, null, generator, new FlowControlStrategy.None())
-        {
-//            @Override
-            public void flush()
-            {
-                try
-                {
-                    unit.sleep(2 * timeout);
-//                    super.flush();
-                }
-                catch (InterruptedException x)
-                {
-                    throw new SPDYException(x);
-                }
-            }
-        };
-
-        final CountDownLatch failedLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(timeout, unit, new Fields(), true, (byte)0), null, new Promise.Adapter<Stream>()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(failedLatch.await(2 * timeout, unit));
-    }
-
-    @Slow
-    @Test
-    public void testAsyncTimeoutInDataFrames() throws Exception
-    {
-        final long timeout = 1000;
-        final TimeUnit unit = TimeUnit.MILLISECONDS;
-
-        ByteBufferPool bufferPool = new MappedByteBufferPool();
-        Executor threadPool = Executors.newCachedThreadPool();
-        Scheduler scheduler = new TimerScheduler();
-        scheduler.start();
-        Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor());
-        Session session = new StandardSession(SPDY.V2, bufferPool, scheduler, new TestController(),
-                endPoint, null, 1, null, generator, new FlowControlStrategy.None())
-        {
-//            @Override
-            protected void write(ByteBuffer buffer, Callback callback)
-            {
-                try
-                {
-                    // Wait if we're writing the data frame (control frame's first byte is 0x80)
-                    if (buffer.get(0) == 0)
-                        unit.sleep(2 * timeout);
-//                    super.write(buffer, callback);
-                }
-                catch (InterruptedException x)
-                {
-                    throw new SPDYException(x);
-                }
-            }
-        };
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        final CountDownLatch failedLatch = new CountDownLatch(1);
-        stream.data(new StringDataInfo(timeout, unit, "data", true), new Callback.Adapter()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(failedLatch.await(2 * timeout, unit));
-    }
-
-    private static class TestController implements Controller
-    {
-        @Override
-        public void write(Callback callback, ByteBuffer... buffers)
-        {
-            callback.succeeded();
-        }
-
-        @Override
-        public void close(boolean onlyOutput)
-        {
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
deleted file mode 100644
index 80bd21c..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
+++ /dev/null
@@ -1,681 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.nio.ByteBuffer;
-import java.nio.channels.ClosedChannelException;
-import java.util.HashSet;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.spdy.frames.SettingsFrame;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.FuturePromise;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
-import org.eclipse.jetty.util.thread.Scheduler;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class StandardSessionTest
-{
-    private static final Logger LOG = Log.getLogger(StandardSessionTest.class);
-    private static final short VERSION = SPDY.V2;
-
-    @Mock
-    private Controller controller;
-
-    @Mock
-    private EndPoint endPoint;
-
-    private ExecutorService threadPool;
-    private StandardSession session;
-    private Scheduler scheduler;
-    private Fields headers;
-    private final ByteBufferPool bufferPool = new MappedByteBufferPool();
-    private final Generator generator = new Generator(bufferPool, new StandardCompressionFactory.StandardCompressor());
-
-    @Before
-    public void setUp() throws Exception
-    {
-        threadPool = Executors.newCachedThreadPool();
-        scheduler = new ScheduledExecutorScheduler();
-        scheduler.start();
-        session = new StandardSession(VERSION, bufferPool, scheduler, controller, endPoint, null, 1, null,
-                generator, new FlowControlStrategy.None());
-        when(endPoint.getIdleTimeout()).thenReturn(30000L);
-        headers = new Fields();
-    }
-
-    @After
-    public void after() throws Exception
-    {
-        scheduler.stop();
-        threadPool.shutdownNow();
-    }
-
-    @SuppressWarnings("unchecked")
-    private void setControllerWriteExpectation(final boolean fail)
-    {
-        doAnswer(new Answer()
-        {
-            public Object answer(InvocationOnMock invocation)
-            {
-                Object[] args = invocation.getArguments();
-                Callback callback = (Callback)args[0];
-                if (fail)
-                    callback.failed(new ClosedChannelException());
-                else
-                    callback.succeeded();
-                return null;
-            }
-        }).when(controller).write(any(Callback.class), any(ByteBuffer.class));
-    }
-
-    @Test
-    public void testStreamIsRemovedFromSessionWhenReset() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        assertThatStreamIsInSession(stream);
-        assertThat("stream is not reset", stream.isReset(), is(false));
-        session.rst(new RstInfo(stream.getId(), StreamStatus.STREAM_ALREADY_CLOSED));
-        assertThatStreamIsNotInSession(stream);
-        assertThatStreamIsReset(stream);
-    }
-
-    @Test
-    public void testStreamIsAddedAndRemovedFromSession() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        assertThatStreamIsInSession(stream);
-        stream.updateCloseState(true, true);
-        session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null));
-        assertThatStreamIsClosed(stream);
-        assertThatStreamIsNotInSession(stream);
-    }
-
-    @Test
-    public void testStreamIsRemovedWhenHeadersWithCloseFlagAreSent() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        assertThatStreamIsInSession(stream);
-        stream.updateCloseState(true, false);
-        stream.headers(new HeadersInfo(headers, true));
-        assertThatStreamIsClosed(stream);
-        assertThatStreamIsNotInSession(stream);
-    }
-
-    @Test
-    public void testStreamIsUnidirectional() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        assertThat("stream is not unidirectional", stream.isUnidirectional(), not(true));
-        Stream pushStream = createPushStream(stream);
-        assertThat("pushStream is unidirectional", pushStream.isUnidirectional(), is(true));
-    }
-
-    @Test
-    public void testPushStreamCreation() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        Stream stream = createStream();
-        IStream pushStream = createPushStream(stream);
-        assertThat("Push stream must be associated to the first stream created", pushStream.getAssociatedStream().getId(), is(stream.getId()));
-        assertThat("streamIds need to be monotonic", pushStream.getId(), greaterThan(stream.getId()));
-    }
-
-    @Test
-    public void testPushStreamIsNotClosedWhenAssociatedStreamIsClosed() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        Stream pushStream = createPushStream(stream);
-        assertThatStreamIsNotHalfClosed(stream);
-        assertThatStreamIsNotClosed(stream);
-        assertThatPushStreamIsHalfClosed(pushStream);
-        assertThatPushStreamIsNotClosed(pushStream);
-
-        stream.updateCloseState(true, true);
-        assertThatStreamIsHalfClosed(stream);
-        assertThatStreamIsNotClosed(stream);
-        assertThatPushStreamIsHalfClosed(pushStream);
-        assertThatPushStreamIsNotClosed(pushStream);
-
-        session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), null));
-        assertThatStreamIsClosed(stream);
-        assertThatPushStreamIsNotClosed(pushStream);
-    }
-
-    @Test
-    public void testCreatePushStreamOnClosedStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        stream.updateCloseState(true, true);
-        assertThatStreamIsHalfClosed(stream);
-        stream.updateCloseState(true, false);
-        assertThatStreamIsClosed(stream);
-        createPushStreamAndMakeSureItFails(stream);
-    }
-
-    private void createPushStreamAndMakeSureItFails(IStream stream) throws InterruptedException
-    {
-        final CountDownLatch failedLatch = new CountDownLatch(1);
-        PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
-        stream.push(pushInfo, new Promise.Adapter<Stream>()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedLatch.countDown();
-            }
-        });
-        assertThat("pushStream creation failed", failedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testPushStreamIsAddedAndRemovedFromParentAndSessionWhenClosed() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        IStream pushStream = createPushStream(stream);
-        assertThatPushStreamIsHalfClosed(pushStream);
-        assertThatPushStreamIsInSession(pushStream);
-        assertThatStreamIsAssociatedWithPushStream(stream, pushStream);
-        session.data(pushStream, new StringDataInfo("close", true), 5, TimeUnit.SECONDS, new Callback.Adapter());
-        assertThatPushStreamIsClosed(pushStream);
-        assertThatPushStreamIsNotInSession(pushStream);
-        assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream);
-    }
-
-    @Test
-    public void testPushStreamIsRemovedWhenReset() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        IStream pushStream = (IStream)stream.push(new PushInfo(new Fields(), false));
-        assertThatPushStreamIsInSession(pushStream);
-        session.rst(new RstInfo(pushStream.getId(), StreamStatus.INVALID_STREAM));
-        assertThatPushStreamIsNotInSession(pushStream);
-        assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream);
-        assertThatStreamIsReset(pushStream);
-    }
-
-    @Test
-    public void testPushStreamWithSynInfoClosedTrue() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, true);
-        IStream pushStream = (IStream)stream.push(pushInfo);
-        assertThatPushStreamIsHalfClosed(pushStream);
-        assertThatPushStreamIsClosed(pushStream);
-        assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream);
-        assertThatStreamIsNotInSession(pushStream);
-    }
-
-    @Test
-    public void testPushStreamSendHeadersWithCloseFlagIsRemovedFromSessionAndDisassociateFromParent() throws InterruptedException, ExecutionException,
-            TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = createStream();
-        PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
-        IStream pushStream = (IStream)stream.push(pushInfo);
-        assertThatStreamIsAssociatedWithPushStream(stream, pushStream);
-        assertThatPushStreamIsInSession(pushStream);
-        pushStream.headers(new HeadersInfo(headers, true));
-        assertThatPushStreamIsNotInSession(pushStream);
-        assertThatPushStreamIsHalfClosed(pushStream);
-        assertThatPushStreamIsClosed(pushStream);
-        assertThatStreamIsNotAssociatedWithPushStream(stream, pushStream);
-    }
-
-    @Test
-    public void testCreatedAndClosedListenersAreCalledForNewStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        final CountDownLatch createdListenerCalledLatch = new CountDownLatch(1);
-        final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1);
-        session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch));
-        IStream stream = createStream();
-        session.onControlFrame(new SynReplyFrame(VERSION, (byte)0, stream.getId(), new Fields()));
-        session.onDataFrame(new DataFrame(stream.getId(), SynInfo.FLAG_CLOSE, 128), ByteBuffer.allocate(128));
-        stream.data(new StringDataInfo("close", true));
-        assertThat("onStreamCreated listener has been called", createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch);
-    }
-
-    @Test
-    public void testListenerIsCalledForResetStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1);
-        session.addListener(new TestStreamListener(null, closedListenerCalledLatch));
-        IStream stream = createStream();
-        session.rst(new RstInfo(stream.getId(), StreamStatus.CANCEL_STREAM));
-        assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch);
-    }
-
-    @Test
-    public void testCreatedAndClosedListenersAreCalledForNewPushStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        final CountDownLatch createdListenerCalledLatch = new CountDownLatch(2);
-        final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1);
-        session.addListener(new TestStreamListener(createdListenerCalledLatch, closedListenerCalledLatch));
-        IStream stream = createStream();
-        IStream pushStream = createPushStream(stream);
-        session.data(pushStream, new StringDataInfo("close", true), 5, TimeUnit.SECONDS, new Callback.Adapter());
-        assertThat("onStreamCreated listener has been called twice. Once for the stream and once for the pushStream",
-                createdListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch);
-    }
-
-    @Test
-    public void testListenerIsCalledForResetPushStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        final CountDownLatch closedListenerCalledLatch = new CountDownLatch(1);
-        session.addListener(new TestStreamListener(null, closedListenerCalledLatch));
-        IStream stream = createStream();
-        IStream pushStream = createPushStream(stream);
-        session.rst(new RstInfo(pushStream.getId(), StreamStatus.CANCEL_STREAM));
-        assertThatOnStreamClosedListenerHasBeenCalled(closedListenerCalledLatch);
-    }
-
-    private class TestStreamListener extends Session.StreamListener.Adapter
-    {
-        private CountDownLatch createdListenerCalledLatch;
-        private CountDownLatch closedListenerCalledLatch;
-
-        public TestStreamListener(CountDownLatch createdListenerCalledLatch, CountDownLatch closedListenerCalledLatch)
-        {
-            this.createdListenerCalledLatch = createdListenerCalledLatch;
-            this.closedListenerCalledLatch = closedListenerCalledLatch;
-        }
-
-        @Override
-        public void onStreamCreated(Stream stream)
-        {
-            if (createdListenerCalledLatch != null)
-                createdListenerCalledLatch.countDown();
-            super.onStreamCreated(stream);
-        }
-
-        @Override
-        public void onStreamClosed(Stream stream)
-        {
-            if (closedListenerCalledLatch != null)
-                closedListenerCalledLatch.countDown();
-            super.onStreamClosed(stream);
-        }
-    }
-
-    @Test
-    @Ignore("In V3 we need to rst the stream if we receive data on a remotely half closed stream.")
-    public void receiveDataOnRemotelyHalfClosedStreamResetsStreamInV3() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        IStream stream = (IStream)session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter());
-        stream.updateCloseState(true, false);
-        assertThat("stream is half closed from remote side", stream.isHalfClosed(), is(true));
-        stream.process(new ByteBufferDataInfo(ByteBuffer.allocate(256), true));
-    }
-
-    @Test
-    public void testReceiveDataOnRemotelyClosedStreamIsIgnored() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        final CountDownLatch onDataCalledLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        onDataCalledLatch.countDown();
-                        super.onData(stream, dataInfo);
-                    }
-                });
-        session.onControlFrame(new SynReplyFrame(VERSION, SynInfo.FLAG_CLOSE, stream.getId(), headers));
-        session.onDataFrame(new DataFrame(stream.getId(), (byte)0, 0), ByteBuffer.allocate(128));
-        assertThat("onData is never called", onDataCalledLatch.await(1, TimeUnit.SECONDS), not(true));
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testControllerWriteFails() throws Exception
-    {
-        final AtomicInteger writes = new AtomicInteger();
-        final AtomicBoolean fail = new AtomicBoolean();
-        Controller controller = new Controller()
-        {
-            @Override
-            public void write(Callback callback, ByteBuffer... buffers)
-            {
-                writes.incrementAndGet();
-                if (fail.get())
-                    callback.failed(new ClosedChannelException());
-                else
-                    callback.succeeded();
-            }
-
-            @Override
-            public void close(boolean onlyOutput)
-            {
-
-            }
-        };
-        ISession session = new StandardSession(VERSION, bufferPool, scheduler, controller, endPoint, null, 1, null, generator, null);
-        IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null);
-        stream.updateWindowSize(8192);
-
-        // Send a reply to comply with the API usage
-        stream.reply(new ReplyInfo(false), new Callback.Adapter());
-
-        // Make the controller fail
-        fail.set(true);
-        final CountDownLatch failedCalledLatch = new CountDownLatch(1);
-        Callback.Adapter callback = new Callback.Adapter()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedCalledLatch.countDown();
-            }
-        };
-        // Data frame should fail on controller.write()
-        stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), callback);
-
-        Assert.assertEquals(2, writes.get());
-        Assert.assertTrue(failedCalledLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testControlFramesAreStillSentForResetStreams() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        setControllerWriteExpectation(false);
-
-        // This is necessary to keep the compression context of Headers valid
-        IStream stream = createStream();
-        session.rst(new RstInfo(stream.getId(), StreamStatus.INVALID_STREAM));
-        stream.headers(new HeadersInfo(headers, true));
-
-        verify(controller, times(3)).write(any(Callback.class), any(ByteBuffer.class));
-    }
-
-    @Test
-    public void testMaxConcurrentStreams() throws InterruptedException
-    {
-        final CountDownLatch failedBecauseMaxConcurrentStreamsExceeded = new CountDownLatch(1);
-
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0));
-        SettingsFrame settingsFrame = new SettingsFrame(VERSION, (byte)0, settings);
-        session.onControlFrame(settingsFrame);
-
-        PushSynInfo pushSynInfo = new PushSynInfo(1, new PushInfo(new Fields(), false));
-        session.syn(pushSynInfo, null, new Promise.Adapter<Stream>()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedBecauseMaxConcurrentStreamsExceeded.countDown();
-            }
-        });
-
-        assertThat("Opening push stream failed because maxConcurrentStream is exceeded",
-                failedBecauseMaxConcurrentStreamsExceeded.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testHeaderFramesAreSentInTheOrderTheyAreCreated() throws ExecutionException,
-            TimeoutException, InterruptedException
-    {
-        testHeaderFramesAreSentInOrder((byte)0, (byte)0, (byte)0);
-    }
-
-    @Test
-    public void testHeaderFramesAreSentInTheOrderTheyAreCreatedWithPrioritization() throws ExecutionException,
-            TimeoutException, InterruptedException
-    {
-        testHeaderFramesAreSentInOrder((byte)0, (byte)1, (byte)2);
-    }
-
-    private void testHeaderFramesAreSentInOrder(final byte priority0, final byte priority1, final byte priority2) throws InterruptedException, ExecutionException
-    {
-        final StandardSession testLocalSession = new StandardSession(VERSION, bufferPool, scheduler,
-                new ControllerMock(), endPoint, null, 1, null, generator, new FlowControlStrategy.None());
-        HashSet<Future> tasks = new HashSet<>();
-
-        int numberOfTasksToRun = 128;
-        for (int i = 0; i < numberOfTasksToRun; i++)
-        {
-            tasks.add(threadPool.submit(new Runnable()
-            {
-
-                @Override
-                public void run()
-                {
-                    synStream(priority0);
-                    synStream(priority1);
-                    synStream(priority2);
-                }
-
-                private void synStream(byte priority)
-                {
-                    SynInfo synInfo = new SynInfo(headers, false, priority);
-                    testLocalSession.syn(synInfo, new StreamFrameListener.Adapter(), new FuturePromise<Stream>());
-                }
-            }));
-        }
-
-        for (Future task : tasks)
-        {
-            task.get();
-        }
-
-        threadPool.shutdown();
-        threadPool.awaitTermination(60, TimeUnit.SECONDS);
-    }
-
-    private class ControllerMock implements Controller
-    {
-        long lastStreamId = 0;
-
-        @Override
-        public void write(Callback callback, ByteBuffer... buffers)
-        {
-            StandardSession.FrameBytes frameBytes = (StandardSession.FrameBytes)callback;
-
-            int streamId = frameBytes.getStream().getId();
-            if (LOG.isDebugEnabled())
-                LOG.debug("last: {}, current: {}", lastStreamId, streamId);
-            if (lastStreamId < streamId)
-                lastStreamId = streamId;
-            else
-                throw new IllegalStateException("Last streamId: " + lastStreamId + " is not smaller than current StreamId: " +
-                        streamId);
-            frameBytes.succeeded();
-        }
-
-        @Override
-        public void close(boolean onlyOutput)
-        {
-        }
-    }
-
-    private IStream createStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        SynInfo synInfo = new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0);
-        return (IStream)session.syn(synInfo, new StreamFrameListener.Adapter());
-    }
-
-    private IStream createPushStream(Stream stream) throws InterruptedException, ExecutionException, TimeoutException
-    {
-        PushInfo pushInfo = new PushInfo(5, TimeUnit.SECONDS, headers, false);
-        return (IStream)stream.push(pushInfo);
-    }
-
-    private void assertThatStreamIsClosed(IStream stream)
-    {
-        assertThat("stream is closed", stream.isClosed(), is(true));
-    }
-
-    private void assertThatStreamIsReset(IStream stream)
-    {
-        assertThat("stream is reset", stream.isReset(), is(true));
-    }
-
-    private void assertThatStreamIsNotInSession(IStream stream)
-    {
-        assertThat("stream is not in session", session.getStreams().contains(stream), not(true));
-    }
-
-    private void assertThatStreamIsInSession(IStream stream)
-    {
-        assertThat("stream is in session", session.getStreams().contains(stream), is(true));
-    }
-
-    private void assertThatStreamIsNotClosed(IStream stream)
-    {
-        assertThat("stream is not closed", stream.isClosed(), not(true));
-    }
-
-    private void assertThatStreamIsNotHalfClosed(IStream stream)
-    {
-        assertThat("stream is not halfClosed", stream.isHalfClosed(), not(true));
-    }
-
-    private void assertThatPushStreamIsNotClosed(Stream pushStream)
-    {
-        assertThat("pushStream is not closed", pushStream.isClosed(), not(true));
-    }
-
-    private void assertThatStreamIsHalfClosed(IStream stream)
-    {
-        assertThat("stream is halfClosed", stream.isHalfClosed(), is(true));
-    }
-
-    private void assertThatStreamIsNotAssociatedWithPushStream(IStream stream, IStream pushStream)
-    {
-        assertThat("pushStream is removed from parent", stream.getPushedStreams().contains(pushStream), not(true));
-    }
-
-    private void assertThatPushStreamIsNotInSession(Stream pushStream)
-    {
-        assertThat("pushStream is not in session", session.getStreams().contains(pushStream), not(true));
-    }
-
-    private void assertThatPushStreamIsInSession(Stream pushStream)
-    {
-        assertThat("pushStream is in session", session.getStreams().contains(pushStream), is(true));
-    }
-
-    private void assertThatStreamIsAssociatedWithPushStream(IStream stream, Stream pushStream)
-    {
-        assertThat("stream is associated with pushStream", stream.getPushedStreams().contains(pushStream), is(true));
-    }
-
-    private void assertThatPushStreamIsClosed(Stream pushStream)
-    {
-        assertThat("pushStream is closed", pushStream.isClosed(), is(true));
-    }
-
-    private void assertThatPushStreamIsHalfClosed(Stream pushStream)
-    {
-        assertThat("pushStream is half closed ", pushStream.isHalfClosed(), is(true));
-    }
-
-    private void assertThatOnStreamClosedListenerHasBeenCalled(final CountDownLatch closedListenerCalledLatch) throws InterruptedException
-    {
-        assertThat("onStreamClosed listener has been called", closedListenerCalledLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java
deleted file mode 100644
index ee79f81..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardStreamTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy;
-
-import java.nio.channels.ClosedChannelException;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.toolchain.test.annotation.Slow;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class StandardStreamTest
-{
-    private final ScheduledExecutorScheduler scheduler = new ScheduledExecutorScheduler();
-    @Mock
-    private ISession session;
-    @Mock
-    private SynStreamFrame synStreamFrame;
-
-    @Before
-    public void setUp() throws Exception
-    {
-        scheduler.start();
-    }
-
-    @After
-    public void tearDown() throws Exception
-    {
-        scheduler.stop();
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testSyn()
-    {
-        Stream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session, null, null, null);
-        Set<Stream> streams = new HashSet<>();
-        streams.add(stream);
-        when(synStreamFrame.isClose()).thenReturn(false);
-        PushInfo pushInfo = new PushInfo(new Fields(), false);
-        when(session.getStreams()).thenReturn(streams);
-        stream.push(pushInfo, new Promise.Adapter<Stream>());
-        verify(session).syn(argThat(new PushSynInfoMatcher(stream.getId(), pushInfo)),
-                any(StreamFrameListener.class), any(Promise.class));
-    }
-
-    private class PushSynInfoMatcher extends ArgumentMatcher<PushSynInfo>
-    {
-        private int associatedStreamId;
-        private PushInfo pushInfo;
-
-        public PushSynInfoMatcher(int associatedStreamId, PushInfo pushInfo)
-        {
-            this.associatedStreamId = associatedStreamId;
-            this.pushInfo = pushInfo;
-        }
-
-        @Override
-        public boolean matches(Object argument)
-        {
-            PushSynInfo pushSynInfo = (PushSynInfo)argument;
-            return pushSynInfo.getAssociatedStreamId() == associatedStreamId && pushSynInfo.isClose() == pushInfo.isClose();
-        }
-    }
-
-    @Test
-    public void testSynOnClosedStream()
-    {
-        IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session,
-                null, null , null);
-        stream.updateCloseState(true, true);
-        stream.updateCloseState(true, false);
-        assertThat("stream expected to be closed", stream.isClosed(), is(true));
-        final CountDownLatch failedLatch = new CountDownLatch(1);
-        stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false), new Promise.Adapter<Stream>()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedLatch.countDown();
-            }
-        });
-        assertThat("PushStream creation failed", failedLatch.getCount(), equalTo(0L));
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test(expected = IllegalStateException.class)
-    public void testSendDataOnHalfClosedStream() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        SynStreamFrame synStreamFrame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, null);
-        IStream stream = new StandardStream(synStreamFrame.getStreamId(), synStreamFrame.getPriority(), session,
-                null, scheduler, null);
-        stream.updateWindowSize(8192);
-        stream.updateCloseState(synStreamFrame.isClose(), true);
-        assertThat("stream is half closed", stream.isHalfClosed(), is(true));
-        stream.data(new StringDataInfo("data on half closed stream", true));
-        verify(session, never()).data(any(IStream.class), any(DataInfo.class), anyInt(), any(TimeUnit.class), any(Callback.class));
-    }
-
-    @Test
-    @Slow
-    public void testIdleTimeout() throws Exception
-    {
-        IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null);
-        long idleTimeout = 500;
-        stream.setIdleTimeout(idleTimeout);
-
-        final AtomicInteger failureCount = new AtomicInteger();
-        final CountDownLatch failureLatch = new CountDownLatch(1);
-        stream.setStreamFrameListener(new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onFailure(Stream stream, Throwable x)
-            {
-                assertThat("exception is a TimeoutException", x, is(instanceOf(TimeoutException.class)));
-                failureCount.incrementAndGet();
-                failureLatch.countDown();
-            }
-        });
-        stream.process(new StringDataInfo("string", false));
-
-        // Wait more than (2 * idleTimeout) to be sure to trigger a failureCount > 1
-        Thread.sleep(3 * idleTimeout);
-
-        assertThat("onFailure has been called", failureLatch.await(5, TimeUnit.SECONDS), is(true));
-        Assert.assertEquals(1, failureCount.get());
-    }
-
-    @Test
-    @Slow
-    public void testIdleTimeoutIsInterruptedWhenReceiving() throws Exception
-    {
-        final CountDownLatch failureLatch = new CountDownLatch(1);
-        IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null);
-        long idleTimeout = 1000;
-        stream.setIdleTimeout(idleTimeout);
-        stream.setStreamFrameListener(new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onFailure(Stream stream, Throwable x)
-            {
-                assertThat("exception is a TimeoutException", x, is(instanceOf(TimeoutException.class)));
-                failureLatch.countDown();
-            }
-        });
-        stream.process(new SynStreamFrame(SPDY.V3, (byte)0, 1, 0, (byte)0, (short)0, null));
-        stream.process(new StringDataInfo("string", false));
-        Thread.sleep(idleTimeout / 2);
-        stream.process(new StringDataInfo("string", false));
-        Thread.sleep(idleTimeout / 2);
-        stream.process(new StringDataInfo("string", false));
-        Thread.sleep(idleTimeout / 2);
-        stream.process(new StringDataInfo("string", true));
-        stream.reply(new ReplyInfo(true), new Callback.Adapter());
-        Thread.sleep(idleTimeout);
-        assertThat("onFailure has not been called", failureLatch.await(idleTimeout, TimeUnit.MILLISECONDS), is(false));
-    }
-
-    @Test
-    @Slow
-    public void testReplyFailureClosesStream() throws Exception
-    {
-        ISession session = new StandardSession(SPDY.V3, null, null, null, null, null, 1, null, null, null)
-        {
-            @Override
-            public void control(IStream stream, ControlFrame frame, long timeout, TimeUnit unit, Callback callback)
-            {
-                callback.failed(new ClosedChannelException());
-            }
-        };
-        IStream stream = new StandardStream(1, (byte)0, session, null, scheduler, null);
-        final AtomicInteger failureCount = new AtomicInteger();
-        stream.setStreamFrameListener(new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onFailure(Stream stream, Throwable x)
-            {
-                failureCount.incrementAndGet();
-            }
-        });
-        long idleTimeout = 500;
-        stream.setIdleTimeout(idleTimeout);
-
-        stream.process(new SynStreamFrame(SPDY.V3, (byte)0, 1, 0, (byte)0, (short)0, null));
-
-        final CountDownLatch failureLatch = new CountDownLatch(1);
-        stream.reply(new ReplyInfo(false), new Callback.Adapter()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failureLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
-
-        // Make sure that the idle timeout never fires, since the failure above should have closed the stream
-        Thread.sleep(3 * idleTimeout);
-
-        Assert.assertEquals(0, failureCount.get());
-        Assert.assertTrue(stream.isClosed());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java
deleted file mode 100644
index bd1ea53..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ClientUsageTest.java
+++ /dev/null
@@ -1,260 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.spdy.StandardSession;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore
-public class ClientUsageTest
-{
-    @Test
-    public void testClientRequestResponseNoBody() throws Exception
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null);
-
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                // Do something with the response
-                replyInfo.getHeaders().get("host");
-
-                // Then issue another similar request
-                try
-                {
-                    stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                }
-                catch (ExecutionException | InterruptedException | TimeoutException e)
-                {
-                    throw new IllegalStateException(e);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void testClientReceivesPush1() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null);
-
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                return new Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                    }
-                };
-            };
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                // Do something with the response
-                replyInfo.getHeaders().get("host");
-
-                // Then issue another similar request
-                try
-                {
-                    stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                }
-                catch (ExecutionException | InterruptedException | TimeoutException e)
-                {
-                    throw new IllegalStateException(e);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void testClientReceivesPush2() throws InterruptedException, ExecutionException, TimeoutException
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, new SessionFrameListener.Adapter()
-        {
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                    }
-                };
-            }
-        }, null, null);
-
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                // Do something with the response
-                replyInfo.getHeaders().get("host");
-
-                // Then issue another similar request
-                try
-                {
-                    stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                }
-                catch (ExecutionException | InterruptedException | TimeoutException e)
-                {
-                    throw new IllegalStateException(e);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void testClientRequestWithBodyResponseNoBody() throws Exception
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null);
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        // Do something with the response
-                        replyInfo.getHeaders().get("host");
-
-                        // Then issue another similar request
-                        try
-                        {
-                            stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                        }
-                        catch (ExecutionException | InterruptedException | TimeoutException e)
-                        {
-                            throw new IllegalStateException(e);
-                        }
-                    }
-                });
-        // Send-and-forget the data
-        stream.data(new StringDataInfo("data", true));
-    }
-
-    @Test
-    public void testAsyncClientRequestWithBodyResponseNoBody() throws Exception
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null);
-
-        final String context = "context";
-        session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        // Do something with the response
-                        replyInfo.getHeaders().get("host");
-
-                        // Then issue another similar request
-                        try
-                        {
-                            stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                        }
-                        catch (ExecutionException | InterruptedException | TimeoutException e)
-                        {
-                            throw new IllegalStateException(e);
-                        }
-                    }
-                }, new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream stream)
-                    {
-                        // Differently from JDK 7 AIO, there is no need to
-                        // have an explicit parameter for the context since
-                        // that is captured while the handler is created anyway,
-                        // and it is used only by the handler as parameter
-
-                        // The style below is fire-and-forget, since
-                        // we do not pass the handler nor we call get()
-                        // to wait for the data to be sent
-                        stream.data(new StringDataInfo(context, true), new Callback.Adapter());
-                    }
-                }
-        );
-    }
-
-    @Test
-    public void testAsyncClientRequestWithBodyAndResponseWithBody() throws Exception
-    {
-        Session session = new StandardSession(SPDY.V2, null, null, null, null, null, 1, null, null, null);
-
-        session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-                {
-                    // The good of passing the listener to push() is that applications can safely
-                    // accumulate info from the reply headers to be used in the data callback,
-                    // e.g. content-type, charset, etc.
-
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        // Do something with the response
-                        Fields headers = replyInfo.getHeaders();
-                        int contentLength = headers.get("content-length").getValueAsInt();
-                        stream.setAttribute("content-length", contentLength);
-                        if (!replyInfo.isClose())
-                            stream.setAttribute("builder", new StringBuilder());
-
-                        // May issue another similar request while waiting for data
-                        try
-                        {
-                            stream.getSession().syn(new SynInfo(new Fields(), true), this);
-                        }
-                        catch (ExecutionException | InterruptedException | TimeoutException e)
-                        {
-                            throw new IllegalStateException(e);
-                        }
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        StringBuilder builder = (StringBuilder)stream.getAttribute("builder");
-                        builder.append(dataInfo.asString(StandardCharsets.UTF_8, true));
-
-                    }
-                }, new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream stream)
-                    {
-                        stream.data(new BytesDataInfo("wee".getBytes(StandardCharsets.UTF_8), false), new Callback.Adapter());
-                        stream.data(new StringDataInfo("foo", false), new Callback.Adapter());
-                        stream.data(new ByteBufferDataInfo(StandardCharsets.UTF_8.encode("bar"), true), new Callback.Adapter());
-                    }
-                }
-        );
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java
deleted file mode 100644
index 88a94ac..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/api/ServerUsageTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.api;
-
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore
-public class ServerUsageTest
-{
-    @Test
-    public void testServerSynAndReplyWithData() throws Exception
-    {
-        ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo)
-            {
-                Fields synHeaders = streamInfo.getHeaders();
-                // Do something with headers, for example extract them and
-                // perform an http request via Jetty's LocalConnector
-
-                // Get the http response, fill headers and data
-                Fields replyHeaders = new Fields();
-                replyHeaders.put(synHeaders.get("host"));
-                // Sends a reply
-                stream.reply(new ReplyInfo(replyHeaders, false), new Callback.Adapter());
-
-                // Sends data
-                StringDataInfo dataInfo = new StringDataInfo("foo", false);
-                stream.data(dataInfo, new Callback.Adapter());
-                // Stream is now closed
-                return null;
-            }
-        };
-        Assert.assertNotNull(ssfl);
-    }
-
-    @Test
-    public void testServerInitiatesStreamAndPushesData() throws Exception
-    {
-        ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                // SPDY does not allow the server to initiate a stream without an existing stream
-                // being opened by the client already.
-                // Correct SPDY sequence will be:
-                // C ---       SYN_STREAM(id=1)       --> S
-                // C <--       SYN_REPLY(id=1)        --- S
-                // C <-- SYN_STREAM(id=2,uni,assId=1) --- S
-                //
-                // However, the API may allow to initiate the stream
-
-                session.syn(new SynInfo(new Fields(), false), null, new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream stream)
-                    {
-                        // The point here is that we have no idea if the client accepted our stream
-                        // So we return a stream, we may be able to send the headers frame, but later
-                        // the client sends a rst frame.
-                        // We have to atomically set some flag on the stream to signal it's closed
-                        // and any operation on it will throw
-                        stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter());
-                    }
-                });
-            }
-        };
-        Assert.assertNotNull(ssfl);
-    }
-
-    @Test
-    public void testServerPush() throws Exception
-    {
-        ServerSessionFrameListener ssfl = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo streamInfo)
-            {
-                // Need to send the reply first
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-
-                Session session = stream.getSession();
-                // Since it's unidirectional, no need to pass the listener
-                session.syn(new SynInfo(new Fields(), false, (byte)0), null, new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream pushStream)
-                    {
-                        pushStream.data(new StringDataInfo("foo", false), new Callback.Adapter());
-                    }
-                });
-                return null;
-            }
-        };
-        Assert.assertNotNull(ssfl);
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java
deleted file mode 100644
index e1c10ec..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/CredentialGenerateParseTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.security.KeyStore;
-import java.security.cert.Certificate;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.resource.Resource;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class CredentialGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        short slot = 1;
-        byte[] proof = new byte[]{0, 1, 2};
-        Certificate[] temp = loadCertificates();
-        Certificate[] certificates = new Certificate[temp.length * 2];
-        System.arraycopy(temp, 0, certificates, 0, temp.length);
-        System.arraycopy(temp, 0, certificates, temp.length, temp.length);
-        CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType());
-        CredentialFrame credential = (CredentialFrame)frame2;
-        Assert.assertEquals(SPDY.V3, credential.getVersion());
-        Assert.assertEquals(0, credential.getFlags());
-        Assert.assertEquals(slot, credential.getSlot());
-        Assert.assertArrayEquals(proof, credential.getProof());
-        Assert.assertArrayEquals(certificates, credential.getCertificateChain());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        short slot = 1;
-        byte[] proof = new byte[]{0, 1, 2};
-        Certificate[] certificates = loadCertificates();
-        CredentialFrame frame1 = new CredentialFrame(SPDY.V3, slot, proof, certificates);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.CREDENTIAL, frame2.getType());
-        CredentialFrame credential = (CredentialFrame)frame2;
-        Assert.assertEquals(SPDY.V3, credential.getVersion());
-        Assert.assertEquals(0, credential.getFlags());
-        Assert.assertEquals(slot, credential.getSlot());
-        Assert.assertArrayEquals(proof, credential.getProof());
-        Assert.assertArrayEquals(certificates, credential.getCertificateChain());
-    }
-
-    private Certificate[] loadCertificates() throws Exception
-    {
-        KeyStore keyStore = KeyStore.getInstance("JKS");
-        InputStream keyStoreStream = Resource.newResource("src/test/resources/keystore.jks").getInputStream();
-        keyStore.load(keyStoreStream, "storepwd".toCharArray());
-        return keyStore.getCertificateChain("mykey");
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java
deleted file mode 100644
index a209fe8..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/DataGenerateParseTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DataGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        testGenerateParse("test1");
-    }
-
-    @Test
-    public void testGenerateParseZeroLength() throws Exception
-    {
-        testGenerateParse("");
-    }
-
-    private void testGenerateParse(String content) throws Exception
-    {
-        int length = content.length();
-        DataInfo data = new StringDataInfo(content, true);
-        int streamId = 13;
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.data(streamId, 2 * length, data);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        DataFrame frame2 = listener.getDataFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(streamId, frame2.getStreamId());
-        Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags());
-        Assert.assertEquals(length, frame2.getLength());
-        Assert.assertEquals(length, listener.getData().remaining());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        String content = "test2";
-        int length = content.length();
-        DataInfo data = new StringDataInfo(content, true);
-        int streamId = 13;
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.data(streamId, 2 * length, data);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-        {
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-            if (buffer.remaining() < length)
-            {
-                DataFrame frame2 = listener.getDataFrame();
-                Assert.assertNotNull(frame2);
-                Assert.assertEquals(streamId, frame2.getStreamId());
-                Assert.assertEquals(buffer.hasRemaining() ? 0 : DataInfo.FLAG_CLOSE, frame2.getFlags());
-                Assert.assertEquals(1, frame2.getLength());
-                Assert.assertEquals(1, listener.getData().remaining());
-            }
-        }
-    }
-
-    @Test
-    public void testGenerateParseWithSyntheticFrames() throws Exception
-    {
-        String content = "0123456789ABCDEF";
-        int length = content.length();
-        DataInfo data = new StringDataInfo(content, true);
-        int streamId = 13;
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.data(streamId, 2 * length, data);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-
-        // Split the buffer to simulate a split boundary in receiving the bytes
-        int split = 3;
-        ByteBuffer buffer1 = ByteBuffer.allocate(buffer.remaining() - split);
-        buffer.limit(buffer.limit() - split);
-        buffer1.put(buffer);
-        buffer1.flip();
-        ByteBuffer buffer2 = ByteBuffer.allocate(split);
-        buffer.limit(buffer.limit() + split);
-        buffer2.put(buffer);
-        buffer2.flip();
-
-        parser.parse(buffer1);
-        DataFrame frame2 = listener.getDataFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(streamId, frame2.getStreamId());
-        Assert.assertEquals(0, frame2.getFlags());
-        Assert.assertEquals(length - split, frame2.getLength());
-        Assert.assertEquals(length - split, listener.getData().remaining());
-
-        parser.parse(buffer2);
-        DataFrame frame3 = listener.getDataFrame();
-
-        Assert.assertNotNull(frame3);
-        Assert.assertEquals(streamId, frame3.getStreamId());
-        Assert.assertEquals(DataInfo.FLAG_CLOSE, frame3.getFlags());
-        Assert.assertEquals(split, frame3.getLength());
-        Assert.assertEquals(split, listener.getData().remaining());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java
deleted file mode 100644
index 11ce7ea..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/GoAwayGenerateParseTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class GoAwayGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        int lastStreamId = 13;
-        int statusCode = 1;
-        GoAwayFrame frame1 = new GoAwayFrame(SPDY.V3, lastStreamId, statusCode);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.GO_AWAY, frame2.getType());
-        GoAwayFrame goAway = (GoAwayFrame)frame2;
-        Assert.assertEquals(SPDY.V3, goAway.getVersion());
-        Assert.assertEquals(lastStreamId, goAway.getLastStreamId());
-        Assert.assertEquals(0, goAway.getFlags());
-        Assert.assertEquals(statusCode, goAway.getStatusCode());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        int lastStreamId = 13;
-        int statusCode = 1;
-        GoAwayFrame frame1 = new GoAwayFrame(SPDY.V3, lastStreamId, statusCode);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.GO_AWAY, frame2.getType());
-        GoAwayFrame goAway = (GoAwayFrame)frame2;
-        Assert.assertEquals(SPDY.V3, goAway.getVersion());
-        Assert.assertEquals(lastStreamId, goAway.getLastStreamId());
-        Assert.assertEquals(0, goAway.getFlags());
-        Assert.assertEquals(statusCode, goAway.getStatusCode());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java
deleted file mode 100644
index 03c3cd4..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/HeadersGenerateParseTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Before;
-import org.junit.Test;
-
-public class HeadersGenerateParseTest
-{
-
-    private Fields headers = new Fields();
-    private int streamId = 13;
-    private byte flags = HeadersInfo.FLAG_RESET_COMPRESSION;
-    private final TestSPDYParserListener listener = new TestSPDYParserListener();
-    private final Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-    private ByteBuffer buffer;
-
-    @Before
-    public void setUp()
-    {
-        parser.addListener(listener);
-        headers.put("a", "b");
-        buffer = createHeadersFrameBuffer(headers);
-    }
-
-    private ByteBuffer createHeadersFrameBuffer(Fields headers)
-    {
-        HeadersFrame frame1 = new HeadersFrame(SPDY.V2, flags, streamId, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-        assertThat("Buffer is not null", buffer, notNullValue());
-        return buffer;
-    }
-
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        parser.parse(buffer);
-        assertExpectationsAreMet(headers);
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-
-        assertExpectationsAreMet(headers);
-    }
-
-    @Test
-    public void testHeadersAreTranslatedToLowerCase()
-    {
-        Fields headers = new Fields();
-        headers.put("Via","localhost");
-        parser.parse(createHeadersFrameBuffer(headers));
-        HeadersFrame parsedHeadersFrame = assertExpectationsAreMet(headers);
-        Fields.Field viaHeader = parsedHeadersFrame.getHeaders().get("via");
-        assertThat("Via Header name is lowercase", viaHeader.getName(), is("via"));
-    }
-
-    private HeadersFrame assertExpectationsAreMet(Fields headers)
-    {
-        ControlFrame parsedControlFrame = listener.getControlFrame();
-        assertThat("listener received controlFrame", parsedControlFrame, notNullValue());
-        assertThat("ControlFrame type is HEADERS", ControlFrameType.HEADERS, is(parsedControlFrame.getType()));
-        HeadersFrame headersFrame = (HeadersFrame)parsedControlFrame;
-        assertThat("Version matches", SPDY.V2, is(headersFrame.getVersion()));
-        assertThat("StreamId matches", streamId, is(headersFrame.getStreamId()));
-        assertThat("flags match", flags, is(headersFrame.getFlags()));
-        assertThat("headers match", headers, is(headersFrame.getHeaders()));
-        return headersFrame;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java
deleted file mode 100644
index 7795337..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/NoOpGenerateParseTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class NoOpGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        NoOpFrame frame1 = new NoOpFrame();
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.NOOP, frame2.getType());
-        NoOpFrame noOp = (NoOpFrame)frame2;
-        Assert.assertEquals(0, noOp.getFlags());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        NoOpFrame frame1 = new NoOpFrame();
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.NOOP, frame2.getType());
-        NoOpFrame noOp = (NoOpFrame)frame2;
-        Assert.assertEquals(0, noOp.getFlags());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java
deleted file mode 100644
index f34ed57..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/PingGenerateParseTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PingGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        int pingId = 13;
-        PingFrame frame1 = new PingFrame(SPDY.V2, pingId);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.PING, frame2.getType());
-        PingFrame ping = (PingFrame)frame2;
-        Assert.assertEquals(SPDY.V2, ping.getVersion());
-        Assert.assertEquals(pingId, ping.getPingId());
-        Assert.assertEquals(0, ping.getFlags());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        int pingId = 13;
-        PingFrame frame1 = new PingFrame(SPDY.V2, pingId);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.PING, frame2.getType());
-        PingFrame ping = (PingFrame)frame2;
-        Assert.assertEquals(SPDY.V2, ping.getVersion());
-        Assert.assertEquals(pingId, ping.getPingId());
-        Assert.assertEquals(0, ping.getFlags());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java
deleted file mode 100644
index 8bc8710..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/RstStreamGenerateParseTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertThat;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class RstStreamGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        int streamId = 13;
-        int streamStatus = StreamStatus.UNSUPPORTED_VERSION.getCode(SPDY.V2);
-        RstStreamFrame frame1 = new RstStreamFrame(SPDY.V2, streamId, streamStatus);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        assertThat("buffer is not null", buffer, not(nullValue()));
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        assertThat("frame2 is not null", frame2, not(nullValue()));
-        assertThat("frame2 is type RST_STREAM",ControlFrameType.RST_STREAM, equalTo(frame2.getType()));
-        RstStreamFrame rstStream = (RstStreamFrame)frame2;
-        assertThat("rstStream version is SPDY.V2",SPDY.V2, equalTo(rstStream.getVersion()));
-        assertThat("rstStream id is equal to streamId",streamId, equalTo(rstStream.getStreamId()));
-        assertThat("rstStream flags are 0",(byte)0, equalTo(rstStream.getFlags()));
-        assertThat("stream status is equal to rstStream statuscode",streamStatus, is(rstStream.getStatusCode()));
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        int streamId = 13;
-        int streamStatus = StreamStatus.UNSUPPORTED_VERSION.getCode(SPDY.V2);
-        RstStreamFrame frame1 = new RstStreamFrame(SPDY.V2, streamId, streamStatus);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.RST_STREAM, frame2.getType());
-        RstStreamFrame rstStream = (RstStreamFrame)frame2;
-        Assert.assertEquals(SPDY.V2, rstStream.getVersion());
-        Assert.assertEquals(streamId, rstStream.getStreamId());
-        Assert.assertEquals(0, rstStream.getFlags());
-        Assert.assertEquals(streamStatus, rstStream.getStatusCode());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java
deleted file mode 100644
index adf9760..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SettingsGenerateParseTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SettingsGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        byte flags = SettingsInfo.CLEAR_PERSISTED;
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, Settings.Flag.PERSIST, 100));
-        settings.put(new Settings.Setting(Settings.ID.ROUND_TRIP_TIME, Settings.Flag.PERSISTED, 500));
-        SettingsFrame frame1 = new SettingsFrame(SPDY.V2, flags, settings);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SETTINGS, frame2.getType());
-        SettingsFrame settingsFrame = (SettingsFrame)frame2;
-        Assert.assertEquals(SPDY.V2, settingsFrame.getVersion());
-        Assert.assertEquals(flags, settingsFrame.getFlags());
-        Assert.assertEquals(settings, settingsFrame.getSettings());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        byte flags = SettingsInfo.CLEAR_PERSISTED;
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_RETRANSMISSION_RATE, 100));
-        settings.put(new Settings.Setting(Settings.ID.ROUND_TRIP_TIME, 500));
-        SettingsFrame frame1 = new SettingsFrame(SPDY.V2, flags, settings);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SETTINGS, frame2.getType());
-        SettingsFrame settingsFrame = (SettingsFrame)frame2;
-        Assert.assertEquals(SPDY.V2, settingsFrame.getVersion());
-        Assert.assertEquals(flags, settingsFrame.getFlags());
-        Assert.assertEquals(settings, settingsFrame.getSettings());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java
deleted file mode 100644
index 61c5cc5..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynReplyGenerateParseTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SynReplyGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        byte flags = ReplyInfo.FLAG_CLOSE;
-        int streamId = 13;
-        Fields headers = new Fields();
-        headers.put("a", "b");
-        SynReplyFrame frame1 = new SynReplyFrame(SPDY.V2, flags, streamId, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SYN_REPLY, frame2.getType());
-        SynReplyFrame synReply = (SynReplyFrame)frame2;
-        Assert.assertEquals(SPDY.V2, synReply.getVersion());
-        Assert.assertEquals(flags, synReply.getFlags());
-        Assert.assertEquals(streamId, synReply.getStreamId());
-        Assert.assertEquals(headers, synReply.getHeaders());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        byte flags = ReplyInfo.FLAG_CLOSE;
-        int streamId = 13;
-        Fields headers = new Fields();
-        headers.put("a", "b");
-        SynReplyFrame frame1 = new SynReplyFrame(SPDY.V2, flags, streamId, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SYN_REPLY, frame2.getType());
-        SynReplyFrame synReply = (SynReplyFrame)frame2;
-        Assert.assertEquals(SPDY.V2, synReply.getVersion());
-        Assert.assertEquals(flags, synReply.getFlags());
-        Assert.assertEquals(streamId, synReply.getStreamId());
-        Assert.assertEquals(headers, synReply.getHeaders());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java
deleted file mode 100644
index 0eeb55c..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/SynStreamGenerateParseTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SynStreamGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        byte flags = SynInfo.FLAG_CLOSE;
-        int streamId = 13;
-        int associatedStreamId = 11;
-        byte priority = 3;
-        short slot = 5;
-        Fields headers = new Fields();
-        headers.put("a", "b");
-        headers.put("c", "d");
-        SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SYN_STREAM, frame2.getType());
-        SynStreamFrame synStream = (SynStreamFrame)frame2;
-        Assert.assertEquals(SPDY.V2, synStream.getVersion());
-        Assert.assertEquals(streamId, synStream.getStreamId());
-        Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId());
-        Assert.assertEquals(flags, synStream.getFlags());
-        Assert.assertEquals(priority, synStream.getPriority());
-        Assert.assertEquals(slot, synStream.getSlot());
-        Assert.assertEquals(headers, synStream.getHeaders());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        byte flags = SynInfo.FLAG_CLOSE;
-        int streamId = 13;
-        int associatedStreamId = 11;
-        byte priority = 3;
-        short slot = 5;
-        Fields headers = new Fields();
-        headers.put("a", "b");
-        headers.put("c", "d");
-        SynStreamFrame frame1 = new SynStreamFrame(SPDY.V2, flags, streamId, associatedStreamId, priority, slot, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.SYN_STREAM, frame2.getType());
-        SynStreamFrame synStream = (SynStreamFrame)frame2;
-        Assert.assertEquals(SPDY.V2, synStream.getVersion());
-        Assert.assertEquals(streamId, synStream.getStreamId());
-        Assert.assertEquals(associatedStreamId, synStream.getAssociatedStreamId());
-        Assert.assertEquals(flags, synStream.getFlags());
-        Assert.assertEquals(priority, synStream.getPriority());
-        Assert.assertEquals(slot, synStream.getSlot());
-        Assert.assertEquals(headers, synStream.getHeaders());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java
deleted file mode 100644
index 3d6d5b3..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/TestSPDYParserListener.java
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.parser.Parser;
-
-public class TestSPDYParserListener implements Parser.Listener
-{
-    private ControlFrame controlFrame;
-    private DataFrame dataFrame;
-    private ByteBuffer data;
-
-    @Override
-    public void onControlFrame(ControlFrame frame)
-    {
-        this.controlFrame = frame;
-    }
-
-    @Override
-    public void onDataFrame(DataFrame frame, ByteBuffer data)
-    {
-        this.dataFrame = frame;
-        this.data = data;
-    }
-
-    @Override
-    public void onStreamException(StreamException x)
-    {
-    }
-
-    @Override
-    public void onSessionException(SessionException x)
-    {
-    }
-
-    public ControlFrame getControlFrame()
-    {
-        return controlFrame;
-    }
-
-    public DataFrame getDataFrame()
-    {
-        return dataFrame;
-    }
-
-    public ByteBuffer getData()
-    {
-        return data;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java
deleted file mode 100644
index 2468935..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/frames/WindowUpdateGenerateParseTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.frames;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class WindowUpdateGenerateParseTest
-{
-    @Test
-    public void testGenerateParse() throws Exception
-    {
-        int streamId = 13;
-        int windowDelta = 17;
-        WindowUpdateFrame frame1 = new WindowUpdateFrame(SPDY.V2, streamId, windowDelta);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        parser.parse(buffer);
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.WINDOW_UPDATE, frame2.getType());
-        WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame2;
-        Assert.assertEquals(SPDY.V2, windowUpdate.getVersion());
-        Assert.assertEquals(streamId, windowUpdate.getStreamId());
-        Assert.assertEquals(0, windowUpdate.getFlags());
-        Assert.assertEquals(windowDelta, windowUpdate.getWindowDelta());
-    }
-
-    @Test
-    public void testGenerateParseOneByteAtATime() throws Exception
-    {
-        int streamId = 13;
-        int windowDelta = 17;
-        WindowUpdateFrame frame1 = new WindowUpdateFrame(SPDY.V2, streamId, windowDelta);
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        ByteBuffer buffer = generator.control(frame1);
-
-        Assert.assertNotNull(buffer);
-
-        TestSPDYParserListener listener = new TestSPDYParserListener();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(listener);
-        while (buffer.hasRemaining())
-            parser.parse(ByteBuffer.wrap(new byte[]{buffer.get()}));
-        ControlFrame frame2 = listener.getControlFrame();
-
-        Assert.assertNotNull(frame2);
-        Assert.assertEquals(ControlFrameType.WINDOW_UPDATE, frame2.getType());
-        WindowUpdateFrame windowUpdate = (WindowUpdateFrame)frame2;
-        Assert.assertEquals(SPDY.V2, windowUpdate.getVersion());
-        Assert.assertEquals(streamId, windowUpdate.getStreamId());
-        Assert.assertEquals(0, windowUpdate.getFlags());
-        Assert.assertEquals(windowDelta, windowUpdate.getWindowDelta());
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java
deleted file mode 100644
index b0c972c..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/generator/DataFrameGeneratorTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.generator;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.ThreadLocalRandom;
-
-import org.eclipse.jetty.io.ArrayByteBufferPool;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.util.BufferUtil;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class DataFrameGeneratorTest
-{
-    private int increment = 1024;
-    private int streamId = 1;
-    private ArrayByteBufferPool bufferPool;
-    private DataFrameGenerator dataFrameGenerator;
-    private ByteBuffer headerBuffer = ByteBuffer.allocate(DataFrame.HEADER_LENGTH);
-
-    @Before
-    public void setUp()
-    {
-        bufferPool = new ArrayByteBufferPool(64, increment, 8192);
-        dataFrameGenerator = new DataFrameGenerator(bufferPool);
-        headerBuffer.putInt(0, streamId & 0x7F_FF_FF_FF);
-
-    }
-
-    @Test
-    public void testGenerateSmallFrame()
-    {
-        int bufferSize = 256;
-        generateFrame(bufferSize);
-    }
-
-    @Test
-    public void testGenerateFrameWithBufferThatEqualsBucketSize()
-    {
-        int bufferSize = increment;
-        generateFrame(bufferSize);
-    }
-
-    @Test
-    public void testGenerateFrameWithBufferThatEqualsBucketSizeMinusHeaderLength()
-    {
-        int bufferSize = increment - DataFrame.HEADER_LENGTH;
-        generateFrame(bufferSize);
-    }
-
-    private void generateFrame(int bufferSize)
-    {
-        ByteBuffer byteBuffer = createByteBuffer(bufferSize);
-        ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(byteBuffer, true);
-        fillHeaderBuffer(bufferSize);
-        ByteBuffer dataFrameBuffer = dataFrameGenerator.generate(streamId, bufferSize, dataInfo);
-
-        assertThat("The content size in dataFrameBuffer matches the buffersize + header length",
-                dataFrameBuffer.limit(),
-                is(bufferSize + DataFrame.HEADER_LENGTH));
-
-        byte[] headerBytes = new byte[DataFrame.HEADER_LENGTH];
-        dataFrameBuffer.get(headerBytes, 0, DataFrame.HEADER_LENGTH);
-        
-        assertThat("Header bytes are prepended", headerBytes, is(headerBuffer.array()));
-    }
-
-    private ByteBuffer createByteBuffer(int bufferSize)
-    {
-        byte[] bytes = new byte[bufferSize];
-        ThreadLocalRandom.current().nextBytes(bytes);
-        ByteBuffer byteBuffer = bufferPool.acquire(bufferSize, false);
-        BufferUtil.flipToFill(byteBuffer);
-        byteBuffer.put(bytes);
-        BufferUtil.flipToFlush(byteBuffer, 0);
-        return byteBuffer;
-    }
-
-    private void fillHeaderBuffer(int bufferSize)
-    {
-        headerBuffer.putInt(4, bufferSize & 0x00_FF_FF_FF);
-        headerBuffer.put(4, DataInfo.FLAG_CLOSE);
-    }
-
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java
deleted file mode 100644
index 5d1a51d..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/BrokenFrameTest.java
+++ /dev/null
@@ -1,287 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.zip.ZipException;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Test;
-
-public class BrokenFrameTest
-{
-
-    @Test
-    public void testInvalidHeaderNameLength() throws Exception
-    {
-        Fields headers = new Fields();
-        headers.add("broken", "header");
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor());
-
-        ByteBuffer bufferWithBrokenHeaderNameLength = generator.control(frame);
-        // Break the header name length to provoke the Parser to throw a StreamException
-        bufferWithBrokenHeaderNameLength.put(21, (byte)0);
-
-        ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame);
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        outputStream.write(BufferUtil.toArray(bufferWithBrokenHeaderNameLength));
-        outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame));
-
-        byte concatenatedFramesByteArray[] = outputStream.toByteArray();
-        ByteBuffer concatenatedBuffer = BufferUtil.toBuffer(concatenatedFramesByteArray);
-
-        final CountDownLatch latch = new CountDownLatch(2);
-        Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-                latch.countDown();
-            }
-        });
-        parser.parse(concatenatedBuffer);
-
-        assertThat(latch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testInvalidVersion() throws Exception
-    {
-        Fields headers = new Fields();
-        headers.add("good", "header");
-        headers.add("another","header");
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor());
-
-        ByteBuffer bufferWithBrokenVersion = generator.control(frame);
-        // Break the header name length to provoke the Parser to throw a StreamException
-        bufferWithBrokenVersion.put(1, (byte)4);
-
-        ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame);
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion));
-        outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame));
-
-        byte concatenatedFramesByteArray[] = outputStream.toByteArray();
-        ByteBuffer concatenatedBuffer = BufferUtil.toBuffer(concatenatedFramesByteArray);
-
-        final CountDownLatch latch = new CountDownLatch(2);
-        Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-                latch.countDown();
-            }
-        });
-        parser.parse(concatenatedBuffer);
-
-        assertThat(latch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testInvalidVersionWithSplitBuffer() throws Exception
-    {
-        Fields headers = new Fields();
-        headers.add("good", "header");
-        headers.add("another","header");
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor());
-
-        ByteBuffer bufferWithBrokenVersion = generator.control(frame);
-        // Break the header name length to provoke the Parser to throw a StreamException
-        bufferWithBrokenVersion.put(1, (byte)4);
-
-        ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame);
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion));
-        outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame));
-
-        byte concatenatedFramesByteArray[] = outputStream.toByteArray();
-        ByteBuffer concatenatedBuffer1 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,0,20));
-        ByteBuffer concatenatedBuffer2 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,20,
-                concatenatedFramesByteArray.length));
-
-        final CountDownLatch latch = new CountDownLatch(2);
-        Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-                latch.countDown();
-            }
-        });
-        parser.parse(concatenatedBuffer1);
-        parser.parse(concatenatedBuffer2);
-
-        assertThat(latch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testInvalidVersionAndGoodFrameSplitInThreeBuffers() throws Exception
-    {
-        Fields headers = new Fields();
-        headers.add("good", "header");
-        headers.add("another","header");
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, headers);
-        Generator generator = new Generator(new MappedByteBufferPool(), new NoCompressionCompressionFactory.NoCompressionCompressor());
-
-        ByteBuffer bufferWithBrokenVersion = generator.control(frame);
-        // Break the header name length to provoke the Parser to throw a StreamException
-        bufferWithBrokenVersion.put(1, (byte)4);
-
-        ByteBuffer bufferWithValidSynStreamFrame = generator.control(frame);
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        outputStream.write(BufferUtil.toArray(bufferWithBrokenVersion));
-        outputStream.write(BufferUtil.toArray(bufferWithValidSynStreamFrame));
-
-        byte concatenatedFramesByteArray[] = outputStream.toByteArray();
-        ByteBuffer concatenatedBuffer1 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,0,20));
-        ByteBuffer concatenatedBuffer2 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,20, 30));
-        ByteBuffer concatenatedBuffer3 = BufferUtil.toBuffer(Arrays.copyOfRange(concatenatedFramesByteArray,30,
-                concatenatedFramesByteArray.length));
-
-        final CountDownLatch latch = new CountDownLatch(2);
-        Parser parser = new Parser(new NoCompressionCompressionFactory.NoCompressionDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-                latch.countDown();
-            }
-        });
-        parser.parse(concatenatedBuffer1);
-        parser.parse(concatenatedBuffer2);
-        parser.parse(concatenatedBuffer3);
-
-        assertThat(latch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private static class NoCompressionCompressionFactory implements CompressionFactory
-    {
-
-        @Override
-        public Compressor newCompressor()
-        {
-            return null;
-        }
-
-        @Override
-        public Decompressor newDecompressor()
-        {
-            return null;
-        }
-
-        public static class NoCompressionCompressor implements Compressor
-        {
-
-            private byte[] input;
-
-            @Override
-            public void setInput(byte[] input)
-            {
-                this.input = input;
-            }
-
-            @Override
-            public void setDictionary(byte[] dictionary)
-            {
-            }
-
-            @Override
-            public int compress(byte[] output)
-            {
-                System.arraycopy(input, 0, output, 0, input.length);
-                return input.length;
-            }
-        }
-
-        public static class NoCompressionDecompressor implements Decompressor
-        {
-            private byte[] input;
-
-            @Override
-            public void setDictionary(byte[] dictionary)
-            {
-            }
-
-            @Override
-            public void setInput(byte[] input)
-            {
-                this.input = input;
-            }
-
-            @Override
-            public int decompress(byte[] output) throws ZipException
-            {
-                System.arraycopy(input, 0, output, 0, input.length);
-                return input.length;
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java
deleted file mode 100644
index 2ad3a83..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/LiveChromiumRequestParserTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class LiveChromiumRequestParserTest
-{
-    @Test
-    public void testSynStream() throws Exception
-    {
-        // Bytes taken with wireshark from a live chromium request
-        byte[] bytes1 = toBytes("" +
-                "800200010100011a0000000100000000000038eadfa251b262e0626083a41706" +
-                "7bb80b75302cd6ae4017cdcdb12eb435d0b3d4d1d2d702b32c18f850732c036f" +
-                "68889bae850e44da94811f2d0b3308821ca80375a14e714a72065c0d2cd619f8" +
-                "52f37443837552f3a076b080b234033f28de73404c2b43630b135306b65c6059" +
-                "929fc2c0ecee1ac2c0560c4c7eb9a940b52525050ccc206f32ea337021f22643" +
-                "bb6f7e55664e4ea2bea99e81824684a1a135400a3e9979a5150a151666f16626" +
-                "9a0a8e40afa686a726796796e89b1a9bea992b68787b84f8fae828e46466a72a" +
-                "b8a72667e76b2a842695e69594ea1b0203d640c1390358e06496e6ea1b9ae901" +
-                "c3c5d048cfdc1c22988a22149c98965894093195811d1a150c1cb01802000000" +
-                "ffff");
-        byte[] bytes2 = toBytes("" +
-                "800200010100002700000003000000008000428a106660d00ee640e5d14f4b2c" +
-                "cb0466313d203154c217000000ffff");
-
-        final AtomicReference<ControlFrame> frameRef = new AtomicReference<>();
-        Parser parser = new Parser(new StandardCompressionFactory().newDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                frameRef.set(frame);
-            }
-        });
-        parser.parse(ByteBuffer.wrap(bytes1));
-
-        ControlFrame frame = frameRef.get();
-        Assert.assertNotNull(frame);
-        Assert.assertEquals(ControlFrameType.SYN_STREAM, frame.getType());
-        SynStreamFrame synStream = (SynStreamFrame)frame;
-        Assert.assertEquals(2, synStream.getVersion());
-        Assert.assertEquals(1, synStream.getStreamId());
-        Assert.assertEquals(0, synStream.getAssociatedStreamId());
-        Assert.assertEquals(0, synStream.getPriority());
-        Assert.assertNotNull(synStream.getHeaders());
-        Assert.assertFalse(synStream.getHeaders().isEmpty());
-
-        frameRef.set(null);
-        parser.parse(ByteBuffer.wrap(bytes2));
-
-        frame = frameRef.get();
-        Assert.assertNotNull(frame);
-        Assert.assertEquals(ControlFrameType.SYN_STREAM, frame.getType());
-        synStream = (SynStreamFrame)frame;
-        Assert.assertEquals(2, synStream.getVersion());
-        Assert.assertEquals(3, synStream.getStreamId());
-        Assert.assertEquals(0, synStream.getAssociatedStreamId());
-        Assert.assertEquals(2, synStream.getPriority());
-        Assert.assertNotNull(synStream.getHeaders());
-        Assert.assertFalse(synStream.getHeaders().isEmpty());
-    }
-
-    private byte[] toBytes(String hexs)
-    {
-        byte[] bytes = new byte[hexs.length() / 2];
-        for (int i = 0; i < hexs.length(); i += 2)
-        {
-            String hex = hexs.substring(i, i + 2);
-            bytes[i / 2] = (byte)Integer.parseInt(hex, 16);
-        }
-        return bytes;
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java
deleted file mode 100644
index 4c5e5d6..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/ParseVersusCacheBenchmarkTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class ParseVersusCacheBenchmarkTest
-{
-    @Ignore
-    @Test
-    public void testParseVersusCache() throws Exception
-    {
-        // The parser knows the header name and value lengths, so it creates strings
-        // out of the bytes; however, this involves creating a byte[] copy the bytes,
-        // and creating a new String.
-        // The alternative is to use a cache<ByteBuffer, String>. Is that faster ?
-        // See also: http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html
-
-        String name = "Content-Type";
-        String value = "application/octect-stream";
-        ByteBuffer buffer = ByteBuffer.wrap((name + value).getBytes(StandardCharsets.ISO_8859_1));
-        int iterations = 100_000_000;
-
-        long begin = System.nanoTime();
-        for (int i = 0; i < iterations; ++i)
-        {
-            byte[] nameBytes = new byte[name.length()];
-            buffer.get(nameBytes);
-            String name2 = new String(nameBytes, StandardCharsets.ISO_8859_1);
-            Assert.assertEquals(name2, name);
-
-            byte[] valueBytes = new byte[value.length()];
-            buffer.get(valueBytes);
-            String value2 = new String(valueBytes, StandardCharsets.ISO_8859_1);
-            Assert.assertEquals(value2, value);
-
-            buffer.flip();
-        }
-        long end = System.nanoTime();
-        System.err.printf("parse time: %d%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
-
-        Map<ByteBuffer, String> map = new HashMap<>();
-        map.put(ByteBuffer.wrap(name.getBytes(StandardCharsets.ISO_8859_1)), name);
-        map.put(ByteBuffer.wrap(value.getBytes(StandardCharsets.ISO_8859_1)), value);
-        final Map<ByteBuffer, String> cache = Collections.unmodifiableMap(map);
-
-        begin = System.nanoTime();
-        for (int i = 0; i < iterations; ++i)
-        {
-            buffer.limit(buffer.position() + name.length());
-            String name2 = cache.get(buffer);
-            Assert.assertEquals(name2, name);
-
-            buffer.position(buffer.limit());
-            buffer.limit(buffer.position() + value.length());
-            String value2 = cache.get(buffer);
-            Assert.assertEquals(value2, value);
-
-            buffer.position(buffer.limit());
-            buffer.flip();
-        }
-        end = System.nanoTime();
-        System.err.printf("cache time: %d%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java
deleted file mode 100644
index 9bd9909..0000000
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/parser/UnknownControlFrameTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.parser;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.SessionException;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class UnknownControlFrameTest
-{
-    @Test
-    public void testUnknownControlFrame() throws Exception
-    {
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Fields());
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-        ByteBuffer buffer = generator.control(frame);
-        // Change the frame type to unknown
-        buffer.putShort(2, (short)0);
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onDataFrame(DataFrame frame, ByteBuffer data)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onStreamException(StreamException x)
-            {
-                latch.countDown();
-            }
-
-            @Override
-            public void onSessionException(SessionException x)
-            {
-                latch.countDown();
-            }
-        });
-        parser.parse(buffer);
-
-        Assert.assertFalse(latch.await(1, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties
deleted file mode 100644
index 5250a08..0000000
--- a/jetty-spdy/spdy-core/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-org.eclipse.jetty.spdy.LEVEL=WARN
diff --git a/jetty-spdy/spdy-core/src/test/resources/keystore.jks b/jetty-spdy/spdy-core/src/test/resources/keystore.jks
deleted file mode 100644
index 428ba54..0000000
--- a/jetty-spdy/spdy-core/src/test/resources/keystore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-core/src/test/resources/truststore.jks b/jetty-spdy/spdy-core/src/test/resources/truststore.jks
deleted file mode 100644
index 839cb8c..0000000
--- a/jetty-spdy/spdy-core/src/test/resources/truststore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-example-webapp/pom.xml b/jetty-spdy/spdy-example-webapp/pom.xml
deleted file mode 100644
index 0045fc1..0000000
--- a/jetty-spdy/spdy-example-webapp/pom.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-example-webapp</artifactId>
-    <packaging>war</packaging>
-    <name>Jetty :: SPDY :: HTTP Web Application</name>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.eclipse.jetty</groupId>
-                <artifactId>jetty-maven-plugin</artifactId>
-                <version>${project.version}</version>
-                <configuration>
-                    <stopPort>8888</stopPort>
-                    <stopKey>quit</stopKey>
-                    <jvmArgs>
-                        -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar
-                    </jvmArgs>
-                    <jettyXml>${basedir}/src/main/config/example-jetty-spdy.xml</jettyXml>
-                    <contextPath>/</contextPath>
-                    <excludedGoals>
-                       <excludedGoal>run</excludedGoal>
-                       <excludedGoal>run-war</excludedGoal>
-                       <excludedGoal>deploy</excludedGoal>
-                       <excludedGoal>start</excludedGoal>
-                       <excludedGoal>stop</excludedGoal>
-                    </excludedGoals>
-                </configuration>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.eclipse.jetty.spdy</groupId>
-                        <artifactId>spdy-http-server</artifactId>
-                        <version>${project.version}</version>
-                    </dependency>
-                </dependencies>
-            </plugin>
-        </plugins>
-    </build>
-
-    <profiles>
-        <profile>
-            <id>proxy</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.eclipse.jetty</groupId>
-                        <artifactId>jetty-maven-plugin</artifactId>
-                        <version>${project.version}</version>
-                        <configuration>
-                            <stopPort>8888</stopPort>
-                            <stopKey>quit</stopKey>
-                            <jvmArgs>
-                                -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${npn.version}/npn-boot-${npn.version}.jar
-                            </jvmArgs>
-                            <jettyXml>${basedir}/src/main/config/example-jetty-spdy-proxy.xml</jettyXml>
-                            <contextPath>/</contextPath>
-                            <excludedGoals>
-                               <excludedGoal>run</excludedGoal>
-                               <excludedGoal>run-war</excludedGoal>
-                               <excludedGoal>deploy</excludedGoal>
-                               <excludedGoal>start</excludedGoal>
-                               <excludedGoal>stop</excludedGoal>
-                            </excludedGoals>
-                        </configuration>
-                        <dependencies>
-                            <dependency>
-                                <groupId>org.eclipse.jetty.spdy</groupId>
-                                <artifactId>spdy-http-server</artifactId>
-                                <version>${project.version}</version>
-                            </dependency>
-                        </dependencies>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
-
-</project>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml
deleted file mode 100644
index 7d3d360..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy-proxy.xml
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-    <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-        <Set name="keyStorePath">src/main/resources/keystore.jks</Set>
-        <Set name="keyStorePassword">storepwd</Set>
-        <Set name="trustStorePath">src/main/resources/truststore.jks</Set>
-        <Set name="trustStorePassword">storepwd</Set>
-        <Set name="protocol">TLSv1</Set>
-    </New>
-
-    <!--
-    <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
-    -->
-
-    <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-        <Arg>
-            <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-                <Set name="secureScheme">https</Set>
-                <Set name="securePort">
-                    <Property name="jetty.tls.port" default="8443"/>
-                </Set>
-                <Set name="outputBufferSize">32768</Set>
-                <Set name="requestHeaderSize">8192</Set>
-                <Set name="responseHeaderSize">8192</Set>
-
-                <!-- Uncomment to enable handling of X-Forwarded- style headers
-                <Call name="addCustomizer">
-                    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
-                </Call>
-                -->
-            </New>
-        </Arg>
-        <Call name="addCustomizer">
-            <Arg>
-                <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/>
-            </Arg>
-        </Call>
-    </New>
-
-    <!--
-    This is the upstream server connector. It speaks non-SSL SPDY/3(HTTP) on port 9090.
-    -->
-    <Call name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.server.ServerConnector">
-                <Arg name="server">
-                    <Ref refid="Server"/>
-                </Arg>
-                <Arg name="factories">
-                    <Array type="org.eclipse.jetty.server.ConnectionFactory">
-                        <!-- SPDY/3 Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">3</Arg>
-                                <Arg name="config">
-                                    <Ref refid="tlsHttpConfig"/>
-                                </Arg>
-                            </New>
-                        </Item>
-                    </Array>
-                </Arg>
-                <Set name="port">9090</Set>
-            </New>
-        </Arg>
-    </Call>
-
-    <!--
-    This ProxyEngine translates the incoming SPDY/x(HTTP) request to SPDY/2(HTTP)
-    -->
-    <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.server.proxy.SPDYProxyEngine">
-        <Arg>
-            <New class="org.eclipse.jetty.spdy.client.SPDYClient$Factory">
-                <Call name="start"/>
-            </New>
-        </Arg>
-    </New>
-
-    <!--
-    The ProxyEngineSelector receives SPDY/x(HTTP) requests from proxy connectors below
-    and is configured to process requests for host "localhost".
-    Such requests are converted from SPDY/x(HTTP) to SPDY/3(HTTP) by the configured ProxyEngine
-    and forwarded to 127.0.0.1:9090, where they are served by the upstream server above.
-    -->
-    <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector">
-        <Call name="putProxyEngine">
-            <Arg>spdy/3</Arg>
-            <Arg>
-                <Ref refid="spdyProxyEngine"/>
-            </Arg>
-        </Call>
-        <Set name="proxyServerInfos">
-            <Map>
-                <Entry>
-                    <Item>localhost</Item>
-                    <Item>
-                        <New class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector$ProxyServerInfo">
-                            <Arg type="String">spdy/3</Arg>
-                            <Arg>127.0.0.1</Arg>
-                            <Arg type="int">9090</Arg>
-                        </New>
-                    </Item>
-                </Entry>
-            </Map>
-        </Set>
-    </New>
-
-    <!--
-    These are the reverse proxy connectors accepting requests from clients.
-    They accept non-SSL (on port 8080) and SSL (on port 8443) HTTP,
-    SPDY/2(HTTP) and SPDY/3(HTTP).
-    Non-SPDY HTTP requests are converted to SPDY internally and passed to the
-    ProxyEngine above.
-    -->
-    <Call name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
-                <Arg>
-                    <Ref refid="Server"/>
-                </Arg>
-                <Arg>
-                    <Ref refid="proxyEngineSelector"/>
-                </Arg>
-                <Set name="Port">8080</Set>
-            </New>
-        </Arg>
-    </Call>
-    <Call name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
-                <Arg>
-                    <Ref refid="Server"/>
-                </Arg>
-                <Arg>
-                    <Ref refid="sslContextFactory"/>
-                </Arg>
-                <Arg>
-                    <Ref refid="proxyEngineSelector"/>
-                </Arg>
-                <Set name="Port">8443</Set>
-            </New>
-        </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml b/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml
deleted file mode 100644
index 47f83be..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/config/example-jetty-spdy.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-    <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-        <Set name="keyStorePath">src/main/resources/keystore.jks</Set>
-        <Set name="keyStorePassword">storepwd</Set>
-        <Set name="trustStorePath">src/main/resources/truststore.jks</Set>
-        <Set name="trustStorePassword">storepwd</Set>
-        <Set name="protocol">TLSv1</Set>
-    </New>
-
-    <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-        <Arg>
-            <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-                <Set name="secureScheme">https</Set>
-                <Set name="securePort">
-                    <Property name="jetty.tls.port" default="8443"/>
-                </Set>
-                <Set name="outputBufferSize">32768</Set>
-                <Set name="requestHeaderSize">8192</Set>
-                <Set name="responseHeaderSize">8192</Set>
-
-                <!-- Uncomment to enable handling of X-Forwarded- style headers
-                <Call name="addCustomizer">
-                    <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
-                </Call>
-                -->
-            </New>
-        </Arg>
-        <Call name="addCustomizer">
-            <Arg>
-                <New class="org.eclipse.jetty.server.SecureRequestCustomizer"/>
-            </Arg>
-        </Call>
-    </New>
-
-    <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
-        <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
-             user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
-        <!--
-        <Set name="UserAgentBlacklist">
-            <Array type="String">
-                <Item>.*(?i)firefox/14.*</Item>
-                <Item>.*(?i)firefox/15.*</Item>
-                <Item>.*(?i)firefox/16.*</Item>
-            </Array>
-        </Set>
-        -->
-
-        <!-- Uncomment to override default file extensions to push -->
-        <!--
-        <Set name="PushRegexps">
-            <Array type="String">
-               <Item>.*\.css</Item>
-               <Item>.*\.js</Item>
-               <Item>.*\.png</Item>
-               <Item>.*\.jpg</Item>
-               <Item>.*\.gif</Item>
-           </Array>
-        </Set>
-        -->
-        <Set name="referrerPushPeriod">5000</Set>
-        <Set name="maxAssociatedResources">32</Set>
-    </New>
-
-    <Call id="sslConnector" name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.server.ServerConnector">
-                <Arg name="server"><Ref refid="Server"/></Arg>
-                <Arg name="factories">
-                    <Array type="org.eclipse.jetty.server.ConnectionFactory">
-
-                        <!-- SSL Connection factory with NPN as next protocol -->
-                        <Item>
-                            <New class="org.eclipse.jetty.server.SslConnectionFactory">
-                                <Arg name="next">npn</Arg>
-                                <Arg name="sslContextFactory">
-                                    <Ref refid="sslContextFactory"/>
-                                </Arg>
-                            </New>
-                        </Item>
-
-                        <!-- NPN Connection factory with HTTP as default protocol -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory">
-                                <Arg name="protocols">
-                                    <Array type="String">
-                                        <Item>spdy/3</Item>
-                                        <Item>spdy/2</Item>
-                                        <Item>http/1.1</Item>
-                                    </Array>
-                                </Arg>
-                                <Set name="defaultProtocol">http/1.1</Set>
-                            </New>
-                        </Item>
-
-                        <!-- SPDY/3 Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">3</Arg>
-                                <Arg name="config">
-                                    <Ref refid="tlsHttpConfig"/>
-                                </Arg>
-                                <Arg name="pushStrategy">
-                                    <Ref refid="pushStrategy"/>
-                                </Arg>
-                            </New>
-                        </Item>
-
-                        <!-- SPDY/2 Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">2</Arg>
-                                <Arg name="config">
-                                    <Ref refid="tlsHttpConfig"/>
-                                </Arg>
-                            </New>
-                        </Item>
-
-                        <!-- HTTP Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                                <Arg name="config">
-                                    <Ref refid="tlsHttpConfig"/>
-                                </Arg>
-                            </New>
-                        </Item>
-                    </Array>
-                </Arg>
-
-                <Set name="port">8443</Set>
-            </New>
-        </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties b/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties
deleted file mode 100644
index 5250a08..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/resources/jetty-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-org.eclipse.jetty.spdy.LEVEL=WARN
diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks b/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks
deleted file mode 100644
index 428ba54..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/resources/keystore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks b/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks
deleted file mode 100644
index 839cb8c..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/resources/truststore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index eb49319..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<web-app xmlns="http://java.sun.com/xml/ns/javaee"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
-         version="3.0">
-</web-app>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp
deleted file mode 100644
index 4e41a65..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/form.jsp
+++ /dev/null
@@ -1,3 +0,0 @@
-<div>
-    <p>This paragraph has been retrieved via an AJAX call</p>
-</div>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp
deleted file mode 100644
index d69cd4a..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/included.jsp
+++ /dev/null
@@ -1,3 +0,0 @@
-<div>
-    <p>This paragraph is an included content via &lt;jsp:include&gt;</p>
-</div>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp b/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp
deleted file mode 100644
index f190e57..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/index.jsp
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-    <title>SPDY TEST PAGE</title>
-    <link rel="stylesheet" href="stylesheet.css" />
-    <script type="text/javascript">
-        function submit()
-        {
-            var xhr = new XMLHttpRequest();
-            xhr.open("POST", "${pageContext.request.contextPath}/form.jsp", false);
-            xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
-            xhr.send("param=1");
-            window.document.getElementById("form").innerHTML = xhr.responseText;
-        }
-    </script>
-</head>
-<body>
-<h2>SPDY TEST PAGE</h2>
-<div>
-    <p><span id="css">This paragraph should have a colored background, meaning that the CSS has been loaded.</span></p>
-</div>
-<div id="image">
-    <p>Below there should be an image</p>
-    <img src="${pageContext.request.contextPath}/logo.jpg"  alt="logo" />
-</div>
-<div>
-    <jsp:include page="included.jsp" />
-</div>
-<div>
-    <p>Click on the button below to perform an AJAX call</p>
-    <button type="button" onclick="submit()">
-        PERFORM AJAX CALL
-    </button>
-    <p id="form"></p>
-</div>
-</body>
-</html>
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg b/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg
deleted file mode 100644
index e8eb8c5..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/logo.jpg
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css b/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css
deleted file mode 100644
index 169c339..0000000
--- a/jetty-spdy/spdy-example-webapp/src/main/webapp/stylesheet.css
+++ /dev/null
@@ -1,9 +0,0 @@
-body
-{
-    font-family: Verdana, sans-serif;
-}
-
-#css
-{
-    background: #0FF;
-}
diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml
deleted file mode 100644
index 1cb3ae6..0000000
--- a/jetty-spdy/spdy-http-client-transport/pom.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-http-client-transport</artifactId>
-    <name>Jetty :: SPDY :: HTTP Client Transport</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.client.http</bundle-symbolic-name>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.client.http;version="9.1"</Export-Package>
-                                <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-common</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java
deleted file mode 100644
index 0f32567..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpChannelOverSPDY.java
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import org.eclipse.jetty.client.HttpChannel;
-import org.eclipse.jetty.client.HttpDestination;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.client.api.Result;
-import org.eclipse.jetty.spdy.api.Session;
-
-public class HttpChannelOverSPDY extends HttpChannel
-{
-    private final HttpConnectionOverSPDY connection;
-    private final Session session;
-    private final HttpSenderOverSPDY sender;
-    private final HttpReceiverOverSPDY receiver;
-
-    public HttpChannelOverSPDY(HttpDestination destination, HttpConnectionOverSPDY connection, Session session)
-    {
-        super(destination);
-        this.connection = connection;
-        this.session = session;
-        this.sender = new HttpSenderOverSPDY(this);
-        this.receiver = new HttpReceiverOverSPDY(this);
-    }
-
-    public Session getSession()
-    {
-        return session;
-    }
-
-    public HttpSenderOverSPDY getHttpSender()
-    {
-        return sender;
-    }
-
-    public HttpReceiverOverSPDY getHttpReceiver()
-    {
-        return receiver;
-    }
-
-    @Override
-    public void send()
-    {
-        HttpExchange exchange = getHttpExchange();
-        if (exchange != null)
-            sender.send(exchange);
-    }
-
-    @Override
-    public void release()
-    {
-        connection.release(this);
-    }
-
-    @Override
-    public void exchangeTerminated(HttpExchange exchange, Result result)
-    {
-        super.exchangeTerminated(exchange, result);
-        release();
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java
deleted file mode 100644
index 2aef0a5..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpClientTransportOverSPDY.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.io.IOException;
-import java.net.SocketAddress;
-import java.util.Map;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpClientTransport;
-import org.eclipse.jetty.client.HttpDestination;
-import org.eclipse.jetty.client.Origin;
-import org.eclipse.jetty.client.api.Connection;
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.util.Promise;
-
-public class HttpClientTransportOverSPDY implements HttpClientTransport
-{
-    private final SPDYClient client;
-    private final ClientConnectionFactory connectionFactory;
-    private HttpClient httpClient;
-
-    public HttpClientTransportOverSPDY(SPDYClient client)
-    {
-        this.client = client;
-        this.connectionFactory = client.getClientConnectionFactory();
-        client.setClientConnectionFactory(new ClientConnectionFactory()
-        {
-            @Override
-            public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
-            {
-                HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
-                return destination.getClientConnectionFactory().newConnection(endPoint, context);
-            }
-        });
-    }
-
-    @Override
-    public void setHttpClient(HttpClient client)
-    {
-        httpClient = client;
-    }
-
-    @Override
-    public HttpDestination newHttpDestination(Origin origin)
-    {
-        return new HttpDestinationOverSPDY(httpClient, origin);
-    }
-
-    @Override
-    public void connect(SocketAddress address, Map<String, Object> context)
-    {
-        final HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
-        @SuppressWarnings("unchecked")
-        final Promise<Connection> promise = (Promise<Connection>)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
-
-        SessionFrameListener.Adapter listener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onFailure(Session session, Throwable x)
-            {
-                destination.abort(x);
-            }
-        };
-
-        client.connect(address, listener, new Promise<Session>()
-        {
-            @Override
-            public void succeeded(Session session)
-            {
-                promise.succeeded(new HttpConnectionOverSPDY(destination, session));
-            }
-
-            @Override
-            public void failed(Throwable x)
-            {
-                promise.failed(x);
-            }
-        }, context);
-    }
-
-    @Override
-    public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
-    {
-        return connectionFactory.newConnection(endPoint, context);
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java
deleted file mode 100644
index f3055e9..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpConnectionOverSPDY.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.nio.channels.AsynchronousCloseException;
-import java.util.Set;
-
-import org.eclipse.jetty.client.HttpChannel;
-import org.eclipse.jetty.client.HttpConnection;
-import org.eclipse.jetty.client.HttpDestination;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.ConcurrentHashSet;
-
-public class HttpConnectionOverSPDY extends HttpConnection
-{
-    private final Set<HttpChannel> channels = new ConcurrentHashSet<>();
-    private final Session session;
-
-    public HttpConnectionOverSPDY(HttpDestination destination, Session session)
-    {
-        super(destination);
-        this.session = session;
-    }
-
-    @Override
-    protected void send(HttpExchange exchange)
-    {
-        normalizeRequest(exchange.getRequest());
-        // One connection maps to N channels, so for each exchange we create a new channel
-        HttpChannel channel = new HttpChannelOverSPDY(getHttpDestination(), this, session);
-        channels.add(channel);
-        if (channel.associate(exchange))
-            channel.send();
-        else
-            channel.release();
-    }
-
-    protected void release(HttpChannel channel)
-    {
-        channels.remove(channel);
-    }
-
-    @Override
-    public void close()
-    {
-        // First close then abort, to be sure that the connection cannot be reused
-        // from an onFailure() handler or by blocking code waiting for completion.
-        getHttpDestination().close(this);
-        session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
-        abort(new AsynchronousCloseException());
-    }
-
-    private void abort(Throwable failure)
-    {
-        for (HttpChannel channel : channels)
-        {
-            HttpExchange exchange = channel.getHttpExchange();
-            if (exchange != null)
-                exchange.getRequest().abort(failure);
-        }
-        channels.clear();
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java
deleted file mode 100644
index c52e0c4..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpDestinationOverSPDY.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.client.MultiplexHttpDestination;
-import org.eclipse.jetty.client.Origin;
-
-public class HttpDestinationOverSPDY extends MultiplexHttpDestination<HttpConnectionOverSPDY>
-{
-    public HttpDestinationOverSPDY(HttpClient client, Origin origin)
-    {
-        super(client, origin);
-    }
-
-    @Override
-    protected void send(HttpConnectionOverSPDY connection, HttpExchange exchange)
-    {
-        connection.send(exchange);
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java
deleted file mode 100644
index 51b3151..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpReceiverOverSPDY.java
+++ /dev/null
@@ -1,152 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.client.HttpReceiver;
-import org.eclipse.jetty.client.HttpResponse;
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-
-public class HttpReceiverOverSPDY extends HttpReceiver implements StreamFrameListener
-{
-    public HttpReceiverOverSPDY(HttpChannelOverSPDY channel)
-    {
-        super(channel);
-    }
-
-    @Override
-    public HttpChannelOverSPDY getHttpChannel()
-    {
-        return (HttpChannelOverSPDY)super.getHttpChannel();
-    }
-
-    @Override
-    public void onReply(Stream stream, ReplyInfo replyInfo)
-    {
-        HttpExchange exchange = getHttpExchange();
-        if (exchange == null)
-            return;
-
-        try
-        {
-            HttpResponse response = exchange.getResponse();
-
-            Fields fields = replyInfo.getHeaders();
-            short spdy = stream.getSession().getVersion();
-            HttpVersion version = HttpVersion.fromString(fields.get(HTTPSPDYHeader.VERSION.name(spdy)).getValue());
-            response.version(version);
-            String[] status = fields.get(HTTPSPDYHeader.STATUS.name(spdy)).getValue().split(" ", 2);
-
-            Integer code = Integer.parseInt(status[0]);
-            response.status(code);
-            String reason = status.length < 2 ? HttpStatus.getMessage(code) : status[1];
-            response.reason(reason);
-
-            if (responseBegin(exchange))
-            {
-                for (Fields.Field field : fields)
-                {
-                    String name = field.getName();
-                    if (HTTPSPDYHeader.from(spdy, name) != null)
-                        continue;
-                    // TODO: handle multiple values properly
-                    HttpField httpField = new HttpField(name, field.getValue());
-                    responseHeader(exchange, httpField);
-                }
-
-                if (responseHeaders(exchange))
-                {
-                    if (replyInfo.isClose())
-                    {
-                        responseSuccess(exchange);
-                    }
-                }
-            }
-        }
-        catch (Exception x)
-        {
-            responseFailure(x);
-        }
-    }
-
-    @Override
-    public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-    {
-        // SPDY push not supported
-        getHttpChannel().getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), Callback.Adapter.INSTANCE);
-        return null;
-    }
-
-    @Override
-    public void onHeaders(Stream stream, HeadersInfo headersInfo)
-    {
-        // TODO: see above handling of headers
-    }
-
-    @Override
-    public void onData(Stream stream, DataInfo dataInfo)
-    {
-        HttpExchange exchange = getHttpExchange();
-        if (exchange == null)
-            return;
-
-        try
-        {
-            int length = dataInfo.length();
-            // TODO: avoid data copy here
-            // TODO: handle callback properly
-            boolean process = responseContent(exchange, dataInfo.asByteBuffer(false), new Callback.Adapter());
-            dataInfo.consume(length);
-
-            if (process)
-            {
-                if (dataInfo.isClose())
-                {
-                    responseSuccess(exchange);
-                }
-            }
-        }
-        catch (Exception x)
-        {
-            responseFailure(x);
-        }
-    }
-
-    @Override
-    public void onFailure(Stream stream, Throwable x)
-    {
-        HttpExchange exchange = getHttpExchange();
-        if (exchange == null)
-            return;
-        exchange.getRequest().abort(x);
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java b/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java
deleted file mode 100644
index 7429fcf..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/main/java/org/eclipse/jetty/spdy/client/http/HttpSenderOverSPDY.java
+++ /dev/null
@@ -1,118 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import org.eclipse.jetty.client.HttpContent;
-import org.eclipse.jetty.client.HttpExchange;
-import org.eclipse.jetty.client.HttpSender;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-
-public class HttpSenderOverSPDY extends HttpSender
-{
-    private volatile Stream stream;
-
-    public HttpSenderOverSPDY(HttpChannelOverSPDY channel)
-    {
-        super(channel);
-    }
-
-    @Override
-    public HttpChannelOverSPDY getHttpChannel()
-    {
-        return (HttpChannelOverSPDY)super.getHttpChannel();
-    }
-
-    @Override
-    protected void sendHeaders(HttpExchange exchange, final HttpContent content, final Callback callback)
-    {
-        final Request request = exchange.getRequest();
-        final long idleTimeout = request.getIdleTimeout();
-        short spdyVersion = getHttpChannel().getSession().getVersion();
-        Fields fields = new Fields();
-        HttpField hostHeader = null;
-        for (HttpField header : request.getHeaders())
-        {
-            String name = header.getName();
-            // The host header needs a special treatment
-            if (HTTPSPDYHeader.from(spdyVersion, name) != HTTPSPDYHeader.HOST)
-                fields.add(name, header.getValue());
-            else
-                hostHeader = header;
-        }
-
-        // Add special SPDY headers
-        fields.put(HTTPSPDYHeader.METHOD.name(spdyVersion), request.getMethod());
-        String path = request.getPath();
-        String query = request.getQuery();
-        if (query != null)
-            path += "?" + query;
-        fields.put(HTTPSPDYHeader.URI.name(spdyVersion), path);
-        fields.put(HTTPSPDYHeader.VERSION.name(spdyVersion), request.getVersion().asString());
-        if (hostHeader != null)
-            fields.put(HTTPSPDYHeader.HOST.name(spdyVersion), hostHeader.getValue());
-
-        SynInfo synInfo = new SynInfo(fields, !content.hasContent());
-        getHttpChannel().getSession().syn(synInfo, getHttpChannel().getHttpReceiver(), new Promise<Stream>()
-        {
-            @Override
-            public void succeeded(Stream stream)
-            {
-                stream.setIdleTimeout(idleTimeout);
-                if (content.hasContent())
-                    HttpSenderOverSPDY.this.stream = stream;
-                callback.succeeded();
-            }
-
-            @Override
-            public void failed(Throwable failure)
-            {
-                callback.failed(failure);
-            }
-        });
-    }
-
-    @Override
-    protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback)
-    {
-        if (content.isConsumed())
-        {
-            callback.succeeded();
-        }
-        else
-        {
-            ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(content.getByteBuffer(), content.isLast());
-            stream.data(dataInfo, callback);
-        }
-    }
-
-    @Override
-    protected void reset()
-    {
-        super.reset();
-        stream = null;
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java
deleted file mode 100644
index ab7a2a7..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/AbstractHttpClientServerTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.http.HttpScheme;
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public abstract class AbstractHttpClientServerTest
-{
-    @Parameterized.Parameters
-    public static Collection<SslContextFactory[]> parameters()
-    {
-        return Arrays.asList(new SslContextFactory[]{null}, new SslContextFactory[]{new SslContextFactory()});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-
-    protected SslContextFactory sslContextFactory;
-    protected String scheme;
-    protected Server server;
-    protected ServerConnector connector;
-    protected SPDYClient.Factory factory;
-    protected HttpClient client;
-
-    public AbstractHttpClientServerTest(SslContextFactory sslContextFactory)
-    {
-        this.sslContextFactory = sslContextFactory;
-        this.scheme = (sslContextFactory == null ? HttpScheme.HTTP : HttpScheme.HTTPS).asString();
-    }
-
-    public void start(Handler handler) throws Exception
-    {
-        short version = SPDY.V3;
-
-        HTTPSPDYServerConnectionFactory httpSPDY = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration());
-        if (sslContextFactory != null)
-        {
-            sslContextFactory.setEndpointIdentificationAlgorithm("");
-            sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-            sslContextFactory.setKeyStorePassword("storepwd");
-            sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-            sslContextFactory.setTrustStorePassword("storepwd");
-        }
-
-        server = new Server();
-        connector = new ServerConnector(server, AbstractConnectionFactory.getFactories(sslContextFactory, httpSPDY));
-        server.addConnector(connector);
-        server.setHandler(handler);
-        server.start();
-
-        QueuedThreadPool executor = new QueuedThreadPool();
-        executor.setName(executor.getName() + "-client");
-
-        factory = new SPDYClient.Factory(executor);
-        factory.start();
-        client = new HttpClient(new HttpClientTransportOverSPDY(factory.newSPDYClient(version)), sslContextFactory);
-        client.setExecutor(executor);
-        client.start();
-    }
-
-    @After
-    public void dispose() throws Exception
-    {
-        if (client != null)
-            client.stop();
-        if (factory != null)
-            factory.stop();
-        if (server != null)
-            server.stop();
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java
deleted file mode 100644
index 34743bf..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/EmptyServerHandler.java
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.io.IOException;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-
-public class EmptyServerHandler extends AbstractHandler
-{
-    @Override
-    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-    {
-        baseRequest.setHandled(true);
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java
deleted file mode 100644
index 7753ae4..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientCustomProxyTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.io.IOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.HttpClientTransport;
-import org.eclipse.jetty.client.HttpDestination;
-import org.eclipse.jetty.client.Origin;
-import org.eclipse.jetty.client.ProxyConfiguration;
-import org.eclipse.jetty.client.api.Connection;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.io.AbstractConnection;
-import org.eclipse.jetty.io.ClientConnectionFactory;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.PushStrategy;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class HttpClientCustomProxyTest
-{
-    public static final byte[] CAFE_BABE = new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE};
-
-    private Server server;
-    private ServerConnector connector;
-    private SPDYClient.Factory factory;
-    private HttpClient httpClient;
-
-    public void prepare(Handler handler) throws Exception
-    {
-        server = new Server();
-        connector = new ServerConnector(server, new CAFEBABEServerConnectionFactory(new HTTPSPDYServerConnectionFactory(SPDY.V3, new HttpConfiguration(), new PushStrategy.None())));
-        server.addConnector(connector);
-        server.setHandler(handler);
-        server.start();
-
-        QueuedThreadPool executor = new QueuedThreadPool();
-        executor.setName(executor.getName() + "-client");
-
-        factory = new SPDYClient.Factory(executor);
-        factory.start();
-
-        httpClient = new HttpClient(new HttpClientTransportOverSPDY(factory.newSPDYClient(SPDY.V3)), null);
-        httpClient.setExecutor(executor);
-        httpClient.start();
-    }
-
-    @After
-    public void dispose() throws Exception
-    {
-        if (httpClient != null)
-            httpClient.stop();
-        if (factory != null)
-            factory.stop();
-        if (server != null)
-            server.stop();
-    }
-
-    @Test
-    public void testCustomProxy() throws Exception
-    {
-        final String serverHost = "server";
-        final int status = HttpStatus.NO_CONTENT_204;
-        prepare(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                if (!URI.create(baseRequest.getUri().toString()).isAbsolute())
-                    response.setStatus(HttpServletResponse.SC_USE_PROXY);
-                else if (serverHost.equals(request.getServerName()))
-                    response.setStatus(status);
-                else
-                    response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
-            }
-        });
-
-        // Setup the custom proxy
-        int proxyPort = connector.getLocalPort();
-        int serverPort = proxyPort + 1; // Any port will do for these tests - just not the same as the proxy
-        httpClient.getProxyConfiguration().getProxies().add(new CAFEBABEProxy(new Origin.Address("localhost", proxyPort), false));
-
-        ContentResponse response = httpClient.newRequest(serverHost, serverPort)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertEquals(status, response.getStatus());
-    }
-
-    private class CAFEBABEProxy extends ProxyConfiguration.Proxy
-    {
-        private CAFEBABEProxy(Origin.Address address, boolean secure)
-        {
-            super(address, secure);
-        }
-
-        @Override
-        public ClientConnectionFactory newClientConnectionFactory(ClientConnectionFactory connectionFactory)
-        {
-            return new CAFEBABEClientConnectionFactory(connectionFactory);
-        }
-    }
-
-    private static class CAFEBABEClientConnectionFactory implements ClientConnectionFactory
-    {
-        private final ClientConnectionFactory connectionFactory;
-
-        private CAFEBABEClientConnectionFactory(ClientConnectionFactory connectionFactory)
-        {
-            this.connectionFactory = connectionFactory;
-        }
-
-        @Override
-        public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
-        {
-            HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
-            Executor executor = destination.getHttpClient().getExecutor();
-            return new CAFEBABEConnection(endPoint, executor, connectionFactory, context);
-        }
-    }
-
-    private static class CAFEBABEConnection extends AbstractConnection
-    {
-        private final ClientConnectionFactory connectionFactory;
-        private final Map<String, Object> context;
-
-        public CAFEBABEConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, Map<String, Object> context)
-        {
-            super(endPoint, executor);
-            this.connectionFactory = connectionFactory;
-            this.context = context;
-        }
-
-        @Override
-        public void onOpen()
-        {
-            super.onOpen();
-            fillInterested();
-            getEndPoint().write(new Callback.Adapter(), ByteBuffer.wrap(CAFE_BABE));
-        }
-
-        @Override
-        public void onFillable()
-        {
-            try
-            {
-                ByteBuffer buffer = BufferUtil.allocate(4);
-                int filled = getEndPoint().fill(buffer);
-                Assert.assertEquals(4, filled);
-                Assert.assertArrayEquals(CAFE_BABE, buffer.array());
-
-                // We are good, upgrade the connection
-                ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(getEndPoint(), context));
-            }
-            catch (Throwable x)
-            {
-                close();
-                @SuppressWarnings("unchecked")
-                Promise<Connection> promise = (Promise<Connection>)context.get(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY);
-                promise.failed(x);
-            }
-        }
-    }
-
-    private class CAFEBABEServerConnectionFactory extends AbstractConnectionFactory
-    {
-        private final org.eclipse.jetty.server.ConnectionFactory connectionFactory;
-
-        private CAFEBABEServerConnectionFactory(org.eclipse.jetty.server.ConnectionFactory connectionFactory)
-        {
-            super("cafebabe");
-            this.connectionFactory = connectionFactory;
-        }
-
-        @Override
-        public org.eclipse.jetty.io.Connection newConnection(Connector connector, EndPoint endPoint)
-        {
-            return new CAFEBABEServerConnection(connector, endPoint, connectionFactory);
-        }
-    }
-
-    private class CAFEBABEServerConnection extends AbstractConnection
-    {
-        private final org.eclipse.jetty.server.ConnectionFactory connectionFactory;
-
-        public CAFEBABEServerConnection(Connector connector, EndPoint endPoint, org.eclipse.jetty.server.ConnectionFactory connectionFactory)
-        {
-            super(endPoint, connector.getExecutor());
-            this.connectionFactory = connectionFactory;
-        }
-
-        @Override
-        public void onOpen()
-        {
-            super.onOpen();
-            fillInterested();
-        }
-
-        @Override
-        public void onFillable()
-        {
-            try
-            {
-                ByteBuffer buffer = BufferUtil.allocate(4);
-                int filled = getEndPoint().fill(buffer);
-                Assert.assertEquals(4, filled);
-                Assert.assertArrayEquals(CAFE_BABE, buffer.array());
-                getEndPoint().write(new Callback.Adapter(), buffer);
-
-                // We are good, upgrade the connection
-                ClientConnectionFactory.Helper.replaceConnection(this, connectionFactory.newConnection(connector, getEndPoint()));
-            }
-            catch (Throwable x)
-            {
-                close();
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java b/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java
deleted file mode 100644
index 2fcf1e9..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/test/java/org/eclipse/jetty/spdy/client/http/HttpClientTest.java
+++ /dev/null
@@ -1,467 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.client.http;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URLEncoder;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.zip.GZIPOutputStream;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
-import org.eclipse.jetty.client.util.BytesContentProvider;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.toolchain.test.annotation.Slow;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class HttpClientTest extends AbstractHttpClientServerTest
-{
-    public HttpClientTest(SslContextFactory sslContextFactory)
-    {
-        super(sslContextFactory);
-    }
-
-    @Test
-    public void test_GET_ResponseWithoutContent() throws Exception
-    {
-        start(new EmptyServerHandler());
-
-        Response response = client.GET(scheme + "://localhost:" + connector.getLocalPort());
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-    }
-
-    @Test
-    public void test_GET_ResponseWithContent() throws Exception
-    {
-        final byte[] data = new byte[]{0, 1, 2, 3, 4, 5, 6, 7};
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                response.getOutputStream().write(data);
-                baseRequest.setHandled(true);
-            }
-        });
-
-        ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort());
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        byte[] content = response.getContent();
-        Assert.assertArrayEquals(data, content);
-    }
-
-    @Test
-    public void test_GET_WithParameters_ResponseWithContent() throws Exception
-    {
-        final String paramName1 = "a";
-        final String paramName2 = "b";
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                response.setCharacterEncoding("UTF-8");
-                ServletOutputStream output = response.getOutputStream();
-                String paramValue1 = request.getParameter(paramName1);
-                output.write(paramValue1.getBytes("UTF-8"));
-                String paramValue2 = request.getParameter(paramName2);
-                Assert.assertEquals("", paramValue2);
-                output.write("empty".getBytes("UTF-8"));
-                baseRequest.setHandled(true);
-            }
-        });
-
-        String value1 = "\u20AC";
-        String paramValue1 = URLEncoder.encode(value1, "UTF-8");
-        String query = paramName1 + "=" + paramValue1 + "&" + paramName2;
-        ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query);
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        String content = new String(response.getContent(), "UTF-8");
-        Assert.assertEquals(value1 + "empty", content);
-    }
-
-    @Test
-    public void test_GET_WithParametersMultiValued_ResponseWithContent() throws Exception
-    {
-        final String paramName1 = "a";
-        final String paramName2 = "b";
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                response.setCharacterEncoding("UTF-8");
-                ServletOutputStream output = response.getOutputStream();
-                String[] paramValues1 = request.getParameterValues(paramName1);
-                for (String paramValue : paramValues1)
-                    output.write(paramValue.getBytes("UTF-8"));
-                String paramValue2 = request.getParameter(paramName2);
-                output.write(paramValue2.getBytes("UTF-8"));
-                baseRequest.setHandled(true);
-            }
-        });
-
-        String value11 = "\u20AC";
-        String value12 = "\u20AA";
-        String value2 = "&";
-        String paramValue11 = URLEncoder.encode(value11, "UTF-8");
-        String paramValue12 = URLEncoder.encode(value12, "UTF-8");
-        String paramValue2 = URLEncoder.encode(value2, "UTF-8");
-        String query = paramName1 + "=" + paramValue11 + "&" + paramName1 + "=" + paramValue12 + "&" + paramName2 + "=" + paramValue2;
-        ContentResponse response = client.GET(scheme + "://localhost:" + connector.getLocalPort() + "/?" + query);
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        String content = new String(response.getContent(), "UTF-8");
-        Assert.assertEquals(value11 + value12 + value2, content);
-    }
-
-    @Test
-    public void test_POST_WithParameters() throws Exception
-    {
-        final String paramName = "a";
-        final String paramValue = "\u20AC";
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                String value = request.getParameter(paramName);
-                if (paramValue.equals(value))
-                {
-                    response.setCharacterEncoding("UTF-8");
-                    response.setContentType("text/plain");
-                    response.getOutputStream().print(value);
-                }
-            }
-        });
-
-        ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort())
-                .param(paramName, paramValue)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8"));
-    }
-
-    @Test
-    public void test_PUT_WithParameters() throws Exception
-    {
-        final String paramName = "a";
-        final String paramValue = "\u20AC";
-        final String encodedParamValue = URLEncoder.encode(paramValue, "UTF-8");
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                String value = request.getParameter(paramName);
-                if (paramValue.equals(value))
-                {
-                    response.setCharacterEncoding("UTF-8");
-                    response.setContentType("text/plain");
-                    response.getOutputStream().print(value);
-                }
-            }
-        });
-
-        URI uri = URI.create(scheme + "://localhost:" + connector.getLocalPort() + "/path?" + paramName + "=" + encodedParamValue);
-        ContentResponse response = client.newRequest(uri)
-                .method(HttpMethod.PUT)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertEquals(paramValue, new String(response.getContent(), "UTF-8"));
-    }
-
-    @Test
-    public void test_POST_WithParameters_WithContent() throws Exception
-    {
-        final byte[] content = {0, 1, 2, 3};
-        final String paramName = "a";
-        final String paramValue = "\u20AC";
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                String value = request.getParameter(paramName);
-                if (paramValue.equals(value))
-                {
-                    response.setCharacterEncoding("UTF-8");
-                    response.setContentType("application/octet-stream");
-                    response.getOutputStream().write(content);
-                }
-            }
-        });
-
-        ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort() + "/?b=1")
-                .param(paramName, paramValue)
-                .content(new BytesContentProvider(content))
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertArrayEquals(content, response.getContent());
-    }
-
-    @Test
-    public void test_POST_WithContent_NotifiesRequestContentListener() throws Exception
-    {
-        final byte[] content = {0, 1, 2, 3};
-        start(new EmptyServerHandler());
-
-        ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort())
-                .onRequestContent(new Request.ContentListener()
-                {
-                    @Override
-                    public void onContent(Request request, ByteBuffer buffer)
-                    {
-                        byte[] bytes = new byte[buffer.remaining()];
-                        buffer.get(bytes);
-                        if (!Arrays.equals(content, bytes))
-                            request.abort(new Exception());
-                    }
-                })
-                .content(new BytesContentProvider(content))
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-    }
-
-    @Test
-    public void test_POST_WithContent_TracksProgress() throws Exception
-    {
-        start(new EmptyServerHandler());
-
-        final AtomicInteger progress = new AtomicInteger();
-        ContentResponse response = client.POST(scheme + "://localhost:" + connector.getLocalPort())
-                .onRequestContent(new Request.ContentListener()
-                {
-                    @Override
-                    public void onContent(Request request, ByteBuffer buffer)
-                    {
-                        byte[] bytes = new byte[buffer.remaining()];
-                        Assert.assertEquals(1, bytes.length);
-                        buffer.get(bytes);
-                        Assert.assertEquals(bytes[0], progress.getAndIncrement());
-                    }
-                })
-                .content(new BytesContentProvider(new byte[]{0}, new byte[]{1}, new byte[]{2}, new byte[]{3}, new byte[]{4}))
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertEquals(5, progress.get());
-    }
-
-    @Test
-    public void test_GZIP_ContentEncoding() throws Exception
-    {
-        final byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                response.setHeader("Content-Encoding", "gzip");
-                GZIPOutputStream gzipOutput = new GZIPOutputStream(response.getOutputStream());
-                gzipOutput.write(data);
-                gzipOutput.finish();
-            }
-        });
-
-        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
-                .scheme(scheme)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertArrayEquals(data, response.getContent());
-    }
-
-    @Slow
-    @Test
-    public void test_Request_IdleTimeout() throws Exception
-    {
-        final long idleTimeout = 1000;
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                try
-                {
-                    baseRequest.setHandled(true);
-                    TimeUnit.MILLISECONDS.sleep(2 * idleTimeout);
-                }
-                catch (InterruptedException x)
-                {
-                    throw new ServletException(x);
-                }
-            }
-        });
-
-        final String host = "localhost";
-        final int port = connector.getLocalPort();
-        try
-        {
-            client.newRequest(host, port)
-                    .scheme(scheme)
-                    .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS)
-                    .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS)
-                    .send();
-            Assert.fail();
-        }
-        catch (ExecutionException expected)
-        {
-            Assert.assertTrue(expected.getCause() instanceof TimeoutException);
-        }
-
-        // Make another request without specifying the idle timeout, should not fail
-        ContentResponse response = client.newRequest(host, port)
-                .scheme(scheme)
-                .timeout(3 * idleTimeout, TimeUnit.MILLISECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-    }
-
-    @Test
-    public void testSendToIPv6Address() throws Exception
-    {
-        start(new EmptyServerHandler());
-
-        ContentResponse response = client.newRequest("[::1]", connector.getLocalPort())
-                .scheme(scheme)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-    }
-
-    @Test
-    public void test_HEAD_With_ResponseContentLength() throws Exception
-    {
-        final int length = 1024;
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                response.getOutputStream().write(new byte[length]);
-            }
-        });
-
-        // HEAD requests receive a Content-Length header, but do not
-        // receive the content so they must handle this case properly
-        ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
-                .scheme(scheme)
-                .method(HttpMethod.HEAD)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertEquals(0, response.getContent().length);
-
-        // Perform a normal GET request to be sure the content is now read
-        response = client.newRequest("localhost", connector.getLocalPort())
-                .scheme(scheme)
-                .timeout(5, TimeUnit.SECONDS)
-                .send();
-
-        Assert.assertNotNull(response);
-        Assert.assertEquals(200, response.getStatus());
-        Assert.assertEquals(length, response.getContent().length);
-    }
-
-    @Test
-    public void testLongPollIsAbortedWhenClientIsStopped() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        start(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                request.startAsync();
-                latch.countDown();
-            }
-        });
-
-        final CountDownLatch completeLatch = new CountDownLatch(1);
-        client.newRequest("localhost", connector.getLocalPort())
-                .scheme(scheme)
-                .send(new Response.CompleteListener()
-                {
-                    @Override
-                    public void onComplete(Result result)
-                    {
-                        if (result.isFailed())
-                            completeLatch.countDown();
-                    }
-                });
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-
-        // Stop the client, the complete listener must be invoked.
-        client.stop();
-
-        Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties
deleted file mode 100644
index 8163013..0000000
--- a/jetty-spdy/spdy-http-client-transport/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.LEVEL=DEBUG
-#org.eclipse.jetty.client.LEVEL=DEBUG
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
diff --git a/jetty-spdy/spdy-http-common/pom.xml b/jetty-spdy/spdy-http-common/pom.xml
deleted file mode 100644
index 769206b..0000000
--- a/jetty-spdy/spdy-http-common/pom.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-http-common</artifactId>
-    <name>Jetty :: SPDY :: HTTP Common</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.http.common</bundle-symbolic-name>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.http;version="9.1"</Export-Package>
-                                <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java b/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java
deleted file mode 100644
index 2959d6e..0000000
--- a/jetty-spdy/spdy-http-common/src/main/java/org/eclipse/jetty/spdy/http/HTTPSPDYHeader.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.http;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-
-/**
- * <p>{@link HTTPSPDYHeader} defines the SPDY headers that are not also HTTP headers,
- * such as <tt>method</tt>, <tt>version</tt>, etc. or that are treated differently
- * by the SPDY protocol, such as <tt>host</tt>.</p>
- */
-public enum HTTPSPDYHeader
-{
-    METHOD("method", ":method"),
-    URI("url", ":path"),
-    VERSION("version", ":version"),
-    SCHEME("scheme", ":scheme"),
-    HOST("host", ":host"),
-    STATUS("status", ":status");
-
-    public static HTTPSPDYHeader from(short version, String name)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return Names.v2Names.get(name);
-            case SPDY.V3:
-                return Names.v3Names.get(name);
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private final String v2Name;
-    private final String v3Name;
-
-    private HTTPSPDYHeader(String v2Name, String v3Name)
-    {
-        this.v2Name = v2Name;
-        Names.v2Names.put(v2Name, this);
-        this.v3Name = v3Name;
-        Names.v3Names.put(v3Name, this);
-    }
-
-    public String name(short version)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-                return v2Name;
-            case SPDY.V3:
-                return v3Name;
-            default:
-                throw new IllegalStateException();
-        }
-    }
-
-    private static class Names
-    {
-        private static final Map<String, HTTPSPDYHeader> v2Names = new HashMap<>();
-        private static final Map<String, HTTPSPDYHeader> v3Names = new HashMap<>();
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml
deleted file mode 100644
index b205840..0000000
--- a/jetty-spdy/spdy-http-server/pom.xml
+++ /dev/null
@@ -1,120 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-http-server</artifactId>
-    <name>Jetty :: SPDY :: HTTP Server</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.http.server</bundle-symbolic-name>
-    </properties>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>single</goal>
-                        </goals>
-                        <configuration>
-                            <descriptorRefs>
-                                <descriptorRef>config</descriptorRef>
-                            </descriptorRefs>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>artifact-jars</id>
-                        <goals>
-                            <goal>jar</goal>
-                            <goal>test-jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.server.http;version="9.1",
-                                    org.eclipse.jetty.spdy.server.proxy;version="9.1"
-                                </Export-Package>
-                                <Import-Package>!org.eclipse.jetty.npn,org.eclipse.jetty.*;version="[9.0,10.0)",*
-                                </Import-Package>
-                                <_nouses>true</_nouses>
-                            </instructions>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-common</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-server</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-servlet</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-servlets</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.npn</groupId>
-            <artifactId>npn-api</artifactId>
-            <version>${npn.api.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-continuation</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml
deleted file mode 100644
index c525bd1..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy-proxy.xml
+++ /dev/null
@@ -1,158 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<!-- ============================================================= -->
-<!-- Configure the Jetty Server instance with an ID "Server"       -->
-<!-- by adding a SPDY connector.                                   -->
-<!-- This configuration must be used in conjunction with jetty.xml -->
-<!-- It should not be used with jetty-https.xml as this connector  -->
-<!-- can provide both HTTPS and SPDY connections                   -->
-<!-- ============================================================= -->
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-  <!-- =========================================================== -->
-  <!-- Setup the SSL Context factory used to establish all TLS     -->
-  <!-- Connections and session.                                    -->
-  <!--                                                             -->
-  <!-- Consult the javadoc of o.e.j.util.ssl.SslContextFactory     -->
-  <!-- o.e.j.server.HttpConnectionFactory for all configuration    -->
-  <!-- that may be set here.                                       -->
-  <!-- =========================================================== -->
-  <New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-    <Set name="KeyStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
-    <Set name="KeyStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
-    <Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
-    <Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
-    <Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
-  </New>
-
-  <!-- =========================================================== -->
-  <!-- Enables NPN debugging on System.err                         -->
-  <!-- ===========================================================
-  <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
-  -->
-
-  <!-- =========================================================== -->
-  <!-- Create a TLS specific HttpConfiguration based on the        -->
-  <!-- common HttpConfiguration defined in jetty.xml               -->
-  <!-- Add a SecureRequestCustomizer to extract certificate and    -->
-  <!-- session information                                         -->
-  <!-- =========================================================== -->
-  <New id="tlsHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
-    <Arg><Ref refid="httpConfig"/></Arg>
-    <Call name="addCustomizer">
-      <Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
-    </Call>
-  </New>
-
-  <!-- =========================================================== -->
-  <!-- This is the upstream server connector.                      -->
-  <!-- It speaks non-SSL SPDY/3(HTTP) on port 9090.                -->
-  <!-- =========================================================== -->
-  <Call name="addConnector">
-    <Arg>
-      <New class="org.eclipse.jetty.server.ServerConnector">
-        <Arg name="server">
-          <Ref refid="Server"/>
-        </Arg>
-        <Arg name="factories">
-          <Array type="org.eclipse.jetty.server.ConnectionFactory">
-            <!-- SPDY/3 Connection factory -->
-            <Item>
-              <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                <Arg name="version" type="int">3</Arg>
-                <Arg name="config">
-                  <Ref refid="tlsHttpConfig"/>
-                </Arg>
-              </New>
-            </Item>
-          </Array>
-        </Arg>
-        <Set name="port">9090</Set>
-      </New>
-    </Arg>
-  </Call>
-
-  <!-- =========================================================== -->
-  <!-- This ProxyEngine translates the incoming SPDY/x(HTTP)       -->
-  <!-- requests to SPDY/2(HTTP)                                    -->
-  <!-- =========================================================== -->
-  <New id="spdyProxyEngine" class="org.eclipse.jetty.spdy.server.proxy.SPDYProxyEngine">
-    <Arg>
-      <New class="org.eclipse.jetty.spdy.client.SPDYClient$Factory">
-        <Call name="start"/>
-      </New>
-    </Arg>
-  </New>
-
-  <!-- =========================================================== -->
-  <!-- The ProxyEngineSelector receives SPDY/x(HTTP) requests      -->
-  <!-- from proxy connectors below and is configured to process    -->
-  <!-- requests for host "localhost".                              -->
-  <!-- Such requests are converted from SPDY/x(HTTP) to            -->
-  <!-- SPDY/3(HTTP) by the configured ProxyEngine and forwarded    -->
-  <!-- to 127.0.0.1:9090, where they are served by the upstream    -->
-  <!-- server above.                                               -->
-  <!-- =========================================================== -->
-  <New id="proxyEngineSelector" class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector">
-    <Call name="putProxyEngine">
-      <Arg>spdy/3</Arg>
-      <Arg>
-        <Ref refid="spdyProxyEngine"/>
-      </Arg>
-    </Call>
-    <Set name="proxyServerInfos">
-      <Map>
-        <Entry>
-          <Item>localhost</Item>
-          <Item>
-            <New class="org.eclipse.jetty.spdy.server.proxy.ProxyEngineSelector$ProxyServerInfo">
-              <Arg type="String">spdy/3</Arg>
-              <Arg>127.0.0.1</Arg>
-              <Arg type="int">9090</Arg>
-            </New>
-          </Item>
-        </Entry>
-      </Map>
-    </Set>
-  </New>
-
-  <!-- =========================================================== -->
-  <!-- These are the reverse proxy connectors accepting requests   -->
-  <!-- from clients.                                               -->
-  <!-- They accept non-SSL (on port 8080) and SSL (on port 8443)   -->
-  <!-- HTTP, SPDY/2(HTTP) and SPDY/3(HTTP).                        -->
-  <!-- Non-SPDY HTTP requests are converted to SPDY internally     -->
-  <!-- and passed to the ProxyEngine above.                        -->
-  <!-- =========================================================== -->
-  <Call name="addConnector">
-    <Arg>
-      <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
-        <Arg>
-          <Ref refid="Server"/>
-        </Arg>
-        <Arg>
-          <Ref refid="proxyEngineSelector"/>
-        </Arg>
-        <Set name="Port">8080</Set>
-      </New>
-    </Arg>
-  </Call>
-  <Call name="addConnector">
-    <Arg>
-      <New class="org.eclipse.jetty.spdy.server.proxy.HTTPSPDYProxyServerConnector">
-        <Arg>
-          <Ref refid="Server"/>
-        </Arg>
-        <Arg>
-          <Ref refid="sslContextFactory"/>
-        </Arg>
-        <Arg>
-          <Ref refid="proxyEngineSelector"/>
-        </Arg>
-        <Set name="Port">8443</Set>
-      </New>
-    </Arg>
-  </Call>
-
-</Configure>
diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml
deleted file mode 100644
index b094d7c..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/etc/jetty-spdy.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<!-- ============================================================= -->
-<!-- Configure a SPDY connector.                                   -->
-<!-- This configuration must be used in conjunction with jetty.xml -->
-<!-- and jetty-ssl.xml                                             -->
-<!-- ============================================================= -->
-<Configure id="Server" class="org.eclipse.jetty.server.Server">
-
-    <!-- =========================================================== -->
-    <!-- Create a push strategy which can be used by reference by    -->
-    <!-- individual connection factories below.                      -->
-    <!--                                                             -->
-    <!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
-    <!-- for all configuration that may be set here.                 -->
-    <!-- =========================================================== -->
-    <New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
-        <!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
-             user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
-        <!--
-        <Set name="UserAgentBlacklist">
-            <Array type="String">
-                <Item>.*(?i)firefox/14.*</Item>
-                <Item>.*(?i)firefox/15.*</Item>
-                <Item>.*(?i)firefox/16.*</Item>
-            </Array>
-        </Set>
-        -->
-
-        <!-- Uncomment to override default file extensions to push -->
-        <!--
-        <Set name="PushRegexps">
-            <Array type="String">
-               <Item>.*\.css</Item>
-               <Item>.*\.js</Item>
-               <Item>.*\.png</Item>
-               <Item>.*\.jpg</Item>
-               <Item>.*\.gif</Item>
-           </Array>
-        </Set>
-        -->
-        <Set name="referrerPushPeriod">5000</Set>
-        <Set name="maxAssociatedResources">32</Set>
-    </New>
-
-    <!-- =========================================================== -->
-    <!-- Add a SPDY/HTTPS Connector.                                 -->
-    <!-- Configure an o.e.j.server.ServerConnector with connection   -->
-    <!-- factories for TLS (aka SSL), ProtoNego, SPDY and HTTP to    -->
-    <!-- provide a connector that can accept HTTPS or SPDY           -->
-    <!-- connections.                                                -->
-    <!--                                                             -->
-    <!-- All accepted TLS connections are initially wired to a       -->
-    <!-- Protonego connection, which attempts to use a TLS extension -->
-    <!-- to negotiation the protocol.  If it is not supported by     -->
-    <!-- the client, then the connection is replaced by a HTTP       -->
-    <!-- connection.  If a specific protocol version (eg spdy/3) is  -->
-    <!-- negotiated, then the appropriate connection factory         -->
-    <!-- is used to create a connection to replace the connection    -->
-    <!--                                                             -->
-    <!-- The final result is a SPDY or HTTP connection wired behind  -->
-    <!-- a TLS (aka SSL) connection.                                 -->
-    <!--                                                             -->
-    <!-- Consult the javadoc of o.e.j.server.ServerConnector and the -->
-    <!-- specific connection factory types for all configuration     -->
-    <!-- that may be set here.                                       -->
-    <!-- =========================================================== -->
-    <Call id="spdyConnector" name="addConnector">
-        <Arg>
-            <New class="org.eclipse.jetty.server.ServerConnector">
-                <Arg name="server">
-                    <Ref refid="Server"/>
-                </Arg>
-                <Arg name="factories">
-                    <Array type="org.eclipse.jetty.server.ConnectionFactory">
-
-                        <!-- SSL Connection factory with Protonego as next protocol -->
-                        <Item>
-                            <New class="org.eclipse.jetty.server.SslConnectionFactory">
-                                <Arg name="next"><Property name="protonego"/></Arg>
-                                <Arg name="sslContextFactory">
-                                    <Ref refid="sslContextFactory"/>
-                                </Arg>
-                            </New>
-                        </Item>
-
-                        <!-- NPN Connection factory with HTTP as default protocol -->
-                        <Item>
-			    <Ref refid="protonego"/>
-                        </Item>
-
-                        <!-- SPDY/3 Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">3</Arg>
-                                <Arg name="config">
-                                    <Ref refid="sslHttpConfig"/>
-                                </Arg>
-                                <!-- Set the initial window size for this SPDY connector. -->
-                                <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
-                                <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set>
-                                <!-- Uncomment to enable ReferrerPushStrategy -->
-                                <!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>-->
-                            </New>
-                        </Item>
-
-                        <!-- SPDY/2 Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
-                                <Arg name="version" type="int">2</Arg>
-                                <Arg name="config">
-                                    <Ref refid="sslHttpConfig"/>
-                                </Arg>
-                                <!-- Set the initial window size for this SPDY connector. -->
-                                <!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
-                                <Set name="initialWindowSize"><Property name="spdy.initialWindowSize" default="65536"/></Set>
-                            </New>
-                        </Item>
-
-                        <!-- HTTP Connection factory -->
-                        <Item>
-                            <New class="org.eclipse.jetty.server.HttpConnectionFactory">
-                                <Arg name="config">
-                                    <Ref refid="sslHttpConfig"/>
-                                </Arg>
-                            </New>
-                        </Item>
-                    </Array>
-                </Arg>
-
-                <Set name="host"><Property name="jetty.host"/></Set>
-                <Set name="port"><Property name="spdy.port" default="443"/></Set>
-                <Set name="idleTimeout"><Property name="spdy.timeout" default="30000"/></Set>
-            </New>
-        </Arg>
-    </Call>
-
-</Configure>
diff --git a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml b/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml
deleted file mode 100644
index 6e30f39..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/etc/protonego-npn.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure id="protonego" class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory">
-    <Arg name="protocols">
-	<Array type="String">
-	    <Item>spdy/3</Item>
-	    <Item>spdy/2</Item>
-	    <Item>http/1.1</Item>
-	</Array>
-    </Arg>
-   
-    <Set name="defaultProtocol">http/1.1</Set>
-
-    <!-- =========================================================== -->
-    <!-- Enables NPN debugging on System.err                         -->
-    <!-- ===========================================================
-     <Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
-    -->
-
-</Configure>
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_04.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_06.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_07.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_09.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_10.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_11.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod
deleted file mode 100644
index 1645a52..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_13.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.4.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_15.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_17.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_21.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_25.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_67.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod
deleted file mode 100644
index 851aca8..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_71.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod
deleted file mode 100644
index 851aca8..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_72.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_75.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_76.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_79.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod
deleted file mode 100644
index 2cce5fa..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_80.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.11.v20150415/npn-boot-1.1.11.v20150415.jar|lib/npn/npn-boot-1.1.11.v20150415.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.11.v20150415.jar
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod
deleted file mode 100644
index 1a2c71d..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn.mod
+++ /dev/null
@@ -1,37 +0,0 @@
-# NPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the NPN layer needed for SPDY.
-#
-# This modification has a tight dependency on specific updates of Java 1.7.
-# (No support for Java 8 exists for npn / npn-boot, use alpn instead)
-#
-# The npn module will use an appropriate npn-boot jar for your specific
-# version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing npn-boot jars, and might
-#            need a new npn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of npn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/
-
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/npn-${java.version}
-
-[xml]
-etc/protonego-npn.xml
-
-[files]
-lib/
-lib/npn/
-
-[license]
-NPN is a hosted at github under the GPL v2 with ClassPath Exception.
-NPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
-http://github.com/jetty-project/jetty-npn
-http://openjdk.java.net/legal/gplv2+ce.html
diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod
deleted file mode 100644
index cf79dfa..0000000
--- a/jetty-spdy/spdy-http-server/src/main/config/modules/spdy.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# SPDY Support Module
-#
-
-[depend]
-ssl
-protonego
-
-[lib]
-lib/spdy/*.jar
-
-[xml]
-etc/jetty-ssl.xml
-etc/jetty-spdy.xml
-
-[ini-template]
-## SPDY Configuration
-
-# Port for SPDY connections
-spdy.port=8443
-
-# SPDY idle timeout in milliseconds
-spdy.timeout=30000
-
-# Initial Window Size for SPDY
-#spdy.initialWindowSize=65536
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java
deleted file mode 100644
index 34eef7c..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnectionFactory.java
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.http;
-
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.annotation.Name;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory implements HttpConfiguration.ConnectionFactory
-{
-    private static final String CHANNEL_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.HTTPChannelOverSPDY";
-    private static final Logger LOG = Log.getLogger(HTTPSPDYServerConnectionFactory.class);
-
-    private final PushStrategy pushStrategy;
-    private final HttpConfiguration httpConfiguration;
-
-    public HTTPSPDYServerConnectionFactory(
-        @Name("version") int version,
-        @Name("config") HttpConfiguration config)
-    {
-        this(version,config,new PushStrategy.None());
-    }
-
-    public HTTPSPDYServerConnectionFactory(
-        @Name("version") int version,
-        @Name("config") HttpConfiguration config,
-        @Name("pushStrategy") PushStrategy pushStrategy)
-    {
-        super(version);
-        this.pushStrategy = pushStrategy;
-        httpConfiguration = config;
-        addBean(httpConfiguration);
-    }
-
-    @Override
-    public HttpConfiguration getHttpConfiguration()
-    {
-        return httpConfiguration;
-    }
-
-    @Override
-    protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
-    {
-        return new HTTPServerFrameListener(connector,endPoint);
-    }
-
-    private class HTTPServerFrameListener extends ServerSessionFrameListener.Adapter implements StreamFrameListener
-    {
-        private final Connector connector;
-        private final EndPoint endPoint;
-
-        public HTTPServerFrameListener(Connector connector,EndPoint endPoint)
-        {
-            this.endPoint = endPoint;
-            this.connector=connector;
-        }
-
-        @Override
-        public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
-        {
-            // Every time we have a SYN, it maps to a HTTP request.
-            // We can have multiple concurrent SYNs on the same connection,
-            // and this is very different from HTTP, where only one request
-            // can arrive on the same connection, so we need to create an
-            // HttpChannel for each SYN in order to run concurrently.
-
-            if (LOG.isDebugEnabled())
-                LOG.debug("Received {} on {}", synInfo, stream);
-
-            Fields headers = synInfo.getHeaders();
-            // According to SPDY/3 spec section 3.2.1 user-agents MUST support gzip compression. Firefox omits the
-            // accept-encoding header as it is redundant to negotiate gzip compression support with the server,
-            // if clients have to accept it.
-            // So we inject the accept-encoding header here, even if not set by the client. This will enforce SPDY
-            // clients to follow the spec and enable gzip compression if GzipFilter or the like is enabled.
-            if (!(headers.get("accept-encoding") != null && headers.get("accept-encoding").getValue().contains
-                    ("gzip")))
-                headers.add("accept-encoding", "gzip");
-            HttpTransportOverSPDY transport = new HttpTransportOverSPDY(connector, httpConfiguration, endPoint,
-                    pushStrategy, stream, headers);
-            HttpInputOverSPDY input = new HttpInputOverSPDY();
-            HttpChannelOverSPDY channel = new HttpChannelOverSPDY(connector, httpConfiguration, endPoint, transport, input, stream);
-            stream.setAttribute(CHANNEL_ATTRIBUTE, channel);
-
-            channel.requestStart(headers, synInfo.isClose());
-
-            if (headers.isEmpty())
-            {
-                // If the SYN has no headers, they may come later in a HEADERS frame
-                return this;
-            }
-            else
-            {
-                if (synInfo.isClose())
-                    return null;
-                else
-                    return this;
-            }
-        }
-
-        @Override
-        public void onReply(Stream stream, ReplyInfo replyInfo)
-        {
-            // Do nothing, servers cannot get replies
-        }
-
-        @Override
-        public void onHeaders(Stream stream, HeadersInfo headersInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Received {} on {}", headersInfo, stream);
-            HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
-            channel.requestHeaders(headersInfo.getHeaders(), headersInfo.isClose());
-        }
-
-        @Override
-        public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-        {
-            return null;
-        }
-
-        @Override
-        public void onData(Stream stream, final DataInfo dataInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Received {} on {}", dataInfo, stream);
-            HttpChannelOverSPDY channel = (HttpChannelOverSPDY)stream.getAttribute(CHANNEL_ATTRIBUTE);
-            channel.requestContent(dataInfo, dataInfo.isClose());
-        }
-
-        @Override
-        public void onFailure(Stream stream, Throwable x)
-        {
-            LOG.debug(x);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java
deleted file mode 100644
index 25d1e39..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HTTPSPDYServerConnector.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class HTTPSPDYServerConnector extends ServerConnector
-{
-    public HTTPSPDYServerConnector(Server server)
-    {
-        this(server, Collections.<Short, PushStrategy>emptyMap());
-    }
-
-    public HTTPSPDYServerConnector(Server server, SslContextFactory sslContextFactory)
-    {
-        this(server, sslContextFactory, Collections.<Short, PushStrategy>emptyMap());
-    }
-
-    public HTTPSPDYServerConnector(Server server, Map<Short, PushStrategy> pushStrategies)
-    {
-        this(server, null, pushStrategies);
-    }
-
-    public HTTPSPDYServerConnector(Server server, SslContextFactory sslContextFactory, Map<Short, PushStrategy> pushStrategies)
-    {
-        this(server, new HttpConfiguration(), sslContextFactory, pushStrategies);
-    }
-
-    public HTTPSPDYServerConnector(Server server, short version, HttpConfiguration httpConfiguration, PushStrategy push)
-    {
-        super(server, new HTTPSPDYServerConnectionFactory(version, httpConfiguration, push));
-    }
-
-    public HTTPSPDYServerConnector(Server server, HttpConfiguration config, SslContextFactory sslContextFactory, Map<Short, PushStrategy> pushStrategies)
-    {
-        super(server, AbstractConnectionFactory.getFactories(sslContextFactory,
-                sslContextFactory == null
-                        ? new ConnectionFactory[]{new HttpConnectionFactory(config)}
-                        : new ConnectionFactory[]{new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"),
-                        new HttpConnectionFactory(config),
-                        new HTTPSPDYServerConnectionFactory(SPDY.V3, config, getPushStrategy(SPDY.V3, pushStrategies)),
-                        new HTTPSPDYServerConnectionFactory(SPDY.V2, config, getPushStrategy(SPDY.V2, pushStrategies))}));
-        NPNServerConnectionFactory npnConnectionFactory = getConnectionFactory(NPNServerConnectionFactory.class);
-        if (npnConnectionFactory != null)
-            npnConnectionFactory.setDefaultProtocol("http/1.1");
-    }
-
-    private static PushStrategy getPushStrategy(short version, Map<Short, PushStrategy> pushStrategies)
-    {
-        PushStrategy pushStrategy = pushStrategies.get(version);
-        if (pushStrategy == null)
-            pushStrategy = new PushStrategy.None();
-        return pushStrategy;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
deleted file mode 100644
index f336f4f..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpChannelOverSPDY.java
+++ /dev/null
@@ -1,246 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.nio.ByteBuffer;
-
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpTransport;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class HttpChannelOverSPDY extends HttpChannel<DataInfo>
-{
-    private static final Logger LOG = Log.getLogger(HttpChannelOverSPDY.class);
-
-    private final Stream stream;
-    private boolean dispatched; // Guarded by synchronization on tasks
-    private boolean redispatch; // Guarded by synchronization on tasks
-    private boolean headersComplete;
-
-    public HttpChannelOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInputOverSPDY input, Stream stream)
-    {
-        super(connector, configuration, endPoint, transport, input);
-        this.stream = stream;
-    }
-
-    @Override
-    public long getIdleTimeout()
-    {
-        return stream.getIdleTimeout();
-    }
-    
-    @Override
-    public boolean headerComplete()
-    {
-        headersComplete = true;
-        return super.headerComplete();
-    }
-
-    private void dispatch()
-    {
-        synchronized (this)
-        {
-            if (dispatched)
-                redispatch=true;
-            else
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Dispatch {}", this);
-                dispatched=true;
-                execute(this);
-            }
-        }
-    }
-
-    @Override
-    public void run()
-    {
-        boolean execute=true;
-        
-        while(execute)
-        {
-            try
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Executing {}",this);
-                super.run();
-            }
-            finally
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Completing {}", this);
-                synchronized (this)
-                {
-                    dispatched = redispatch;
-                    redispatch=false;
-                    execute=dispatched;
-                }
-            }
-        }
-    }
-    
-
-    public void requestStart(final Fields headers, final boolean endRequest)
-    {
-        if (!headers.isEmpty())
-            requestHeaders(headers, endRequest);
-    }
-
-    public void requestHeaders(Fields headers, boolean endRequest)
-    {
-        boolean proceed = performBeginRequest(headers);
-        if (!proceed)
-            return;
-
-        performHeaders(headers);
-
-        if (endRequest)
-        {
-            boolean dispatch = headerComplete();
-            if (messageComplete())
-                dispatch=true;
-            if (dispatch)
-                dispatch();
-        }
-    }
-
-    public void requestContent(final DataInfo dataInfo, boolean endRequest)
-    {
-        boolean dispatch=false;
-        if (!headersComplete && headerComplete())
-            dispatch=true;
-
-        if (LOG.isDebugEnabled())
-            LOG.debug("HTTP > {} bytes of content", dataInfo.length());
-
-        // We need to copy the dataInfo since we do not know when its bytes
-        // will be consumed. When the copy is consumed, we consume also the
-        // original, so the implementation can send a window update.
-        ByteBuffer copyByteBuffer = dataInfo.asByteBuffer(false);
-        ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(copyByteBuffer, dataInfo.isClose())
-        {
-            @Override
-            public void consume(int delta)
-            {
-                super.consume(delta);
-                dataInfo.consume(delta);
-            }
-        };
-        if (LOG.isDebugEnabled())
-            LOG.debug("Queuing last={} content {}", endRequest, copyDataInfo);
-
-        if (content(copyDataInfo))
-            dispatch=true;
-
-        if (endRequest && messageComplete())
-            dispatch=true;
-        
-        if (dispatch)
-            dispatch();
-    }
-    
-    @Override
-    public boolean messageComplete()
-    {
-        super.messageComplete();
-        return false;
-    }
-
-    private boolean performBeginRequest(Fields headers)
-    {
-        short version = stream.getSession().getVersion();
-        Fields.Field methodHeader = headers.get(HTTPSPDYHeader.METHOD.name(version));
-        Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version));
-        Fields.Field versionHeader = headers.get(HTTPSPDYHeader.VERSION.name(version));
-
-        if (methodHeader == null || uriHeader == null || versionHeader == null)
-        {
-            badMessage(400, "Missing required request line elements");
-            return false;
-        }
-
-        HttpMethod httpMethod = HttpMethod.fromString(methodHeader.getValue());
-        HttpVersion httpVersion = HttpVersion.fromString(versionHeader.getValue());
-
-        // TODO should handle URI as byte buffer as some bad clients send WRONG encodings in query string
-        // that  we have to deal with
-        ByteBuffer uri = BufferUtil.toBuffer(uriHeader.getValue());
-
-        if (LOG.isDebugEnabled())
-            LOG.debug("HTTP > {} {} {}", httpMethod, uriHeader.getValue(), httpVersion);
-        startRequest(httpMethod, httpMethod.asString(), uri, httpVersion);
-
-        Fields.Field schemeHeader = headers.get(HTTPSPDYHeader.SCHEME.name(version));
-        if (schemeHeader != null)
-            getRequest().setScheme(schemeHeader.getValue());
-        return true;
-    }
-
-    private void performHeaders(Fields headers)
-    {
-        for (Fields.Field header : headers)
-        {
-            String name = header.getName();
-
-            // Skip special SPDY headers, unless it's the "host" header
-            HTTPSPDYHeader specialHeader = HTTPSPDYHeader.from(stream.getSession().getVersion(), name);
-            if (specialHeader != null)
-            {
-                if (specialHeader == HTTPSPDYHeader.HOST)
-                    name = "host";
-                else
-                    continue;
-            }
-
-            switch (name)
-            {
-                case "connection":
-                case "keep-alive":
-                case "proxy-connection":
-                case "transfer-encoding":
-                {
-                    // Spec says to ignore these headers
-                    continue;
-                }
-                default:
-                {
-                    // Spec says headers must be single valued
-                    String value = header.getValue();
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("HTTP > {}: {}", name, value);
-                    parsedHeader(new HttpField(name,value));
-                    break;
-                }
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java
deleted file mode 100644
index 08bb592..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpInputOverSPDY.java
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import org.eclipse.jetty.server.QueuedHttpInput;
-import org.eclipse.jetty.spdy.api.DataInfo;
-
-public class HttpInputOverSPDY extends QueuedHttpInput<DataInfo>
-{
-    @Override
-    protected int remaining(DataInfo item)
-    {
-        return item.available();
-    }
-
-    @Override
-    protected int get(DataInfo item, byte[] buffer, int offset, int length)
-    {
-        return item.readInto(buffer, offset, length);
-    }
-    
-    @Override
-    protected void consume(DataInfo item, int length)
-    {
-        item.consume(length);
-    }
-
-    @Override
-    protected void onContentConsumed(DataInfo dataInfo)
-    {
-        dataInfo.consume(dataInfo.length());
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java
deleted file mode 100644
index aa46cd3..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDY.java
+++ /dev/null
@@ -1,423 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.nio.ByteBuffer;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.EofException;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpTransport;
-import org.eclipse.jetty.spdy.StreamException;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.ConcurrentArrayQueue;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class HttpTransportOverSPDY implements HttpTransport
-{
-    private static final Logger LOG = Log.getLogger(HttpTransportOverSPDY.class);
-
-    private final Connector connector;
-    private final HttpConfiguration configuration;
-    private final EndPoint endPoint;
-    private final PushStrategy pushStrategy;
-    private final Stream stream;
-    private final short version;
-    private final Fields requestHeaders;
-    private final AtomicBoolean committed = new AtomicBoolean();
-
-    public HttpTransportOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint, PushStrategy pushStrategy, Stream stream, Fields requestHeaders)
-    {
-        this.connector = connector;
-        this.configuration = configuration;
-        this.endPoint = endPoint;
-        this.pushStrategy = pushStrategy == null ? new PushStrategy.None() : pushStrategy;
-        this.stream = stream;
-        this.requestHeaders = requestHeaders;
-        Session session = stream.getSession();
-        this.version = session.getVersion();
-    }
-
-    protected Stream getStream()
-    {
-        return stream;
-    }
-
-    protected Fields getRequestHeaders()
-    {
-        return requestHeaders;
-    }
-
-
-    @Override
-    public void send(ByteBuffer responseBodyContent, boolean lastContent, Callback callback)
-    {
-        // TODO can this be more efficient?
-        send(null, responseBodyContent, lastContent, callback);
-    }
-
-    @Override
-    public void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, final Callback callback)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("Sending {} {} {} {} last={}", this, stream, info, BufferUtil.toDetailString(content), lastContent);
-
-        if (stream.isClosed() || stream.isReset())
-        {
-            EofException exception = new EofException("stream closed");
-            callback.failed(exception);
-            return;
-        }
-
-        // info==null content==null lastContent==false          should not happen
-        // info==null content==null lastContent==true           signals no more content - complete
-        // info==null content!=null lastContent==false          send data on committed response
-        // info==null content!=null lastContent==true           send last data on committed response - complete
-        // info!=null content==null lastContent==false          reply, commit
-        // info!=null content==null lastContent==true           reply, commit and complete
-        // info!=null content!=null lastContent==false          reply, commit with content
-        // info!=null content!=null lastContent==true           reply, commit with content and complete
-
-        boolean isHeadRequest = HttpMethod.HEAD.name().equalsIgnoreCase(requestHeaders.get(HTTPSPDYHeader.METHOD.name(version)).getValue());
-        boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest;
-        boolean close = !hasContent && lastContent;
-
-        if (info != null)
-        {
-            if (!committed.compareAndSet(false, true))
-            {
-                StreamException exception = new StreamException(stream.getId(), StreamStatus.PROTOCOL_ERROR,
-                        "Stream already committed!");
-                callback.failed(exception);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Committed response twice.", exception);
-                return;
-            }
-            sendReply(info, !hasContent ? callback : new Callback.Adapter()
-            {
-                @Override
-                public void failed(Throwable x)
-                {
-                    callback.failed(x);
-                }
-            }, close);
-        }
-
-        // Do we have some content to send as well
-        if (hasContent)
-        {
-            // send the data and let it call the callback
-            if (LOG.isDebugEnabled())
-                LOG.debug("Send content: {} on stream: {} lastContent={}", BufferUtil.toDetailString(content), stream,
-                    lastContent);
-            stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS, content, lastContent
-            ), callback);
-        }
-        // else do we need to close
-        else if (lastContent && info == null)
-        {
-            // send empty data to close and let the send call the callback
-            if (LOG.isDebugEnabled())
-                LOG.debug("No content and lastContent=true. Sending empty ByteBuffer to close stream: {}", stream);
-            stream.data(new ByteBufferDataInfo(endPoint.getIdleTimeout(), TimeUnit.MILLISECONDS,
-                    BufferUtil.EMPTY_BUFFER, lastContent), callback);
-        }
-        else if (!lastContent && !hasContent && info == null)
-            throw new IllegalStateException("not lastContent, no content and no responseInfo!");
-
-    }
-
-    private void sendReply(HttpGenerator.ResponseInfo info, Callback callback, boolean close)
-    {
-        Fields headers = new Fields();
-
-        HttpVersion httpVersion = HttpVersion.HTTP_1_1;
-        headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString());
-
-        int status = info.getStatus();
-        StringBuilder httpStatus = new StringBuilder().append(status);
-        String reason = info.getReason();
-        if (reason == null)
-            reason = HttpStatus.getMessage(status);
-        if (reason != null)
-            httpStatus.append(" ").append(reason);
-        headers.put(HTTPSPDYHeader.STATUS.name(version), httpStatus.toString());
-        if (LOG.isDebugEnabled())
-            LOG.debug("HTTP < {} {}", httpVersion, httpStatus);
-
-        // TODO merge the two Field classes into one
-        HttpFields fields = info.getHttpFields();
-        if (fields != null)
-        {
-            for (int i = 0; i < fields.size(); ++i)
-            {
-                HttpField field = fields.getField(i);
-                String name = field.getName();
-                String value = field.getValue();
-                headers.add(name, value);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("HTTP < {}: {}", name, value);
-            }
-        }
-
-        if (configuration.getSendServerVersion())
-            headers.add(HttpHeader.SERVER.asString(), HttpConfiguration.SERVER_VERSION);
-        if (configuration.getSendXPoweredBy())
-            headers.add(HttpHeader.X_POWERED_BY.asString(), HttpConfiguration.SERVER_VERSION);
-
-        ReplyInfo reply = new ReplyInfo(headers, close);
-        if (LOG.isDebugEnabled())
-            LOG.debug("Sending reply: {} on stream: {}", reply, stream);
-        reply(stream, reply, callback);
-    }
-
-    @Override
-    public void completed()
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("Completed {}", this);
-    }
-
-    private void reply(Stream stream, ReplyInfo replyInfo, Callback callback)
-    {
-        if (!stream.isUnidirectional())
-            stream.reply(replyInfo, callback);
-        else
-            stream.headers(new HeadersInfo(replyInfo.getHeaders(), replyInfo.isClose()), callback);
-
-        Fields responseHeaders = replyInfo.getHeaders();
-        if (responseHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().startsWith("200") && !stream.isClosed())
-        {
-            Set<String> pushResources = pushStrategy.apply(stream, requestHeaders, responseHeaders);
-            if (pushResources.size() > 0)
-            {
-                PushResourceCoordinator pushResourceCoordinator = new PushResourceCoordinator(pushResources);
-                pushResourceCoordinator.coordinate();
-            }
-        }
-    }
-
-    private static class PushHttpTransportOverSPDY extends HttpTransportOverSPDY
-    {
-        private final PushResourceCoordinator coordinator;
-        private final short version;
-
-        private PushHttpTransportOverSPDY(Connector connector, HttpConfiguration configuration, EndPoint endPoint,
-                                          PushStrategy pushStrategy, Stream stream, Fields requestHeaders,
-                                          PushResourceCoordinator coordinator, short version)
-        {
-            super(connector, configuration, endPoint, pushStrategy, stream, requestHeaders);
-            this.coordinator = coordinator;
-            this.version = version;
-        }
-
-        @Override
-        public void completed()
-        {
-            Stream stream = getStream();
-            if (LOG.isDebugEnabled())
-                LOG.debug("Resource pushed for {} on {}",
-                    getRequestHeaders().get(HTTPSPDYHeader.URI.name(version)), stream);
-            coordinator.complete();
-        }
-    }
-
-    private class PushResourceCoordinator
-    {
-        private final Queue<PushResource> queue = new ConcurrentArrayQueue<>();
-        private final Set<String> resources;
-        private AtomicBoolean active = new AtomicBoolean(false);
-
-        private PushResourceCoordinator(Set<String> resources)
-        {
-            this.resources = resources;
-        }
-
-        private void coordinate()
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Pushing resources: {}", resources);
-            // Must send all push frames to the client at once before we
-            // return from this method and send the main resource data
-            for (String pushResource : resources)
-                pushResource(pushResource);
-        }
-
-        private void sendNextResourceData()
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("{} sendNextResourceData active: {}", hashCode(), active.get());
-            if (active.compareAndSet(false, true))
-            {
-                PushResource resource = queue.poll();
-                if (resource != null)
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Opening new push channel for: {}", resource);
-                    HttpChannelOverSPDY pushChannel = newHttpChannelOverSPDY(resource.getPushStream(), resource.getPushRequestHeaders());
-                    pushChannel.requestStart(resource.getPushRequestHeaders(), true);
-                    return;
-                }
-
-                if (active.compareAndSet(true, false))
-                {
-                    if (queue.peek() != null)
-                        sendNextResourceData();
-                }
-                else
-                {
-                    throw new IllegalStateException("active must not be false here! Concurrency bug!");
-                }
-            }
-        }
-
-        private HttpChannelOverSPDY newHttpChannelOverSPDY(Stream pushStream, Fields pushRequestHeaders)
-        {
-            HttpTransport transport = new PushHttpTransportOverSPDY(connector, configuration, endPoint, pushStrategy,
-                    pushStream, pushRequestHeaders, this, version);
-            HttpInputOverSPDY input = new HttpInputOverSPDY();
-            return new HttpChannelOverSPDY(connector, configuration, endPoint, transport, input, pushStream);
-        }
-
-        private void pushResource(String pushResource)
-        {
-            Fields.Field scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version));
-            Fields.Field host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version));
-            Fields.Field uri = requestHeaders.get(HTTPSPDYHeader.URI.name(version));
-            final Fields pushHeaders = createPushHeaders(scheme, host, pushResource);
-            final Fields pushRequestHeaders = createRequestHeaders(scheme, host, uri, pushResource);
-
-            stream.push(new PushInfo(pushHeaders, false), new Promise<Stream>()
-            {
-                @Override
-                public void succeeded(Stream pushStream)
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Headers pushed for {} on {}", pushHeaders.get(HTTPSPDYHeader.URI.name(version)), pushStream);
-                    queue.offer(new PushResource(pushStream, pushRequestHeaders));
-                    sendNextResourceData();
-                }
-
-                @Override
-                public void failed(Throwable x)
-                {
-                    LOG.debug("Creating push stream failed.", x);
-                    sendNextResourceData();
-                }
-            });
-        }
-
-        private void complete()
-        {
-            if (!active.compareAndSet(true, false))
-                throw new IllegalStateException();
-            sendNextResourceData();
-        }
-
-        private Fields createRequestHeaders(Fields.Field scheme, Fields.Field host, Fields.Field uri, String pushResourcePath)
-        {
-            final Fields newRequestHeaders = new Fields(requestHeaders, false);
-            newRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-            newRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-            newRequestHeaders.put(scheme);
-            newRequestHeaders.put(host);
-            newRequestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
-            String referrer = scheme.getValue() + "://" + host.getValue() + uri.getValue();
-            newRequestHeaders.put("referer", referrer);
-            newRequestHeaders.put("x-spdy-push", "true");
-            return newRequestHeaders;
-        }
-
-        private Fields createPushHeaders(Fields.Field scheme, Fields.Field host, String pushResourcePath)
-        {
-            final Fields pushHeaders = new Fields();
-            if (version == SPDY.V2)
-                pushHeaders.put(HTTPSPDYHeader.URI.name(version), scheme.getValue() + "://" + host.getValue() + pushResourcePath);
-            else
-            {
-                pushHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
-                pushHeaders.put(scheme);
-                pushHeaders.put(host);
-            }
-            return pushHeaders;
-        }
-    }
-
-    private static class PushResource
-    {
-        private final Stream pushStream;
-        private final Fields pushRequestHeaders;
-
-        public PushResource(Stream pushStream, Fields pushRequestHeaders)
-        {
-            this.pushStream = pushStream;
-            this.pushRequestHeaders = pushRequestHeaders;
-        }
-
-        public Stream getPushStream()
-        {
-            return pushStream;
-        }
-
-        public Fields getPushRequestHeaders()
-        {
-            return pushRequestHeaders;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "PushResource{" +
-                    "pushStream=" + pushStream +
-                    ", pushRequestHeaders=" + pushRequestHeaders +
-                    '}';
-        }
-    }
-
-    @Override
-    public void abort()
-    {
-        // TODO close the stream in a way to indicate an incomplete response?
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java
deleted file mode 100644
index 2c553c9..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/PushStrategy.java
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.util.Collections;
-import java.util.Set;
-
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>{@link PushStrategy} encapsulates the decisions about performing
- * SPDY pushes of secondary resources associated with a primary resource.</p>
- */
-public interface PushStrategy
-{
-    /**
-     * <p>Applies the SPDY push logic for the primary resource.</p>
-     *
-     * @param stream the primary resource stream
-     * @param requestHeaders the primary resource request headers
-     * @param responseHeaders the primary resource response headers
-     * @return a list of secondary resource URIs to push
-     */
-    public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders);
-
-    /**
-     * An implementation that returns an empty list of secondary resources
-     */
-    public static class None implements PushStrategy
-    {
-        @Override
-        public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders)
-        {
-            return Collections.emptySet();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
deleted file mode 100644
index f2beb38..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategy.java
+++ /dev/null
@@ -1,342 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>A SPDY push strategy that auto-populates push metadata based on referrer URLs.<p>A typical request for a main
- * resource such as {@code index.html} is immediately followed by a number of requests for associated resources.
- * Associated resource requests will have a {@code Referer} HTTP header that points to {@code index.html}, which is used
- * to link the associated resource to the main resource.<p>However, also following a hyperlink generates a HTTP request
- * with a {@code Referer} HTTP header that points to {@code index.html}; therefore a proper value for {@link
- * #setReferrerPushPeriod(int)} has to be set. If the referrerPushPeriod for a main resource has elapsed, no more
- * associated resources will be added for that main resource.<p>This class distinguishes associated main resources by
- * their URL path suffix and content type. CSS stylesheets, images and JavaScript files have recognizable URL path
- * suffixes that are classified as associated resources. The suffix regexs can be configured by constructor argument</p>
- * <p>When CSS stylesheets refer to images, the CSS image request will have the CSS stylesheet as referrer. This
- * implementation will push also the CSS image.<p>The push metadata built by this implementation is limited by the
- * number of pages of the application itself, and by the {@link #setMaxAssociatedResources(int)} max associated
- * resources} parameter. This parameter limits the number of associated resources per each main resource, so that if a
- * main resource has hundreds of associated resources, only up to the number specified by this parameter will be
- * pushed.
- */
-public class ReferrerPushStrategy implements PushStrategy
-{
-    private static final Logger LOG = Log.getLogger(ReferrerPushStrategy.class);
-    private final ConcurrentMap<String, MainResource> mainResources = new ConcurrentHashMap<>();
-    private final Set<Pattern> pushRegexps = new HashSet<>();
-    private final Set<String> pushContentTypes = new HashSet<>();
-    private final Set<Pattern> allowedPushOrigins = new HashSet<>();
-    private final Set<Pattern> userAgentBlacklist = new HashSet<>();
-    private volatile int maxAssociatedResources = 32;
-    private volatile int referrerPushPeriod = 5000;
-
-    public ReferrerPushStrategy()
-    {
-        List<String> defaultPushRegexps = Arrays.asList(".*\\.css", ".*\\.js", ".*\\.png", ".*\\.jpeg", ".*\\.jpg",
-                ".*\\.gif", ".*\\.ico");
-        addPushRegexps(defaultPushRegexps);
-
-        List<String> defaultPushContentTypes = Arrays.asList(
-                "text/css",
-                "text/javascript", "application/javascript", "application/x-javascript",
-                "image/png", "image/x-png",
-                "image/jpeg",
-                "image/gif",
-                "image/x-icon", "image/vnd.microsoft.icon");
-        this.pushContentTypes.addAll(defaultPushContentTypes);
-    }
-
-    public void setPushRegexps(List<String> pushRegexps)
-    {
-        pushRegexps.clear();
-        addPushRegexps(pushRegexps);
-    }
-
-    private void addPushRegexps(List<String> pushRegexps)
-    {
-        for (String pushRegexp : pushRegexps)
-            this.pushRegexps.add(Pattern.compile(pushRegexp));
-    }
-
-    public void setPushContentTypes(List<String> pushContentTypes)
-    {
-        pushContentTypes.clear();
-        pushContentTypes.addAll(pushContentTypes);
-    }
-
-    public void setAllowedPushOrigins(List<String> allowedPushOrigins)
-    {
-        allowedPushOrigins.clear();
-        for (String allowedPushOrigin : allowedPushOrigins)
-            this.allowedPushOrigins.add(Pattern.compile(allowedPushOrigin.replace(".", "\\.").replace("*", ".*")));
-    }
-
-    public void setUserAgentBlacklist(List<String> userAgentPatterns)
-    {
-        userAgentBlacklist.clear();
-        for (String userAgentPattern : userAgentPatterns)
-            userAgentBlacklist.add(Pattern.compile(userAgentPattern));
-    }
-
-    public void setMaxAssociatedResources(int maxAssociatedResources)
-    {
-        this.maxAssociatedResources = maxAssociatedResources;
-    }
-
-    public void setReferrerPushPeriod(int referrerPushPeriod)
-    {
-        this.referrerPushPeriod = referrerPushPeriod;
-    }
-
-    public Set<Pattern> getPushRegexps()
-    {
-        return pushRegexps;
-    }
-
-    public Set<String> getPushContentTypes()
-    {
-        return pushContentTypes;
-    }
-
-    public Set<Pattern> getAllowedPushOrigins()
-    {
-        return allowedPushOrigins;
-    }
-
-    public Set<Pattern> getUserAgentBlacklist()
-    {
-        return userAgentBlacklist;
-    }
-
-    public int getMaxAssociatedResources()
-    {
-        return maxAssociatedResources;
-    }
-
-    public int getReferrerPushPeriod()
-    {
-        return referrerPushPeriod;
-    }
-
-    @Override
-    public Set<String> apply(Stream stream, Fields requestHeaders, Fields responseHeaders)
-    {
-        Set<String> result = Collections.<String>emptySet();
-        short version = stream.getSession().getVersion();
-        if (!isIfModifiedSinceHeaderPresent(requestHeaders) && isValidMethod(requestHeaders.get(HTTPSPDYHeader.METHOD
-                .name(version)).getValue()) && !isUserAgentBlacklisted(requestHeaders))
-        {
-            String scheme = requestHeaders.get(HTTPSPDYHeader.SCHEME.name(version)).getValue();
-            String host = requestHeaders.get(HTTPSPDYHeader.HOST.name(version)).getValue();
-            String origin = scheme + "://" + host;
-            String url = requestHeaders.get(HTTPSPDYHeader.URI.name(version)).getValue();
-            String absoluteURL = origin + url;
-            if (LOG.isDebugEnabled())
-                LOG.debug("Applying push strategy for {}", absoluteURL);
-            if (isMainResource(url, responseHeaders))
-            {
-                MainResource mainResource = getOrCreateMainResource(absoluteURL);
-                result = mainResource.getResources();
-            }
-            else if (isPushResource(url, responseHeaders))
-            {
-                Fields.Field referrerHeader = requestHeaders.get("referer");
-                if (referrerHeader != null)
-                {
-                    String referrer = referrerHeader.getValue();
-                    MainResource mainResource = mainResources.get(referrer);
-                    if (mainResource == null)
-                        mainResource = getOrCreateMainResource(referrer);
-
-                    Set<String> pushResources = mainResource.getResources();
-                    if (!pushResources.contains(url))
-                        mainResource.addResource(url, origin, referrer);
-                    else
-                        result = getPushResources(absoluteURL);
-                }
-            }
-            if (LOG.isDebugEnabled())
-                LOG.debug("Pushing {} resources for {}: {}", result.size(), absoluteURL, result);
-        }
-        return result;
-    }
-
-    private Set<String> getPushResources(String absoluteURL)
-    {
-        Set<String> result = Collections.emptySet();
-        if (mainResources.get(absoluteURL) != null)
-            result = mainResources.get(absoluteURL).getResources();
-        return result;
-    }
-
-    private MainResource getOrCreateMainResource(String absoluteURL)
-    {
-        MainResource mainResource = mainResources.get(absoluteURL);
-        if (mainResource == null)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Creating new main resource for {}", absoluteURL);
-            MainResource value = new MainResource(absoluteURL);
-            mainResource = mainResources.putIfAbsent(absoluteURL, value);
-            if (mainResource == null)
-                mainResource = value;
-        }
-        return mainResource;
-    }
-
-    private boolean isIfModifiedSinceHeaderPresent(Fields headers)
-    {
-        return headers.get("if-modified-since") != null;
-    }
-
-    private boolean isValidMethod(String method)
-    {
-        return "GET".equalsIgnoreCase(method);
-    }
-
-    private boolean isMainResource(String url, Fields responseHeaders)
-    {
-        return !isPushResource(url, responseHeaders);
-    }
-
-    public boolean isUserAgentBlacklisted(Fields headers)
-    {
-        Fields.Field userAgentHeader = headers.get("user-agent");
-        if (userAgentHeader != null)
-            for (Pattern userAgentPattern : userAgentBlacklist)
-                if (userAgentPattern.matcher(userAgentHeader.getValue()).matches())
-                    return true;
-        return false;
-    }
-
-    private boolean isPushResource(String url, Fields responseHeaders)
-    {
-        for (Pattern pushRegexp : pushRegexps)
-        {
-            if (pushRegexp.matcher(url).matches())
-            {
-                Fields.Field header = responseHeaders.get("content-type");
-                if (header == null)
-                    return true;
-
-                String contentType = header.getValue().toLowerCase(Locale.ENGLISH);
-                for (String pushContentType : pushContentTypes)
-                    if (contentType.startsWith(pushContentType))
-                        return true;
-            }
-        }
-        return false;
-    }
-
-    private class MainResource
-    {
-        private final String name;
-        private final CopyOnWriteArraySet<String> resources = new CopyOnWriteArraySet<>();
-        private final AtomicLong firstResourceAdded = new AtomicLong(-1);
-
-        private MainResource(String name)
-        {
-            this.name = name;
-        }
-
-        public boolean addResource(String url, String origin, String referrer)
-        {
-            // We start the push period here and not when initializing the main resource, because a browser with a
-            // prefilled cache won't request the subresources. If the browser with warmed up cache now hits the main
-            // resource after a server restart, the push period shouldn't start until the first subresource is
-            // being requested.
-            firstResourceAdded.compareAndSet(-1, System.nanoTime());
-
-            long delay = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - firstResourceAdded.get());
-            if (!referrer.startsWith(origin) && !isPushOriginAllowed(origin))
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Skipped store of push metadata {} for {}: Origin: {} doesn't match or origin not allowed",
-                        url, name, origin);
-                return false;
-            }
-
-            // This check is not strictly concurrent-safe, but limiting
-            // the number of associated resources is achieved anyway
-            // although in rare cases few more resources will be stored
-            if (resources.size() >= maxAssociatedResources)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Skipped store of push metadata {} for {}: max associated resources ({}) reached",
-                        url, name, maxAssociatedResources);
-                return false;
-            }
-            if (delay > referrerPushPeriod)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Delay: {}ms longer than referrerPushPeriod ({}ms). Not adding resource: {} for: {}",
-                        delay, referrerPushPeriod, url, name);
-                return false;
-            }
-
-            if (LOG.isDebugEnabled())
-                LOG.debug("Adding: {} to: {} with delay: {}ms.", url, this, delay);
-            resources.add(url);
-            return true;
-        }
-
-        public Set<String> getResources()
-        {
-            return Collections.unmodifiableSet(resources);
-        }
-
-        public String toString()
-        {
-            return String.format("%s@%x{name=%s,resources=%s}",
-                    getClass().getSimpleName(),
-                    hashCode(),
-                    name,
-                    resources
-            );
-        }
-
-        private boolean isPushOriginAllowed(String origin)
-        {
-            for (Pattern allowedPushOrigin : allowedPushOrigins)
-                if (allowedPushOrigin.matcher(origin).matches())
-                    return true;
-            return false;
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java
deleted file mode 100644
index 5906f22..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPProxyEngine.java
+++ /dev/null
@@ -1,276 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.util.DeferredContentProvider;
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.HttpCookieStore;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>{@link HTTPProxyEngine} implements a SPDY to HTTP proxy, that is, converts SPDY events received by clients into
- * HTTP events for the servers.</p>
- */
-public class HTTPProxyEngine extends ProxyEngine
-{
-    private static final Logger LOG = Log.getLogger(HTTPProxyEngine.class);
-    private static final Callback LOGGING_CALLBACK = new LoggingCallback();
-
-    private final HttpClient httpClient;
-
-    public HTTPProxyEngine(HttpClient httpClient)
-    {
-        this.httpClient = httpClient;
-        configureHttpClient(httpClient);
-    }
-
-    private void configureHttpClient(HttpClient httpClient)
-    {
-        // Redirects must be proxied as is, not followed
-        httpClient.setFollowRedirects(false);
-        // Must not store cookies, otherwise cookies of different clients will mix
-        httpClient.setCookieStore(new HttpCookieStore.Empty());
-    }
-
-    public StreamFrameListener proxy(final Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo)
-    {
-        short version = clientStream.getSession().getVersion();
-        String method = clientSynInfo.getHeaders().get(HTTPSPDYHeader.METHOD.name(version)).getValue();
-        String path = clientSynInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue();
-
-        Fields headers = new Fields(clientSynInfo.getHeaders(), false);
-
-        removeHopHeaders(headers);
-        addRequestProxyHeaders(clientStream, headers);
-        customizeRequestHeaders(clientStream, headers);
-
-        String host = proxyServerInfo.getHost();
-        int port = proxyServerInfo.getAddress().getPort();
-
-        if (LOG.isDebugEnabled())
-            LOG.debug("Sending HTTP request to: {}", host + ":" + port);
-        final Request request = httpClient.newRequest(host, port)
-                .path(path)
-                .method(HttpMethod.fromString(method));
-        addNonSpdyHeadersToRequest(version, headers, request);
-
-        if (!clientSynInfo.isClose())
-        {
-            request.content(new DeferredContentProvider());
-        }
-
-        sendRequest(clientStream, request);
-
-        return new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                // We proxy to HTTP so we do not receive replies
-                throw new UnsupportedOperationException("Not Yet Implemented");
-            }
-
-            @Override
-            public void onHeaders(Stream stream, HeadersInfo headersInfo)
-            {
-                throw new UnsupportedOperationException("Not Yet Implemented");
-            }
-
-            @Override
-            public void onData(Stream clientStream, final DataInfo clientDataInfo)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("received clientDataInfo: {} for stream: {}", clientDataInfo, clientStream);
-
-                DeferredContentProvider contentProvider = (DeferredContentProvider)request.getContent();
-                contentProvider.offer(clientDataInfo.asByteBuffer(true));
-
-                if (clientDataInfo.isClose())
-                    contentProvider.close();
-            }
-        };
-    }
-
-    private void sendRequest(final Stream clientStream, Request request)
-    {
-        request.send(new Response.Listener.Adapter()
-        {
-            private volatile boolean committed;
-
-            @Override
-            public void onHeaders(final Response response)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("onHeaders called with response: {}. Sending replyInfo to client.", response);
-                Fields responseHeaders = createResponseHeaders(clientStream, response);
-                removeHopHeaders(responseHeaders);
-                ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
-                clientStream.reply(replyInfo, new Callback.Adapter()
-                {
-                    @Override
-                    public void failed(Throwable x)
-                    {
-                        LOG.debug("failed: ", x);
-                        response.abort(x);
-                    }
-
-                    @Override
-                    public void succeeded()
-                    {
-                        committed = true;
-                    }
-                });
-            }
-
-            @Override
-            public void onContent(final Response response, ByteBuffer content)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("onContent called with response: {} and content: {}. Sending response content to client.",
-                        response, content);
-                final ByteBuffer contentCopy = httpClient.getByteBufferPool().acquire(content.remaining(), true);
-                BufferUtil.flipPutFlip(content, contentCopy);
-                ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(contentCopy, false);
-                clientStream.data(dataInfo, new Callback()
-                {
-                    @Override
-                    public void failed(Throwable x)
-                    {
-                        LOG.debug("failed: ", x);
-                        releaseBuffer();
-                        response.abort(x);
-                    }
-
-                    @Override
-                    public void succeeded()
-                    {
-                        releaseBuffer();
-                    }
-
-                    private void releaseBuffer()
-                    {
-                        httpClient.getByteBufferPool().release(contentCopy);
-                    }
-                });
-            }
-
-            @Override
-            public void onSuccess(Response response)
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("onSuccess called. Closing client stream.");
-                clientStream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true), LOGGING_CALLBACK);
-            }
-
-            @Override
-            public void onFailure(Response response, Throwable failure)
-            {
-                LOG.debug("onFailure called: ", failure);
-                if (committed)
-                {
-                    LOG.debug("clientStream already committed. Resetting stream.");
-                    try
-                    {
-                        clientStream.getSession().rst(new RstInfo(clientStream.getId(), StreamStatus.INTERNAL_ERROR));
-                    }
-                    catch (InterruptedException | ExecutionException | TimeoutException e)
-                    {
-                        LOG.debug(e);
-                    }
-                }
-                else
-                {
-                    if (clientStream.isClosed())
-                        return;
-                    Fields responseHeaders = createResponseHeaders(clientStream, response);
-                    if (failure instanceof TimeoutException)
-                        responseHeaders.add(HTTPSPDYHeader.STATUS.name(clientStream.getSession().getVersion()),
-                                String.valueOf(HttpStatus.GATEWAY_TIMEOUT_504));
-                    else
-                        responseHeaders.add(HTTPSPDYHeader.STATUS.name(clientStream.getSession().getVersion()),
-                                String.valueOf(HttpStatus.BAD_GATEWAY_502));
-                    ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true);
-                    clientStream.reply(replyInfo, LOGGING_CALLBACK);
-                }
-            }
-        });
-    }
-
-    private Fields createResponseHeaders(Stream clientStream, Response response)
-    {
-        Fields responseHeaders = new Fields();
-        for (HttpField header : response.getHeaders())
-            responseHeaders.add(header.getName(), header.getValue());
-            short version = clientStream.getSession().getVersion();
-        if (response.getStatus() > 0)
-            responseHeaders.add(HTTPSPDYHeader.STATUS.name(version),
-                    String.valueOf(response.getStatus()));
-        responseHeaders.add(HTTPSPDYHeader.VERSION.name(version), HttpVersion.HTTP_1_1.asString());
-        addResponseProxyHeaders(clientStream, responseHeaders);
-        return responseHeaders;
-    }
-
-    private void addNonSpdyHeadersToRequest(short version, Fields headers, Request request)
-    {
-        for (Fields.Field header : headers)
-            if (HTTPSPDYHeader.from(version, header.getName()) == null)
-                request.header(header.getName(), header.getValue());
-    }
-
-    static class LoggingCallback extends Callback.Adapter
-    {
-        @Override
-        public void failed(Throwable x)
-        {
-            LOG.debug(x);
-        }
-
-        @Override
-        public void succeeded()
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("succeeded");
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java
deleted file mode 100644
index c29b0e8..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.util.Objects;
-
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class HTTPSPDYProxyServerConnector extends ServerConnector
-{
-    public HTTPSPDYProxyServerConnector(Server server, ProxyEngineSelector proxyEngineSelector)
-    {
-        this(server, new HttpConfiguration(), proxyEngineSelector);
-    }
-
-    public HTTPSPDYProxyServerConnector(Server server, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector)
-    {
-        super(server, (SslContextFactory)null, new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector));
-    }
-
-    public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, ProxyEngineSelector proxyEngineSelector)
-    {
-        this(server, sslContextFactory, new HttpConfiguration(), proxyEngineSelector);
-    }
-
-    public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector)
-    {
-        this(server, sslContextFactory, config, proxyEngineSelector, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"));
-    }
-
-    public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector, NegotiatingServerConnectionFactory negotiatingFactory)
-    {
-        super(server, Objects.requireNonNull(sslContextFactory), negotiatingFactory,
-                new SPDYServerConnectionFactory(SPDY.V3, proxyEngineSelector),
-                new SPDYServerConnectionFactory(SPDY.V2, proxyEngineSelector),
-                new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector));
-        negotiatingFactory.setDefaultProtocol("http/1.1");
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java
deleted file mode 100644
index ffa968f..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngine.java
+++ /dev/null
@@ -1,129 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-
-/**
- * <p>{@link ProxyEngine} is the class for SPDY proxy functionalities that receives a SPDY request and converts it to
- * any protocol to its server side.</p>
- * <p>This class listens for SPDY events sent by clients; subclasses are responsible for translating
- * these SPDY client events into appropriate events to forward to the server, in the appropriate
- * protocol that is understood by the server.</p>
- */
-public abstract class ProxyEngine
-{
-    private static final Set<String> HOP_HEADERS = new HashSet<>();
-    static
-    {
-        HOP_HEADERS.add("proxy-connection");
-        HOP_HEADERS.add("connection");
-        HOP_HEADERS.add("keep-alive");
-        HOP_HEADERS.add("transfer-encoding");
-        HOP_HEADERS.add("te");
-        HOP_HEADERS.add("trailer");
-        HOP_HEADERS.add("proxy-authorization");
-        HOP_HEADERS.add("proxy-authenticate");
-        HOP_HEADERS.add("upgrade");
-    }
-
-    private final String name;
-
-    protected ProxyEngine()
-    {
-        this(name());
-    }
-
-    private static String name()
-    {
-        try
-        {
-            return InetAddress.getLocalHost().getHostName();
-        }
-        catch (UnknownHostException x)
-        {
-            return "localhost";
-        }
-    }
-
-    public abstract StreamFrameListener proxy(Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo);
-
-    protected ProxyEngine(String name)
-    {
-        this.name = name;
-    }
-
-    public String getName()
-    {
-        return name;
-    }
-
-    protected void removeHopHeaders(Fields headers)
-    {
-        // Header names are case-insensitive (RFC2616) and oej.util.Fields.add converts the names to lowercase. So we
-        // need to compare with the lowercase values only
-        for (String hopHeader : HOP_HEADERS)
-            headers.remove(hopHeader);
-    }
-
-    protected void addRequestProxyHeaders(Stream stream, Fields headers)
-    {
-        addViaHeader(headers);
-        Fields.Field schemeField = headers.get(HTTPSPDYHeader.SCHEME.name(stream.getSession().getVersion()));
-        if(schemeField != null)
-            headers.add("X-Forwarded-Proto", schemeField.getValue());
-        InetSocketAddress address = stream.getSession().getRemoteAddress();
-        if (address != null)
-        {
-            headers.add("X-Forwarded-Host", address.getHostName());
-            headers.add("X-Forwarded-For", address.toString());
-        }
-        headers.add("X-Forwarded-Server", name());
-    }
-
-    protected void addResponseProxyHeaders(Stream stream, Fields headers)
-    {
-        addViaHeader(headers);
-    }
-
-    private void addViaHeader(Fields headers)
-    {
-        headers.add("Via", "http/1.1 " + getName());
-    }
-
-    protected void customizeRequestHeaders(Stream stream, Fields headers)
-    {
-    }
-
-    protected void customizeResponseHeaders(Stream stream, Fields headers)
-    {
-    }
-
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java
deleted file mode 100644
index 176122a..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyEngineSelector.java
+++ /dev/null
@@ -1,203 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.net.InetSocketAddress;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.PingResultInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>{@link ProxyEngineSelector} is the main entry point for push stream events of a jetty SPDY proxy. It receives the
- * push stream frames from the clients, checks if there's an appropriate {@link ProxyServerInfo} for the given target
- * host and forwards the push to a {@link ProxyEngine} for the protocol defined in {@link ProxyServerInfo}.</p>
- *
- * <p>If no {@link ProxyServerInfo} can be found for the given target host or no {@link ProxyEngine} can be found for
- * the given protocol, it resets the client stream.</p>
- *
- * <p>This class also provides configuration for the proxy rules.</p>
- */
-public class ProxyEngineSelector extends ServerSessionFrameListener.Adapter
-{
-    protected final Logger LOG = Log.getLogger(getClass());
-    private final Map<String, ProxyServerInfo> proxyInfos = new ConcurrentHashMap<>();
-    private final Map<String, ProxyEngine> proxyEngines = new ConcurrentHashMap<>();
-
-    @Override
-    public final StreamFrameListener onSyn(final Stream clientStream, SynInfo clientSynInfo)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("C -> P {} on {}", clientSynInfo, clientStream);
-
-        final Session clientSession = clientStream.getSession();
-        short clientVersion = clientSession.getVersion();
-        Fields headers = new Fields(clientSynInfo.getHeaders(), false);
-
-        Fields.Field hostHeader = headers.get(HTTPSPDYHeader.HOST.name(clientVersion));
-        if (hostHeader == null)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("No host header found: " + headers);
-            rst(clientStream);
-            return null;
-        }
-
-        String host = hostHeader.getValue();
-        int colon = host.indexOf(':');
-        if (colon >= 0)
-            host = host.substring(0, colon);
-
-        ProxyServerInfo proxyServerInfo = getProxyServerInfo(host);
-        if (proxyServerInfo == null)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("No matching ProxyServerInfo found for: " + host);
-            rst(clientStream);
-            return null;
-        }
-
-        String protocol = proxyServerInfo.getProtocol();
-        ProxyEngine proxyEngine = proxyEngines.get(protocol);
-        if (proxyEngine == null)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("No matching ProxyEngine found for: " + protocol);
-            rst(clientStream);
-            return null;
-        }
-        if (LOG.isDebugEnabled())
-            LOG.debug("Forwarding request: {} -> {}", clientSynInfo, proxyServerInfo);
-        return proxyEngine.proxy(clientStream, clientSynInfo, proxyServerInfo);
-    }
-
-    @Override
-    public void onPing(Session clientSession, PingResultInfo pingResultInfo)
-    {
-        // We do not know to which upstream server
-        // to send the PING so we just ignore it
-    }
-
-    @Override
-    public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo)
-    {
-        // TODO:
-    }
-
-    public Map<String, ProxyEngine> getProxyEngines()
-    {
-        return new HashMap<>(proxyEngines);
-    }
-
-    public void setProxyEngines(Map<String, ProxyEngine> proxyEngines)
-    {
-        this.proxyEngines.clear();
-        this.proxyEngines.putAll(proxyEngines);
-    }
-
-    public ProxyEngine getProxyEngine(String protocol)
-    {
-        return proxyEngines.get(protocol);
-    }
-
-    public void putProxyEngine(String protocol, ProxyEngine proxyEngine)
-    {
-        proxyEngines.put(protocol, proxyEngine);
-    }
-
-    public Map<String, ProxyServerInfo> getProxyServerInfos()
-    {
-        return new HashMap<>(proxyInfos);
-    }
-
-    protected ProxyServerInfo getProxyServerInfo(String host)
-    {
-        return proxyInfos.get(host);
-    }
-
-    public void setProxyServerInfos(Map<String, ProxyServerInfo> proxyServerInfos)
-    {
-        this.proxyInfos.clear();
-        this.proxyInfos.putAll(proxyServerInfos);
-    }
-
-    public void putProxyServerInfo(String host, ProxyServerInfo proxyServerInfo)
-    {
-        proxyInfos.put(host, proxyServerInfo);
-    }
-
-    private void rst(Stream stream)
-    {
-        RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM);
-        stream.getSession().rst(rstInfo, Callback.Adapter.INSTANCE);
-    }
-
-    public static class ProxyServerInfo
-    {
-        private final String protocol;
-        private final String host;
-        private final InetSocketAddress address;
-
-        public ProxyServerInfo(String protocol, String host, int port)
-        {
-            this.protocol = protocol;
-            this.host = host;
-            this.address = new InetSocketAddress(host, port);
-        }
-
-        public String getProtocol()
-        {
-            return protocol;
-        }
-
-        public String getHost()
-        {
-            return host;
-        }
-
-        public InetSocketAddress getAddress()
-        {
-            return address;
-        }
-
-        @Override
-        public String toString()
-        {
-            return "ProxyServerInfo{" +
-                    "protocol='" + protocol + '\'' +
-                    ", host='" + host + '\'' +
-                    ", address=" + address +
-                    '}';
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java
deleted file mode 100644
index e64b1d9..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPConnectionFactory.java
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-
-public class ProxyHTTPConnectionFactory extends AbstractConnectionFactory implements HttpConfiguration.ConnectionFactory
-{
-    private final short version;
-    private final ProxyEngineSelector proxyEngineSelector;
-    private final HttpConfiguration httpConfiguration;
-
-    public ProxyHTTPConnectionFactory(HttpConfiguration httpConfiguration,short version, ProxyEngineSelector proxyEngineSelector)
-    {
-        // replaces http/1.1
-        super(HttpVersion.HTTP_1_1.asString());
-        this.version = version;
-        this.proxyEngineSelector = proxyEngineSelector;
-        this.httpConfiguration=httpConfiguration;
-    }
-
-    @Override
-    public Connection newConnection(Connector connector, EndPoint endPoint)
-    {
-        return configure(new ProxyHTTPSPDYConnection(connector, httpConfiguration, endPoint, version, proxyEngineSelector),connector,endPoint);
-    }
-
-    @Override
-    public HttpConfiguration getHttpConfiguration()
-    {
-        return httpConfiguration;
-    }
-
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
deleted file mode 100644
index 040068c..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPSPDYConnection.java
+++ /dev/null
@@ -1,385 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.nio.ByteBuffer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.http.HttpField;
-import org.eclipse.jetty.http.HttpFields;
-import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpHeaderValue;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpParser;
-import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnection;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.spdy.ISession;
-import org.eclipse.jetty.spdy.IStream;
-import org.eclipse.jetty.spdy.StandardSession;
-import org.eclipse.jetty.spdy.StandardStream;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-
-public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParser.RequestHandler<ByteBuffer>
-{
-    private final short version;
-    private final Fields headers = new Fields();
-    private final ProxyEngineSelector proxyEngineSelector;
-    private final ISession session;
-    private HTTPStream stream;
-    private ByteBuffer content;
-
-    public ProxyHTTPSPDYConnection(Connector connector, HttpConfiguration config, EndPoint endPoint, short version, ProxyEngineSelector proxyEngineSelector)
-    {
-        super(config, connector, endPoint);
-        this.version = version;
-        this.proxyEngineSelector = proxyEngineSelector;
-        this.session = new HTTPSession(version, connector);
-    }
-
-    @Override
-    protected HttpParser.RequestHandler<ByteBuffer> newRequestHandler()
-    {
-        return this;
-    }
-
-    @Override
-    public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion httpVersion)
-    {
-        Connector connector = getConnector();
-        String scheme = connector.getConnectionFactory(SslConnectionFactory.class) != null ? "https" : "http";
-        headers.put(HTTPSPDYHeader.SCHEME.name(version), scheme);
-        headers.put(HTTPSPDYHeader.METHOD.name(version), methodString);
-        headers.put(HTTPSPDYHeader.URI.name(version), BufferUtil.toUTF8String(uri)); // TODO handle bad encodings
-        headers.put(HTTPSPDYHeader.VERSION.name(version), httpVersion.asString());
-        return false;
-    }
-
-    @Override
-    public boolean parsedHeader(HttpField field)
-    {
-        if (field.getHeader() == HttpHeader.HOST)
-            headers.put(HTTPSPDYHeader.HOST.name(version), field.getValue());
-        else
-            headers.put(field.getName(), field.getValue());
-        return false;
-    }
-
-    @Override
-    public boolean parsedHostHeader(String host, int port)
-    {
-        return false;
-    }
-
-    @Override
-    public boolean headerComplete()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean content(ByteBuffer item)
-    {
-        if (content == null)
-        {
-            stream = syn(false);
-            content = item;
-        }
-        else
-        {
-            stream.getStreamFrameListener().onData(stream, toDataInfo(item, false));
-        }
-        return false;
-    }
-
-    @Override
-    public boolean messageComplete()
-    {
-        if (stream == null)
-        {
-            assert content == null;
-            if (headers.isEmpty())
-                proxyEngineSelector.onGoAway(session, new GoAwayResultInfo(0, SessionStatus.OK));
-            else
-                syn(true);
-        }
-        else
-        {
-            stream.getStreamFrameListener().onData(stream, toDataInfo(content, true));
-        }
-        return false;
-    }
-
-    @Override
-    public void completed()
-    {
-        headers.clear();
-        stream = null;
-        content = null;
-        super.completed();
-    }
-
-    @Override
-    public int getHeaderCacheSize()
-    {
-        // TODO get from configuration
-        return 256;
-    }
-
-    @Override
-    public void earlyEOF()
-    {
-        // TODO
-    }
-
-    @Override
-    public void badMessage(int status, String reason)
-    {
-        // TODO
-    }
-
-    private HTTPStream syn(boolean close)
-    {
-        HTTPStream stream = new HTTPStream(1, (byte)0, session, null);
-        StreamFrameListener streamFrameListener = proxyEngineSelector.onSyn(stream, new SynInfo(headers, close));
-        stream.setStreamFrameListener(streamFrameListener);
-        return stream;
-    }
-
-    private DataInfo toDataInfo(ByteBuffer buffer, boolean close)
-    {
-        return new ByteBufferDataInfo(buffer, close);
-    }
-
-    private class HTTPSession extends StandardSession
-    {
-        private HTTPSession(short version, Connector connector)
-        {
-            super(version, connector.getByteBufferPool(), connector.getScheduler(), null,
-                    getEndPoint(), null, 1, proxyEngineSelector, null, null);
-        }
-
-        @Override
-        public void rst(RstInfo rstInfo, Callback handler)
-        {
-            HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(HttpVersion.fromString(headers.get
-                    ("version").getValue()), null, 0, 502, "SPDY reset received from upstream server", false);
-            send(info, null, true, Callback.Adapter.INSTANCE);
-        }
-
-        @Override
-        public void goAway(GoAwayInfo goAwayInfo, Callback handler)
-        {
-            ProxyHTTPSPDYConnection.this.close();
-            handler.succeeded();
-        }
-    }
-
-    /**
-     * <p>This stream will convert the SPDY invocations performed by the proxy into HTTP to be sent to the client.</p>
-     */
-    private class HTTPStream extends StandardStream
-    {
-        private final Pattern statusRegexp = Pattern.compile("(\\d{3})\\s+(.*)");
-
-        private HTTPStream(int id, byte priority, ISession session, IStream associatedStream)
-        {
-            super(id, priority, session, associatedStream, getHttpChannel().getScheduler(), null);
-        }
-
-        @Override
-        public void push(PushInfo pushInfo, Promise<Stream> handler)
-        {
-            // HTTP does not support pushed streams
-            handler.succeeded(new HTTPPushStream(2, getPriority(), getSession(), this));
-        }
-
-        @Override
-        public void headers(HeadersInfo headersInfo, Callback handler)
-        {
-            // TODO
-            throw new UnsupportedOperationException("Not Yet Implemented");
-        }
-
-        @Override
-        public void reply(ReplyInfo replyInfo, final Callback handler)
-        {
-            Fields headers = new Fields(replyInfo.getHeaders(), false);
-
-                addPersistenceHeader(headers);
-
-            headers.remove(HTTPSPDYHeader.SCHEME.name(version));
-
-            String status = headers.remove(HTTPSPDYHeader.STATUS.name(version)).getValue();
-            Matcher matcher = statusRegexp.matcher(status);
-            matcher.matches();
-            int code = Integer.parseInt(matcher.group(1));
-            String reason = matcher.group(2).trim();
-
-            HttpVersion httpVersion = HttpVersion.fromString(headers.remove(HTTPSPDYHeader.VERSION.name(version)).getValue());
-
-            // Convert the Host header from a SPDY special header to a normal header
-            Fields.Field host = headers.remove(HTTPSPDYHeader.HOST.name(version));
-            if (host != null)
-                headers.put("host", host.getValue());
-
-            HttpFields fields = new HttpFields();
-            for (Fields.Field header : headers)
-            {
-                String name = camelize(header.getName());
-                fields.put(name, header.getValue());
-            }
-
-            // TODO: handle better the HEAD last parameter
-            long contentLength = fields.getLongField(HttpHeader.CONTENT_LENGTH.asString());
-            HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(httpVersion, fields, contentLength, code,
-                    reason, false);
-
-            send(info, null, replyInfo.isClose(), new Adapter()
-            {
-                @Override
-                public void failed(Throwable x)
-                {
-                    handler.failed(x);
-                }
-            });
-
-            if (replyInfo.isClose())
-                completed();
-
-            handler.succeeded();
-        }
-
-        private String camelize(String name)
-        {
-            char[] chars = name.toCharArray();
-            chars[0] = Character.toUpperCase(chars[0]);
-
-            for (int i = 0; i < chars.length; ++i)
-            {
-                char c = chars[i];
-                int j = i + 1;
-                if (c == '-' && j < chars.length)
-                    chars[j] = Character.toUpperCase(chars[j]);
-            }
-            return new String(chars);
-        }
-
-        @Override
-        public void data(DataInfo dataInfo, final Callback handler)
-        {
-            // Data buffer must be copied, as the ByteBuffer is pooled
-            ByteBuffer byteBuffer = dataInfo.asByteBuffer(false);
-
-            send(null, byteBuffer, dataInfo.isClose(), new Adapter()
-            {
-                @Override
-                public void failed(Throwable x)
-                {
-                    handler.failed(x);
-                }
-            });
-
-            if (dataInfo.isClose())
-                completed();
-
-            handler.succeeded();
-        }
-    }
-
-    private void addPersistenceHeader(Fields headersToAddTo)
-    {
-        HttpVersion httpVersion = HttpVersion.fromString(headers.get("version").getValue());
-        boolean persistent = false;
-        switch (httpVersion)
-        {
-            case HTTP_1_0:
-            {
-                Fields.Field keepAliveHeader = headers.get(HttpHeader.KEEP_ALIVE.asString());
-                if(keepAliveHeader!=null)
-                    persistent = HttpHeaderValue.KEEP_ALIVE.asString().equals(keepAliveHeader.getValue());
-                if (!persistent)
-                    persistent = HttpMethod.CONNECT.is(headers.get("method").getValue());
-                if (persistent)
-                    headersToAddTo.add(HttpHeader.CONNECTION.asString(), HttpHeaderValue.KEEP_ALIVE.asString());
-                break;
-            }
-            case HTTP_1_1:
-            {
-                Fields.Field connectionHeader = headers.get(HttpHeader.CONNECTION.asString());
-                if(connectionHeader != null)
-                    persistent = !HttpHeaderValue.CLOSE.asString().equals(connectionHeader.getValue());
-                else
-                    persistent = true;
-                if (!persistent)
-                    persistent = HttpMethod.CONNECT.is(headers.get("method").getValue());
-                if (!persistent)
-                    headersToAddTo.add(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString());
-                break;
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    private class HTTPPushStream extends StandardStream
-    {
-        private HTTPPushStream(int id, byte priority, ISession session, IStream associatedStream)
-        {
-            super(id, priority, session, associatedStream, getHttpChannel().getScheduler(), null);
-        }
-
-        @Override
-        public void headers(HeadersInfo headersInfo, Callback handler)
-        {
-            // Ignore pushed headers
-            handler.succeeded();
-        }
-
-        @Override
-        public void data(DataInfo dataInfo, Callback handler)
-        {
-            // Ignore pushed data
-            handler.succeeded();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java
deleted file mode 100644
index 349672a..0000000
--- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/SPDYProxyEngine.java
+++ /dev/null
@@ -1,631 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.net.InetSocketAddress;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.Info;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-/**
- * <p>{@link SPDYProxyEngine} implements a SPDY to SPDY proxy, that is, converts SPDY events received by clients into
- * SPDY events for the servers.</p>
- */
-public class SPDYProxyEngine extends ProxyEngine implements StreamFrameListener
-{
-    private static final Logger LOG = Log.getLogger(SPDYProxyEngine.class);
-
-    private static final String STREAM_PROMISE_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.proxy.streamPromise";
-    private static final String CLIENT_STREAM_ATTRIBUTE = "org.eclipse.jetty.spdy.server.http.proxy.clientStream";
-
-    private final ConcurrentMap<String, Session> serverSessions = new ConcurrentHashMap<>();
-    private final SessionFrameListener sessionListener = new ProxySessionFrameListener();
-    private final SPDYClient.Factory factory;
-    private volatile long connectTimeout = 15000;
-    private volatile long timeout = 60000;
-
-    public SPDYProxyEngine(SPDYClient.Factory factory)
-    {
-        this.factory = factory;
-    }
-
-    public long getConnectTimeout()
-    {
-        return connectTimeout;
-    }
-
-    public void setConnectTimeout(long connectTimeout)
-    {
-        this.connectTimeout = connectTimeout;
-    }
-
-    public long getTimeout()
-    {
-        return timeout;
-    }
-
-    public void setTimeout(long timeout)
-    {
-        this.timeout = timeout;
-    }
-
-    public StreamFrameListener proxy(final Stream clientStream, SynInfo clientSynInfo, ProxyEngineSelector.ProxyServerInfo proxyServerInfo)
-    {
-        Fields headers = new Fields(clientSynInfo.getHeaders(), false);
-
-        short serverVersion = getVersion(proxyServerInfo.getProtocol());
-        InetSocketAddress address = proxyServerInfo.getAddress();
-        Session serverSession = produceSession(proxyServerInfo.getHost(), serverVersion, address);
-        if (serverSession == null)
-        {
-            rst(clientStream);
-            return null;
-        }
-
-        final Session clientSession = clientStream.getSession();
-
-        addRequestProxyHeaders(clientStream, headers);
-        customizeRequestHeaders(clientStream, headers);
-        convert(clientSession.getVersion(), serverVersion, headers);
-
-        SynInfo serverSynInfo = new SynInfo(headers, clientSynInfo.isClose());
-        StreamFrameListener listener = new ProxyStreamFrameListener(clientStream);
-        StreamPromise promise = new StreamPromise(clientStream, serverSynInfo);
-        clientStream.setAttribute(STREAM_PROMISE_ATTRIBUTE, promise);
-        serverSession.syn(serverSynInfo, listener, promise);
-        return this;
-    }
-
-    private static short getVersion(String protocol)
-    {
-        switch (protocol)
-        {
-            case "spdy/2":
-                return SPDY.V2;
-            case "spdy/3":
-                return SPDY.V3;
-            default:
-                throw new IllegalArgumentException("Procotol: " + protocol + " is not a known SPDY protocol");
-        }
-    }
-
-    @Override
-    public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-    {
-        throw new IllegalStateException("We shouldn't receive pushes from clients");
-    }
-
-    @Override
-    public void onReply(Stream stream, ReplyInfo replyInfo)
-    {
-        throw new IllegalStateException("Servers do not receive replies");
-    }
-
-    @Override
-    public void onHeaders(Stream stream, HeadersInfo headersInfo)
-    {
-        // TODO
-        throw new UnsupportedOperationException("Not Yet Implemented");
-    }
-
-    @Override
-    public void onData(Stream clientStream, final DataInfo clientDataInfo)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("C -> P {} on {}", clientDataInfo, clientStream);
-
-        ByteBufferDataInfo serverDataInfo = new ByteBufferDataInfo(clientDataInfo.asByteBuffer(false), clientDataInfo.isClose())
-        {
-            @Override
-            public void consume(int delta)
-            {
-                super.consume(delta);
-                clientDataInfo.consume(delta);
-            }
-        };
-
-        StreamPromise streamPromise = (StreamPromise)clientStream.getAttribute(STREAM_PROMISE_ATTRIBUTE);
-        streamPromise.data(serverDataInfo);
-    }
-
-    @Override
-    public void onFailure(Stream stream, Throwable x)
-    {
-        LOG.debug(x);
-    }
-
-    private Session produceSession(String host, short version, InetSocketAddress address)
-    {
-        try
-        {
-            Session session = serverSessions.get(host);
-            if (session == null)
-            {
-                SPDYClient client = factory.newSPDYClient(version);
-                session = client.connect(address, sessionListener);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Proxy session connected to {}", address);
-                Session existing = serverSessions.putIfAbsent(host, session);
-                if (existing != null)
-                {
-                    session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
-                    session = existing;
-                }
-            }
-            return session;
-        }
-        catch (Exception x)
-        {
-            LOG.debug(x);
-            return null;
-        }
-    }
-
-    private void convert(short fromVersion, short toVersion, Fields headers)
-    {
-        if (fromVersion != toVersion)
-        {
-            for (HTTPSPDYHeader httpHeader : HTTPSPDYHeader.values())
-            {
-                Fields.Field header = headers.remove(httpHeader.name(fromVersion));
-                if (header != null)
-                {
-                    String toName = httpHeader.name(toVersion);
-                    for (String value : header.getValues())
-                        headers.add(toName, value);
-                }
-            }
-        }
-    }
-
-    private void rst(Stream stream)
-    {
-        RstInfo rstInfo = new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM);
-        stream.getSession().rst(rstInfo, Callback.Adapter.INSTANCE);
-    }
-
-    private class ProxyPushStreamFrameListener implements StreamFrameListener
-    {
-        private PushStreamPromise pushStreamPromise;
-
-        private ProxyPushStreamFrameListener(PushStreamPromise pushStreamPromise)
-        {
-            this.pushStreamPromise = pushStreamPromise;
-        }
-
-        @Override
-        public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("S -> P pushed {} on {}. Opening new PushStream P -> C now.", pushInfo, stream);
-            PushStreamPromise newPushStreamPromise = new PushStreamPromise(stream, pushInfo);
-            this.pushStreamPromise.push(newPushStreamPromise);
-            return new ProxyPushStreamFrameListener(newPushStreamPromise);
-        }
-
-        @Override
-        public void onReply(Stream stream, ReplyInfo replyInfo)
-        {
-            // Push streams never send a reply
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void onHeaders(Stream stream, HeadersInfo headersInfo)
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void onData(Stream serverStream, final DataInfo serverDataInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("S -> P pushed {} on {}", serverDataInfo, serverStream);
-
-            ByteBufferDataInfo clientDataInfo = new ByteBufferDataInfo(serverDataInfo.asByteBuffer(false), serverDataInfo.isClose())
-            {
-                @Override
-                public void consume(int delta)
-                {
-                    super.consume(delta);
-                    serverDataInfo.consume(delta);
-                }
-            };
-
-            pushStreamPromise.data(clientDataInfo);
-        }
-
-        @Override
-        public void onFailure(Stream stream, Throwable x)
-        {
-            LOG.debug(x);
-        }
-    }
-
-    private class ProxyStreamFrameListener extends StreamFrameListener.Adapter
-    {
-        private final Stream receiverStream;
-
-        public ProxyStreamFrameListener(Stream receiverStream)
-        {
-            this.receiverStream = receiverStream;
-        }
-
-        @Override
-        public StreamFrameListener onPush(Stream senderStream, PushInfo pushInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("S -> P {} on {}");
-            PushInfo newPushInfo = convertPushInfo(pushInfo, senderStream, receiverStream);
-            PushStreamPromise pushStreamPromise = new PushStreamPromise(senderStream, newPushInfo);
-            receiverStream.push(newPushInfo, pushStreamPromise);
-            return new ProxyPushStreamFrameListener(pushStreamPromise);
-        }
-
-        @Override
-        public void onReply(final Stream stream, ReplyInfo replyInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("S -> P {} on {}", replyInfo, stream);
-            final ReplyInfo clientReplyInfo = new ReplyInfo(convertHeaders(stream, receiverStream, replyInfo.getHeaders()),
-                    replyInfo.isClose());
-            reply(stream, clientReplyInfo);
-        }
-
-        private void reply(final Stream stream, final ReplyInfo clientReplyInfo)
-        {
-            receiverStream.reply(clientReplyInfo, new Callback()
-            {
-                @Override
-                public void succeeded()
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("P -> C {} from {} to {}", clientReplyInfo, stream, receiverStream);
-                }
-
-                @Override
-                public void failed(Throwable x)
-                {
-                    LOG.debug(x);
-                    rst(receiverStream);
-                }
-            });
-        }
-
-        @Override
-        public void onHeaders(Stream stream, HeadersInfo headersInfo)
-        {
-            // TODO
-            throw new UnsupportedOperationException("Not Yet Implemented");
-        }
-
-        @Override
-        public void onData(final Stream stream, final DataInfo dataInfo)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("S -> P {} on {}", dataInfo, stream);
-            data(stream, dataInfo);
-        }
-
-        private void data(final Stream stream, final DataInfo serverDataInfo)
-        {
-            final ByteBufferDataInfo clientDataInfo = new ByteBufferDataInfo(serverDataInfo.asByteBuffer(false), serverDataInfo.isClose())
-            {
-                @Override
-                public void consume(int delta)
-                {
-                    super.consume(delta);
-                    serverDataInfo.consume(delta);
-                }
-            };
-
-            receiverStream.data(clientDataInfo, new Callback() //TODO: timeout???
-            {
-                @Override
-                public void succeeded()
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("P -> C {} from {} to {}", clientDataInfo, stream, receiverStream);
-                }
-
-                @Override
-                public void failed(Throwable x)
-                {
-                    LOG.debug(x);
-                    rst(receiverStream);
-                }
-            });
-        }
-    }
-
-    /**
-     * <p>{@link StreamPromise} implements the forwarding of DATA frames from the client to the server and vice
-     * versa.</p> <p>Instances of this class buffer DATA frames sent by clients and send them to the server. The
-     * buffering happens between the send of the SYN_STREAM to the server (where DATA frames may arrive from the client
-     * before the SYN_STREAM has been fully sent), and between DATA frames, if the client is a fast producer and the
-     * server a slow consumer, or if the client is a SPDY v2 client (and hence without flow control) while the server is
-     * a SPDY v3 server (and hence with flow control).</p>
-     */
-    private class StreamPromise implements Promise<Stream>
-    {
-        private final Queue<DataInfoCallback> queue = new LinkedList<>();
-        private final Stream senderStream;
-        private final Info info;
-        private Stream receiverStream;
-
-        private StreamPromise(Stream senderStream, Info info)
-        {
-            this.senderStream = senderStream;
-            this.info = info;
-        }
-
-        @Override
-        public void succeeded(Stream stream)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("P -> S {} from {} to {}", info, senderStream, stream);
-
-            stream.setAttribute(CLIENT_STREAM_ATTRIBUTE, senderStream);
-
-            DataInfoCallback dataInfoCallback;
-            synchronized (queue)
-            {
-                this.receiverStream = stream;
-                dataInfoCallback = queue.peek();
-                if (dataInfoCallback != null)
-                {
-                    if (dataInfoCallback.flushing)
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("SYN completed, flushing {}, queue size {}", dataInfoCallback.dataInfo, queue.size());
-                        dataInfoCallback = null;
-                    }
-                    else
-                    {
-                        dataInfoCallback.flushing = true;
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("SYN completed, queue size {}", queue.size());
-                    }
-                }
-                else
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("SYN completed, queue empty");
-                }
-            }
-            if (dataInfoCallback != null)
-                flush(stream, dataInfoCallback);
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-            LOG.debug(x);
-            rst(senderStream);
-        }
-
-        public void data(DataInfo dataInfo)
-        {
-            Stream receiverStream;
-            DataInfoCallback dataInfoCallbackToFlush = null;
-            DataInfoCallback dataInfoCallBackToQueue = new DataInfoCallback(dataInfo);
-            synchronized (queue)
-            {
-                queue.offer(dataInfoCallBackToQueue);
-                receiverStream = this.receiverStream;
-                if (receiverStream != null)
-                {
-                    dataInfoCallbackToFlush = queue.peek();
-                    if (dataInfoCallbackToFlush.flushing)
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Queued {}, flushing {}, queue size {}", dataInfo, dataInfoCallbackToFlush.dataInfo, queue.size());
-                        receiverStream = null;
-                    }
-                    else
-                    {
-                        dataInfoCallbackToFlush.flushing = true;
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Queued {}, queue size {}", dataInfo, queue.size());
-                    }
-                }
-                else
-                {
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Queued {}, SYN incomplete, queue size {}", dataInfo, queue.size());
-                }
-            }
-            if (receiverStream != null)
-                flush(receiverStream, dataInfoCallbackToFlush);
-        }
-
-        private void flush(Stream receiverStream, DataInfoCallback dataInfoCallback)
-        {
-            if (LOG.isDebugEnabled())
-                LOG.debug("P -> S {} on {}", dataInfoCallback.dataInfo, receiverStream);
-            receiverStream.data(dataInfoCallback.dataInfo, dataInfoCallback); //TODO: timeout???
-        }
-
-        private class DataInfoCallback implements Callback
-        {
-            private final DataInfo dataInfo;
-            private boolean flushing;
-
-            private DataInfoCallback(DataInfo dataInfo)
-            {
-                this.dataInfo = dataInfo;
-            }
-
-            @Override
-            public void succeeded()
-            {
-                Stream serverStream;
-                DataInfoCallback dataInfoCallback;
-                synchronized (queue)
-                {
-                    serverStream = StreamPromise.this.receiverStream;
-                    assert serverStream != null;
-                    dataInfoCallback = queue.poll();
-                    assert dataInfoCallback == this;
-                    dataInfoCallback = queue.peek();
-                    if (dataInfoCallback != null)
-                    {
-                        assert !dataInfoCallback.flushing;
-                        dataInfoCallback.flushing = true;
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Completed {}, queue size {}", dataInfo, queue.size());
-                    }
-                    else
-                    {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Completed {}, queue empty", dataInfo);
-                    }
-                }
-                if (dataInfoCallback != null)
-                    flush(serverStream, dataInfoCallback);
-            }
-
-            @Override
-            public void failed(Throwable x)
-            {
-                LOG.debug(x);
-                rst(senderStream);
-            }
-        }
-
-        public Stream getSenderStream()
-        {
-            return senderStream;
-        }
-
-        public Info getInfo()
-        {
-            return info;
-        }
-
-        public Stream getReceiverStream()
-        {
-            synchronized (queue)
-            {
-                return receiverStream;
-            }
-        }
-    }
-
-    private class PushStreamPromise extends StreamPromise
-    {
-        private volatile PushStreamPromise pushStreamPromise;
-
-        private PushStreamPromise(Stream senderStream, PushInfo pushInfo)
-        {
-            super(senderStream, pushInfo);
-        }
-
-        @Override
-        public void succeeded(Stream receiverStream)
-        {
-            super.succeeded(receiverStream);
-
-            if (LOG.isDebugEnabled())
-                LOG.debug("P -> C PushStreamPromise.succeeded() called with pushStreamPromise: {}", pushStreamPromise);
-
-            PushStreamPromise promise = pushStreamPromise;
-            if (promise != null)
-                receiverStream.push(convertPushInfo((PushInfo)getInfo(), getSenderStream(), receiverStream), pushStreamPromise);
-        }
-
-        public void push(PushStreamPromise pushStreamPromise)
-        {
-            Stream receiverStream = getReceiverStream();
-
-            if (receiverStream != null)
-                receiverStream.push(convertPushInfo((PushInfo)getInfo(), getSenderStream(), receiverStream), pushStreamPromise);
-            else
-                this.pushStreamPromise = pushStreamPromise;
-        }
-    }
-
-    private class ProxySessionFrameListener extends SessionFrameListener.Adapter
-    {
-        @Override
-        public void onRst(Session serverSession, RstInfo serverRstInfo)
-        {
-            Stream serverStream = serverSession.getStream(serverRstInfo.getStreamId());
-            if (serverStream != null)
-            {
-                Stream clientStream = (Stream)serverStream.getAttribute(CLIENT_STREAM_ATTRIBUTE);
-                if (clientStream != null)
-                {
-                    Session clientSession = clientStream.getSession();
-                    RstInfo clientRstInfo = new RstInfo(clientStream.getId(), serverRstInfo.getStreamStatus());
-                    clientSession.rst(clientRstInfo, Callback.Adapter.INSTANCE);
-                }
-            }
-        }
-
-        @Override
-        public void onGoAway(Session serverSession, GoAwayResultInfo goAwayResultInfo)
-        {
-            serverSessions.values().remove(serverSession);
-        }
-    }
-
-    private PushInfo convertPushInfo(PushInfo pushInfo, Stream from, Stream to)
-    {
-        Fields headersToConvert = pushInfo.getHeaders();
-        Fields headers = convertHeaders(from, to, headersToConvert);
-        return new PushInfo(getTimeout(), TimeUnit.MILLISECONDS, headers, pushInfo.isClose());
-    }
-
-    private Fields convertHeaders(Stream from, Stream to, Fields headersToConvert)
-    {
-        Fields headers = new Fields(headersToConvert, false);
-        addResponseProxyHeaders(from, headers);
-        customizeResponseHeaders(from, headers);
-        convert(from.getSession().getVersion(), to.getSession().getVersion(), headers);
-        return headers;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java
deleted file mode 100644
index 200c8f0..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.net.InetSocketAddress;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public abstract class AbstractHTTPSPDYTest
-{
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestWatcher testName = new TestWatcher()
-    {
-
-        @Override
-        public void starting(Description description)
-        {
-            super.starting(description);
-            System.err.printf("Running %s.%s()%n",
-                    description.getClassName(),
-                    description.getMethodName());
-        }
-    };
-
-    protected final short version;
-    protected Server server;
-    protected SPDYClient.Factory clientFactory;
-    protected HTTPSPDYServerConnector connector;
-
-    protected AbstractHTTPSPDYTest(short version)
-    {
-        this.version = version;
-    }
-
-    protected InetSocketAddress startHTTPServer(short version, Handler handler, long idleTimeout) throws Exception
-    {
-        QueuedThreadPool threadPool = new QueuedThreadPool(256);
-        threadPool.setName("serverQTP");
-        server = new Server(threadPool);
-        connector = newHTTPSPDYServerConnector(version);
-        connector.setPort(0);
-        connector.setIdleTimeout(idleTimeout);
-        server.addConnector(connector);
-        server.setHandler(handler);
-        server.start();
-        return new InetSocketAddress("localhost", connector.getLocalPort());
-    }
-
-    protected Server getServer()
-    {
-        return server;
-    }
-
-    protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version)
-    {
-        // For these tests, we need the connector to speak HTTP over SPDY even in non-SSL
-        HttpConfiguration httpConfiguration = new HttpConfiguration();
-        httpConfiguration.setSendServerVersion(true);
-        httpConfiguration.setSendXPoweredBy(true);
-        return new HTTPSPDYServerConnector(server, version, httpConfiguration, new PushStrategy.None());
-    }
-
-    protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception
-    {
-        if (clientFactory == null)
-        {
-            QueuedThreadPool threadPool = new QueuedThreadPool();
-            threadPool.setName(threadPool.getName() + "-client");
-            clientFactory = newSPDYClientFactory(threadPool);
-            clientFactory.start();
-        }
-        return clientFactory.newSPDYClient(version).connect(socketAddress, listener);
-    }
-
-    protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool)
-    {
-        return new SPDYClient.Factory(threadPool, null, null, connector.getIdleTimeout());
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        ((StdErrLog)Log.getLogger(HTTPSPDYServerConnector.class)).setHideStacks(true);
-        if (clientFactory != null)
-        {
-            clientFactory.stop();
-        }
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-        ((StdErrLog)Log.getLogger(HTTPSPDYServerConnector.class)).setHideStacks(false);
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java
deleted file mode 100644
index b86517a..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ConcurrentStreamsTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ConcurrentStreamsTest extends AbstractHTTPSPDYTest
-{
-    public ConcurrentStreamsTest(short version)
-    {
-        super(version);
-    }
-
-    @Test
-    public void testSlowStreamDoesNotBlockOtherStreams() throws Exception
-    {
-        final CountDownLatch slowServerLatch = new CountDownLatch(1);
-        final CountDownLatch fastServerLatch = new CountDownLatch(1);
-        final String fastPath = "/fast";
-        final String slowPath = "/slow";
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                try
-                {
-                    request.setHandled(true);
-                    switch (target)
-                    {
-                        case slowPath:
-                            Assert.assertTrue(fastServerLatch.await(10, TimeUnit.SECONDS));
-                            slowServerLatch.countDown();
-                            break;
-                        case fastPath:
-                            fastServerLatch.countDown();
-                            break;
-                        default:
-                            Assert.fail();
-                            break;
-                    }
-                }
-                catch (InterruptedException x)
-                {
-                    throw new ServletException(x);
-                }
-            }
-        }, 30000), null);
-
-        // Perform slow request. This will wait on server side until the fast request wakes it up
-        Fields headers = createHeaders(slowPath);
-        final CountDownLatch slowClientLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                slowClientLatch.countDown();
-            }
-        });
-
-        // Perform the fast request. This will wake up the slow request
-        headers = createHeaders(fastPath);
-        final CountDownLatch fastClientLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                Assert.assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                fastClientLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(fastServerLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(slowServerLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(fastClientLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(slowClientLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    private Fields createHeaders(String path)
-    {
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-        headers.put(HTTPSPDYHeader.URI.name(version), path);
-        headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
-        return headers;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java
deleted file mode 100644
index 1656fd5..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/HttpTransportOverSPDYTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.http.HttpGenerator;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class HttpTransportOverSPDYTest
-{
-    @Mock
-    Connector connector;
-    @Mock
-    HttpConfiguration httpConfiguration;
-    @Mock
-    EndPoint endPoint;
-    @Mock
-    PushStrategy pushStrategy;
-    @Mock
-    Stream stream;
-    @Mock
-    Callback callback;
-    @Mock
-    Session session;
-    @Mock
-    HttpGenerator.ResponseInfo responseInfo;
-
-    Random random = new Random();
-    short version = SPDY.V3;
-
-    HttpTransportOverSPDY httpTransportOverSPDY;
-
-    @Before
-    public void setUp() throws Exception
-    {
-        Fields requestHeaders = new Fields();
-        requestHeaders.add(HTTPSPDYHeader.METHOD.name(version), "GET");
-        when(responseInfo.getStatus()).thenReturn(HttpStatus.OK_200);
-        when(stream.getSession()).thenReturn(session);
-        when(session.getVersion()).thenReturn(SPDY.V3);
-        when(stream.isClosed()).thenReturn(false);
-        httpTransportOverSPDY = new HttpTransportOverSPDY(connector, httpConfiguration, endPoint, pushStrategy,
-                stream, requestHeaders);
-    }
-
-    @Test
-    public void testSendWithResponseInfoNullAndContentNullAndLastContentTrue() throws Exception
-    {
-        ByteBuffer content = null;
-        boolean lastContent = true;
-
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        verify(callback, times(1)).succeeded();
-        assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
-        assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
-    }
-
-    @Test
-    public void testSendWithResponseInfoNullAndContentAndLastContentTrue() throws Exception
-    {
-        ByteBuffer content = createRandomByteBuffer();
-
-        boolean lastContent = true;
-
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        verify(callback, times(1)).succeeded();
-        assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
-        assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
-    }
-
-    @Test
-    public void testSendWithResponseInfoNullAndEmptyContentAndLastContentTrue() throws Exception
-    {
-        ByteBuffer content = BufferUtil.EMPTY_BUFFER;
-        boolean lastContent = true;
-
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        verify(callback, times(1)).succeeded();
-        assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
-        assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(0));
-    }
-
-    @Test
-    public void testSendWithResponseInfoNullAndContentAndLastContentFalse() throws Exception
-    {
-        ByteBuffer content = createRandomByteBuffer();
-        boolean lastContent = false;
-
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        verify(callback, times(1)).succeeded();
-        assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
-        assertThat("ByteBuffer is empty", dataInfoCaptor.getValue().length(), is(4096));
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testSendWithResponseInfoNullAndContentNullAndLastContentFalse() throws Exception
-    {
-        ByteBuffer content = null;
-        boolean lastContent = false;
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testSendWithResponseInfoNullAndEmptyContentAndLastContentFalse() throws Exception
-    {
-        ByteBuffer content = BufferUtil.EMPTY_BUFFER;
-        boolean lastContent = false;
-        httpTransportOverSPDY.send(null, content, lastContent, callback);
-    }
-
-    @Test
-    public void testSendWithResponseInfoAndContentNullAndLastContentFalse() throws Exception
-    {
-        ByteBuffer content = null;
-        boolean lastContent = false;
-
-        httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
-        ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(false));
-
-        verify(stream, times(0)).data(any(ByteBufferDataInfo.class), any(Callback.class));
-        verify(callback, times(1)).succeeded();
-    }
-
-    @Test
-    public void testSendWithResponseInfoAndContentNullAndLastContentTrue() throws Exception
-    {
-        ByteBuffer content = null;
-        boolean lastContent = true;
-
-        // when stream.isClosed() is called a 2nd time, the reply has closed the stream already
-        when(stream.isClosed()).thenReturn(false).thenReturn(true);
-
-        httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
-        ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("ReplyInfo close is true", replyInfoCaptor.getValue().isClose(), is(true));
-
-        verify(callback, times(1)).succeeded();
-    }
-
-    @Test
-    public void testSendWithResponseInfoAndContentAndLastContentTrue() throws Exception
-    {
-        ByteBuffer content = createRandomByteBuffer();
-        boolean lastContent = true;
-
-        httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
-        ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("lastContent is true", dataInfoCaptor.getValue().isClose(), is(true));
-        assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
-        verify(callback, times(1)).succeeded();
-    }
-
-    @Test
-    public void testSendWithResponseInfoAndContentAndLastContentFalse() throws Exception
-    {
-        ByteBuffer content = createRandomByteBuffer();
-        boolean lastContent = false;
-
-        httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
-        ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
-        ArgumentCaptor<Callback> callbackCaptor = ArgumentCaptor.forClass(Callback.class);
-        verify(stream, times(1)).reply(replyInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
-
-        ArgumentCaptor<ByteBufferDataInfo> dataInfoCaptor = ArgumentCaptor.forClass(ByteBufferDataInfo.class);
-        verify(stream, times(1)).data(dataInfoCaptor.capture(), callbackCaptor.capture());
-        callbackCaptor.getValue().succeeded();
-        assertThat("lastContent is false", dataInfoCaptor.getValue().isClose(), is(false));
-        assertThat("ByteBuffer length is 4096", dataInfoCaptor.getValue().length(), is(4096));
-
-        verify(callback, times(1)).succeeded();
-    }
-
-    @Test
-    public void testVerifyThatAStreamIsNotCommittedTwice() throws IOException, InterruptedException
-    {
-        final CountDownLatch failedCalledLatch = new CountDownLatch(1);
-        ByteBuffer content = createRandomByteBuffer();
-        boolean lastContent = false;
-
-        httpTransportOverSPDY.send(responseInfo, content, lastContent, callback);
-        ArgumentCaptor<ReplyInfo> replyInfoCaptor = ArgumentCaptor.forClass(ReplyInfo.class);
-        verify(stream, times(1)).reply(replyInfoCaptor.capture(), any(Callback.class));
-        assertThat("ReplyInfo close is false", replyInfoCaptor.getValue().isClose(), is(false));
-
-        httpTransportOverSPDY.send(HttpGenerator.RESPONSE_500_INFO, null, true, new Callback.Adapter()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failedCalledLatch.countDown();
-            }
-        });
-
-        verify(stream, times(1)).data(any(DataInfo.class), any(Callback.class));
-
-        assertThat("callback.failed has been called", failedCalledLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private ByteBuffer createRandomByteBuffer()
-    {
-        ByteBuffer content = BufferUtil.allocate(8192);
-        BufferUtil.flipToFill(content);
-        byte[] randomBytes = new byte[4096];
-        random.nextBytes(randomBytes);
-        content.put(randomBytes);
-        return content;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java
deleted file mode 100644
index 39dd32f..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/PushStrategyBenchmarkTest.java
+++ /dev/null
@@ -1,397 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Response;
-import org.eclipse.jetty.client.api.Result;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore("make this test pass") // TODO
-public class PushStrategyBenchmarkTest extends AbstractHTTPSPDYTest
-{
-    // Sample resources size from webtide.com home page
-    private final int[] htmlResources = new int[]
-            {8 * 1024};
-    private final int[] cssResources = new int[]
-            {12 * 1024, 2 * 1024};
-    private final int[] jsResources = new int[]
-            {75 * 1024, 24 * 1024, 36 * 1024};
-    private final int[] pngResources = new int[]
-            {1024, 45 * 1024, 6 * 1024, 2 * 1024, 2 * 1024, 2 * 1024, 3 * 1024, 512, 512, 19 * 1024, 512, 128, 32};
-    private final Set<String> pushedResources = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
-    private final AtomicReference<CountDownLatch> latch = new AtomicReference<>();
-    private final long roundtrip = 100;
-    private final int runs = 10;
-
-    public PushStrategyBenchmarkTest(short version)
-    {
-        super(version);
-    }
-
-    @Test
-    public void benchmarkPushStrategy() throws Exception
-    {
-        InetSocketAddress address = startHTTPServer(version, new PushStrategyBenchmarkHandler(), 30000);
-
-        // Plain HTTP
-        ConnectionFactory factory = new HttpConnectionFactory(new HttpConfiguration());
-        connector.setDefaultProtocol(factory.getProtocol());
-        HttpClient httpClient = new HttpClient();
-        // Simulate browsers, that open 6 connection per origin
-        httpClient.setMaxConnectionsPerDestination(6);
-        httpClient.start();
-        benchmarkHTTP(httpClient);
-        httpClient.stop();
-
-        // First push strategy
-        PushStrategy pushStrategy = new PushStrategy.None();
-        factory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy);
-        connector.setDefaultProtocol(factory.getProtocol());
-        Session session = startClient(version, address, new ClientSessionFrameListener());
-        benchmarkSPDY(pushStrategy, session);
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        // Second push strategy
-        pushStrategy = new ReferrerPushStrategy();
-        factory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy);
-        connector.setDefaultProtocol(factory.getProtocol());
-        session = startClient(version, address, new ClientSessionFrameListener());
-        benchmarkSPDY(pushStrategy, session);
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-
-    private void benchmarkHTTP(HttpClient httpClient) throws Exception
-    {
-        // Warm up
-        performHTTPRequests(httpClient);
-        performHTTPRequests(httpClient);
-
-        long total = 0;
-        for (int i = 0; i < runs; ++i)
-        {
-            long begin = System.nanoTime();
-            int requests = performHTTPRequests(httpClient);
-            long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - begin);
-            total += elapsed;
-            System.err.printf("HTTP: run %d, %d request(s), roundtrip delay %d ms, elapsed = %d%n",
-                    i, requests, roundtrip, elapsed);
-        }
-        System.err.printf("HTTP: roundtrip delay %d ms, average = %d%n%n",
-                roundtrip, total / runs);
-    }
-
-    private int performHTTPRequests(HttpClient httpClient) throws Exception
-    {
-        int result = 0;
-
-        for (int j = 0; j < htmlResources.length; ++j)
-        {
-            latch.set(new CountDownLatch(cssResources.length + jsResources.length + pngResources.length));
-
-            String primaryPath = "/" + j + ".html";
-            String referrer = "http://localhost:" + connector.getLocalPort() + primaryPath;
-            ++result;
-            ContentResponse response = httpClient.newRequest("localhost", connector.getLocalPort())
-                    .path(primaryPath)
-                    .timeout(5, TimeUnit.SECONDS)
-                    .send();
-            Assert.assertEquals(200, response.getStatus());
-
-            for (int i = 0; i < cssResources.length; ++i)
-            {
-                String path = "/" + i + ".css";
-                ++result;
-                httpClient.newRequest("localhost", connector.getLocalPort())
-                        .path(path)
-                        .header(HttpHeader.REFERER, referrer)
-                        .send(new TestListener());
-            }
-            for (int i = 0; i < jsResources.length; ++i)
-            {
-                String path = "/" + i + ".js";
-                ++result;
-                httpClient.newRequest("localhost", connector.getLocalPort())
-                        .path(path)
-                        .header(HttpHeader.REFERER, referrer)
-                        .send(new TestListener());
-            }
-            for (int i = 0; i < pngResources.length; ++i)
-            {
-                String path = "/" + i + ".png";
-                ++result;
-                httpClient.newRequest("localhost", connector.getLocalPort())
-                        .path(path)
-                        .header(HttpHeader.REFERER, referrer)
-                        .send(new TestListener());
-            }
-
-            Assert.assertTrue(latch.get().await(5, TimeUnit.SECONDS));
-        }
-
-        return result;
-    }
-
-    private void benchmarkSPDY(PushStrategy pushStrategy, Session session) throws Exception
-    {
-        // Warm up PushStrategy
-        performRequests(session);
-        performRequests(session);
-
-        long total = 0;
-        for (int i = 0; i < runs; ++i)
-        {
-            long begin = System.nanoTime();
-            int requests = performRequests(session);
-            long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - begin);
-            total += elapsed;
-            System.err.printf("SPDY(%s): run %d, %d request(s), roundtrip delay %d ms, elapsed = %d%n",
-                    pushStrategy.getClass().getSimpleName(), i, requests, roundtrip, elapsed);
-        }
-        System.err.printf("SPDY(%s): roundtrip delay %d ms, average = %d%n%n",
-                pushStrategy.getClass().getSimpleName(), roundtrip, total / runs);
-    }
-
-    private int performRequests(Session session) throws Exception
-    {
-        int result = 0;
-
-        for (int j = 0; j < htmlResources.length; ++j)
-        {
-            latch.set(new CountDownLatch(cssResources.length + jsResources.length + pngResources.length));
-            pushedResources.clear();
-
-            String primaryPath = "/" + j + ".html";
-            String referrer = "http://localhost:" + connector.getLocalPort() + primaryPath;
-            Fields headers = new Fields();
-            headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-            headers.put(HTTPSPDYHeader.URI.name(version), primaryPath);
-            headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-            headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
-            headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
-            // Wait for the HTML to simulate browser's behavior
-            ++result;
-            final CountDownLatch htmlLatch = new CountDownLatch(1);
-            session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-            {
-                @Override
-                public void onData(Stream stream, DataInfo dataInfo)
-                {
-                    dataInfo.consume(dataInfo.length());
-                    if (dataInfo.isClose())
-                        htmlLatch.countDown();
-                }
-            });
-            Assert.assertTrue(htmlLatch.await(5, TimeUnit.SECONDS));
-
-            for (int i = 0; i < cssResources.length; ++i)
-            {
-                String path = "/" + i + ".css";
-                if (pushedResources.contains(path))
-                    continue;
-                headers = createRequestHeaders(referrer, path);
-                ++result;
-                session.syn(new SynInfo(headers, true), new DataListener());
-            }
-            for (int i = 0; i < jsResources.length; ++i)
-            {
-                String path = "/" + i + ".js";
-                if (pushedResources.contains(path))
-                    continue;
-                headers = createRequestHeaders(referrer, path);
-                ++result;
-                session.syn(new SynInfo(headers, true), new DataListener());
-            }
-            for (int i = 0; i < pngResources.length; ++i)
-            {
-                String path = "/" + i + ".png";
-                if (pushedResources.contains(path))
-                    continue;
-                headers = createRequestHeaders(referrer, path);
-                ++result;
-                session.syn(new SynInfo(headers, true), new DataListener());
-            }
-
-            Assert.assertTrue(latch.get().await(5, TimeUnit.SECONDS));
-        }
-
-        return result;
-    }
-
-    private Fields createRequestHeaders(String referrer, String path)
-    {
-        Fields headers;
-        headers = new Fields();
-        headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-        headers.put(HTTPSPDYHeader.URI.name(version), path);
-        headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-        headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
-        headers.put("referer", referrer);
-        return headers;
-    }
-
-    private void sleep(long delay) throws ServletException
-    {
-        try
-        {
-            TimeUnit.MILLISECONDS.sleep(delay);
-        }
-        catch (InterruptedException x)
-        {
-            throw new ServletException(x);
-        }
-    }
-
-    private class PushStrategyBenchmarkHandler extends AbstractHandler
-    {
-        @Override
-        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-        {
-            baseRequest.setHandled(true);
-
-            // Sleep half of the roundtrip time, to simulate the delay of responses, even for pushed resources
-            sleep(roundtrip / 2);
-            // If it's not a pushed resource, sleep half of the roundtrip time, to simulate the delay of requests
-            if (request.getHeader("x-spdy-push") == null)
-                sleep(roundtrip / 2);
-
-            String suffix = target.substring(target.indexOf('.') + 1);
-            int index = Integer.parseInt(target.substring(1, target.length() - suffix.length() - 1));
-
-            int contentLength;
-            String contentType;
-            switch (suffix)
-            {
-                case "html":
-                    contentLength = htmlResources[index];
-                    contentType = "text/html";
-                    break;
-                case "css":
-                    contentLength = cssResources[index];
-                    contentType = "text/css";
-                    break;
-                case "js":
-                    contentLength = jsResources[index];
-                    contentType = "text/javascript";
-                    break;
-                case "png":
-                    contentLength = pngResources[index];
-                    contentType = "image/png";
-                    break;
-                default:
-                    throw new ServletException();
-            }
-
-            response.setContentType(contentType);
-            response.setContentLength(contentLength);
-            response.getOutputStream().write(new byte[contentLength]);
-        }
-    }
-
-    private void addPushedResource(String pushedURI)
-    {
-        switch (version)
-        {
-            case SPDY.V2:
-            {
-                Matcher matcher = Pattern.compile("https?://[^:]+:\\d+(/.*)").matcher(pushedURI);
-                Assert.assertTrue(matcher.matches());
-                pushedResources.add(matcher.group(1));
-                break;
-            }
-            case SPDY.V3:
-            {
-                pushedResources.add(pushedURI);
-                break;
-            }
-            default:
-            {
-                throw new IllegalStateException();
-            }
-        }
-    }
-
-    private class ClientSessionFrameListener extends SessionFrameListener.Adapter
-    {
-        @Override
-        public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-        {
-            String path = synInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue();
-            addPushedResource(path);
-            return new DataListener();
-        }
-    }
-
-    private class DataListener extends StreamFrameListener.Adapter
-    {
-        @Override
-        public void onData(Stream stream, DataInfo dataInfo)
-        {
-            dataInfo.consume(dataInfo.length());
-            if (dataInfo.isClose())
-                latch.get().countDown();
-        }
-    }
-
-    private class TestListener extends Response.Listener.Adapter
-    {
-        @Override
-        public void onComplete(Result result)
-        {
-            if (!result.isFailed())
-                latch.get().countDown();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
deleted file mode 100644
index 159e742..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
+++ /dev/null
@@ -1,1138 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.net.InetSocketAddress;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.servlets.gzip.GzipHandler;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.log.StdErrLog;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
-{
-    private static final Logger LOG = Log.getLogger(ReferrerPushStrategyTest.class);
-
-    private final int referrerPushPeriod = 1000;
-    private final String mainResource = "/index.html";
-    private final String cssResource = "/style.css";
-    private InetSocketAddress serverAddress;
-    private ReferrerPushStrategy pushStrategy;
-    private ConnectionFactory defaultFactory;
-    private Fields mainRequestHeaders;
-    private Fields associatedCSSRequestHeaders;
-    private Fields associatedJSRequestHeaders;
-
-    public ReferrerPushStrategyTest(short version)
-    {
-        super(version);
-    }
-
-    @Override
-    protected HTTPSPDYServerConnector newHTTPSPDYServerConnector(short version)
-    {
-        return new HTTPSPDYServerConnector(server, version, new HttpConfiguration(), new ReferrerPushStrategy());
-    }
-
-    @Before
-    public void setUp() throws Exception
-    {
-        serverAddress = createServer();
-        pushStrategy = new ReferrerPushStrategy();
-        pushStrategy.setReferrerPushPeriod(referrerPushPeriod);
-        defaultFactory = new HTTPSPDYServerConnectionFactory(version, new HttpConfiguration(), pushStrategy);
-        connector.addConnectionFactory(defaultFactory);
-        if (connector.getConnectionFactory(NPNServerConnectionFactory.class) != null)
-            connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(defaultFactory.getProtocol());
-        else
-            connector.setDefaultProtocol(defaultFactory.getProtocol());
-        mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
-        associatedCSSRequestHeaders = createHeaders(cssResource);
-        associatedJSRequestHeaders = createHeaders("/application.js");
-    }
-
-    @Test
-    public void testPushHeadersAreValid() throws Exception
-    {
-        sendMainRequestAndCSSRequest(null, false);
-        run2ndClientRequests(true, true);
-    }
-
-    @Test
-    public void testClientResetsPushStreams() throws Exception
-    {
-        ((StdErrLog)Log.getLogger("org.eclipse.jetty.server.HttpChannel")).setHideStacks(true);
-        sendMainRequestAndCSSRequest(null, false);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
-        Session session = startClient(version, serverAddress, null);
-        // Send main request. That should initiate the push push's which get reset by the client
-        sendRequest(session, mainRequestHeaders, pushSynHeadersValid, pushDataLatch, true);
-
-        assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
-        assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
-
-        sendRequest(session, associatedCSSRequestHeaders, pushSynHeadersValid, pushDataLatch, true);
-        ((StdErrLog)Log.getLogger("org.eclipse.jetty.server.HttpChannel")).setHideStacks(false);
-    }
-
-    @Test
-    public void testUserAgentBlackList() throws Exception
-    {
-        pushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
-        sendMainRequestAndCSSRequest(null, false);
-        run2ndClientRequests(false, false);
-    }
-
-    @Test
-    public void testReferrerPushPeriod() throws Exception
-    {
-        Session session = sendMainRequestAndCSSRequest(null, false);
-
-        // Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
-        Thread.sleep(referrerPushPeriod + 1);
-        sendRequest(session, associatedJSRequestHeaders, null, null, false);
-
-        run2ndClientRequests(false, true);
-    }
-
-    @Test
-    public void testMaxAssociatedResources() throws Exception
-    {
-        pushStrategy.setMaxAssociatedResources(1);
-        Session session = sendMainRequestAndCSSRequest(null, false);
-        sendRequest(session, associatedJSRequestHeaders, null, null, false);
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(2);
-        final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
-        final CountDownLatch pushResponseHeaders = new CountDownLatch(1);
-        Session session2 = startClient(version, serverAddress, null);
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid);
-
-                assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true));
-                assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
-                        .getValue().endsWith
-                                ("" +
-                                        ".css"),
-                        is(true));
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onHeaders(Stream stream, HeadersInfo headersInfo)
-                    {
-                        Fields headers = headersInfo.getHeaders();
-                        if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200 OK")
-                                && validateHeader(headers, HTTPSPDYHeader.VERSION.name(version),
-                                "HTTP/1.1") && validateHeader(headers, "content-encoding", "gzip"))
-                            pushResponseHeaders.countDown();
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false));
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        assertThat("Main request reply and/or data received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("Not more than one push is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
-        assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("Push response headers are valid", pushResponseHeaders.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testMaxConcurrentStreamsToDisablePush() throws Exception
-    {
-        final CountDownLatch pushReceivedLatch = new CountDownLatch(1);
-
-        Session pushCacheBuildSession = startClient(version, serverAddress, null);
-
-        pushCacheBuildSession.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter());
-        pushCacheBuildSession.syn(new SynInfo(associatedCSSRequestHeaders, true), new StreamFrameListener.Adapter());
-
-        Session session = startClient(version, serverAddress, null);
-
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0));
-        SettingsInfo settingsInfo = new SettingsInfo(settings);
-        session.settings(settingsInfo);
-
-        ((StdErrLog)Log.getLogger("org.eclipse.jetty.spdy.server.http" +
-                        ".HttpTransportOverSPDY$PushResourceCoordinator$1")).setHideStacks(true);
-        session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                pushReceivedLatch.countDown();
-                return super.onPush(stream, pushInfo);
-            }
-        });
-
-        assertThat("No push stream is received", pushReceivedLatch.await(1, TimeUnit.SECONDS), is(false));
-        ((StdErrLog)Log.getLogger("org.eclipse.jetty.spdy.server.http" +
-                                ".HttpTransportOverSPDY$PushResourceCoordinator$1")).setHideStacks(false);
-    }
-
-    @Test
-    public void testPushResourceOrder() throws Exception
-    {
-        final CountDownLatch allExpectedPushesReceivedLatch = new CountDownLatch(4);
-        final CountDownLatch allPushDataReceivedLatch = new CountDownLatch(4);
-
-        Session pushCacheBuildSession = startClient(version, serverAddress, null);
-
-        sendRequest(pushCacheBuildSession, mainRequestHeaders, null, null, false);
-        sendRequest(pushCacheBuildSession, associatedCSSRequestHeaders, null, null, false);
-        sendRequest(pushCacheBuildSession, associatedJSRequestHeaders, null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/image1.jpg", mainResource), null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/image2.jpg", mainResource), null, null, false);
-
-        Session session = startClient(version, serverAddress, null);
-
-        session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                LOG.info("onPush: stream: {}, pushInfo: {}", stream, pushInfo);
-                String uriHeader = pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue();
-                switch ((int)allExpectedPushesReceivedLatch.getCount())
-                {
-                    case 4:
-                        assertThat("1st pushed resource is the css", uriHeader.endsWith("css"), is(true));
-                        break;
-                    case 3:
-                        assertThat("2nd pushed resource is the js", uriHeader.endsWith("js"), is(true));
-                        break;
-                    case 2:
-                        assertThat("3rd pushed resource is image1", uriHeader.endsWith("image1.jpg"),
-                                is(true));
-                        break;
-                    case 1:
-                        assertThat("4th pushed resource is image2", uriHeader.endsWith("image2.jpg"),
-                                is(true));
-                        break;
-                }
-                allExpectedPushesReceivedLatch.countDown();
-                return new Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        if(dataInfo.isClose())
-                            allPushDataReceivedLatch.countDown();
-                    }
-                };
-            }
-        });
-
-        assertThat("All expected push resources have been received", allExpectedPushesReceivedLatch.await(5,
-                TimeUnit.SECONDS), is(true));
-        assertThat("All push data has been fully received", allPushDataReceivedLatch.await(5, TimeUnit.SECONDS),
-                is(true));
-    }
-
-    @Test
-    public void testThatPushResourcesAreUnique() throws Exception
-    {
-        final CountDownLatch pushReceivedLatch = new CountDownLatch(2);
-        sendMainRequestAndCSSRequest(null, false);
-        sendMainRequestAndCSSRequest(null, false);
-
-        Session session = startClient(version, serverAddress, null);
-
-        session.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                pushReceivedLatch.countDown();
-                LOG.info("Push received: {}", pushInfo);
-                return null;
-            }
-        });
-
-        assertThat("style.css has been pushed only once", pushReceivedLatch.await(1, TimeUnit.SECONDS), is(false));
-    }
-
-    @Test
-    public void testPushResourceAreSentNonInterleaved() throws Exception
-    {
-        final CountDownLatch allExpectedPushesReceivedLatch = new CountDownLatch(4);
-        final CountDownLatch allPushDataReceivedLatch = new CountDownLatch(4);
-        final CopyOnWriteArrayList<Integer> dataReceivedOrder = new CopyOnWriteArrayList<>();
-
-        InetSocketAddress bigResponseServerAddress = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                byte[] bytes = new byte[32768];
-                new Random().nextBytes(bytes);
-                ServletOutputStream outputStream = response.getOutputStream();
-                outputStream.write(bytes);
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session pushCacheBuildSession = startClient(version, bigResponseServerAddress, null);
-
-        Fields mainResourceHeaders = createHeadersWithoutReferrer(mainResource);
-        sendRequest(pushCacheBuildSession, mainResourceHeaders, null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/style.css", mainResource), null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/javascript.js", mainResource), null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/image1.jpg", mainResource), null, null, false);
-        sendRequest(pushCacheBuildSession, createHeaders("/image2.jpg", mainResource), null, null, false);
-
-        Session session = startClient(version, bigResponseServerAddress, null);
-
-        session.syn(new SynInfo(mainResourceHeaders, true), new StreamFrameListener.Adapter()
-        {
-            AtomicInteger currentStreamId = new AtomicInteger(2);
-
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                LOG.info("Received push for stream: {} {}", stream.getId(), pushInfo);
-                String uriHeader = pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue();
-                switch ((int)allExpectedPushesReceivedLatch.getCount())
-                {
-                    case 4:
-                        assertThat("1st pushed resource is the css", uriHeader.endsWith("css"), is(true));
-                        break;
-                    case 3:
-                        assertThat("2nd pushed resource is the js", uriHeader.endsWith("js"), is(true));
-                        break;
-                    case 2:
-                        assertThat("3rd pushed resource is image1", uriHeader.endsWith("image1.jpg"),
-                                is(true));
-                        break;
-                    case 1:
-                        assertThat("4th pushed resource is image2", uriHeader.endsWith("image2.jpg"),
-                                is(true));
-                        break;
-                }
-                allExpectedPushesReceivedLatch.countDown();
-                return new Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        if (stream.getId() != currentStreamId.get())
-                            throw new IllegalStateException("Streams interleaved. Expected StreamId: " +
-                                    currentStreamId + " but was: " + stream.getId());
-                        dataInfo.consume(dataInfo.available());
-                        if (dataInfo.isClose())
-                        {
-                            currentStreamId.compareAndSet(currentStreamId.get(), currentStreamId.get() + 2);
-                            dataReceivedOrder.add(stream.getId());
-                            allPushDataReceivedLatch.countDown();
-                        }
-                        LOG.info(stream.getId() + ":" + dataInfo);
-                    }
-                };
-            }
-        });
-
-        assertThat("All push resources received", allExpectedPushesReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("All pushData received", allPushDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("The data for different push streams has not been interleaved",
-                dataReceivedOrder.toString(), equalTo("[2, 4, 6, 8]"));
-        LOG.info(dataReceivedOrder.toString());
-    }
-
-    private InetSocketAddress createServer() throws Exception
-    {
-        GzipHandler gzipHandler = new GzipHandler();
-        gzipHandler.setHandler(new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                    output.print("<html><head/><body>HELLO</body></html>");
-                else if (url.endsWith(".css"))
-                    output.print("body { background: #FFF; }");
-                else if (url.endsWith(".js"))
-                    output.print("function(){}();");
-                baseRequest.setHandled(true);
-            }
-        });
-        return startHTTPServer(version, gzipHandler, 30000);
-    }
-
-    private Session sendMainRequestAndCSSRequest(SessionFrameListener sessionFrameListener, boolean awaitPush) throws Exception
-    {
-        Session session = startClient(version, serverAddress, sessionFrameListener);
-
-        CountDownLatch pushDataLatch = new CountDownLatch(2);
-        sendRequest(session, mainRequestHeaders, null, pushDataLatch, false);
-        sendRequest(session, associatedCSSRequestHeaders, null, pushDataLatch, false);
-        if (awaitPush)
-            assertThat("pushes have been received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true));
-
-        return session;
-    }
-
-    private void sendRequest(Session session, Fields requestHeaders, final CountDownLatch pushSynHeadersValid,
-                             final CountDownLatch pushDataLatch, final boolean resetPush) throws InterruptedException
-    {
-        LOG.info("sendRequest. headers={},resetPush={}", requestHeaders, resetPush);
-        final CountDownLatch dataReceivedLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(requestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                if (pushSynHeadersValid != null)
-                    validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid);
-
-                assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true));
-                assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
-                        .getValue().endsWith
-                                ("" +
-                                        ".css"),
-                        is(true));
-                if (resetPush)
-                    stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
-                return new StreamFrameListener.Adapter()
-                {
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertThat(replyInfo.getHeaders().get(HTTPSPDYHeader.STATUS.name(version)).getValue(), is("200 OK"));
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    dataReceivedLatch.countDown();
-            }
-        }, new Promise.Adapter<Stream>());
-        assertThat(dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private void run2ndClientRequests(final boolean validateHeaders,
-                                      boolean expectPushResource) throws Exception
-    {
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
-        final CountDownLatch pushResponseHeaders = new CountDownLatch(1);
-        Session session2 = startClient(version, serverAddress, null);
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                if (validateHeaders)
-                    validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid);
-
-                assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true));
-                assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
-                        .getValue().endsWith
-                                ("" +
-                                        ".css"),
-                        is(true));
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onHeaders(Stream stream, HeadersInfo headersInfo)
-                    {
-                        Fields headers = headersInfo.getHeaders();
-                        if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200 OK")
-                                && validateHeader(headers, HTTPSPDYHeader.VERSION.name(version),
-                                "HTTP/1.1") && validateHeader(headers, "content-encoding", "gzip"))
-                            pushResponseHeaders.countDown();
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertThat("replyInfo.isClose() is false", replyInfo.isClose(), is(false));
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        assertThat("Main request reply and/or data received", mainStreamLatch.await(5, TimeUnit.SECONDS), is(true));
-        if (expectPushResource)
-            assertThat("Pushed data received", pushDataLatch.await(5, TimeUnit.SECONDS), is(true));
-        else
-            assertThat("No push data is received", pushDataLatch.await(1, TimeUnit.SECONDS), is(false));
-        if (validateHeaders)
-        {
-            assertThat("Push push headers valid", pushSynHeadersValid.await(5, TimeUnit.SECONDS), is(true));
-            assertThat("Push response headers are valid", pushResponseHeaders.await(5, TimeUnit.SECONDS), is(true));
-        }
-    }
-
-    @Test
-    public void testAssociatedResourceIsPushed() throws Exception
-    {
-        InetSocketAddress address = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                    output.print("<html><head/><body>HELLO</body></html>");
-                else if (url.endsWith(".css"))
-                    output.print("body { background: #FFF; }");
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session session1 = startClient(version, address, null);
-
-        final CountDownLatch mainResourceLatch = new CountDownLatch(1);
-        Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
-
-        session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
-
-        sendRequest(session1, createHeaders(cssResource), null, null, false);
-
-        // Create another client, and perform the same request for the main resource, we expect the css being pushed
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        Session session2 = startClient(version, address, null);
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                Assert.assertTrue(stream.isUnidirectional());
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testAssociatedResourceWithWrongContentTypeIsNotPushed() throws Exception
-    {
-        final String fakeResource = "/fake.png";
-        InetSocketAddress address = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                {
-                    response.setContentType("text/html");
-                    output.print("<html><head/><body>HELLO</body></html>");
-                }
-                else if (url.equals(fakeResource))
-                {
-                    response.setContentType("text/html");
-                    output.print("<html><head/><body>IMAGE</body></html>");
-                }
-                else if (url.endsWith(".css"))
-                {
-                    response.setContentType("text/css");
-                    output.print("body { background: #FFF; }");
-                }
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session session1 = startClient(version, address, null);
-
-        final CountDownLatch mainResourceLatch = new CountDownLatch(1);
-        Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
-
-        session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
-        String cssResource = "/stylesheet.css";
-        Fields associatedRequestHeaders = createHeaders(cssResource);
-        session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    associatedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch fakeAssociatedResourceLatch = new CountDownLatch(1);
-        Fields fakeAssociatedRequestHeaders = createHeaders(fakeResource);
-        session1.syn(new SynInfo(fakeAssociatedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    fakeAssociatedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(fakeAssociatedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        // Create another client, and perform the same request for the main resource,
-        // we expect the css being pushed but not the fake PNG
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        Session session2 = startClient(version, address, null);
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                Assert.assertTrue(stream.isUnidirectional());
-                Assert.assertTrue(pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version)).getValue().endsWith("" +
-                        ".css"));
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testNestedAssociatedResourceIsPushed() throws Exception
-    {
-        InetSocketAddress address = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                    output.print("<html><head/><body>HELLO</body></html>");
-                else if (url.endsWith(".css"))
-                    output.print("body { background: #FFF; }");
-                else if (url.endsWith(".gif"))
-                    output.print("\u0000");
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session session1 = startClient(version, address, null);
-
-        final CountDownLatch mainResourceLatch = new CountDownLatch(1);
-        Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
-
-        session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
-        Fields associatedRequestHeaders = createHeaders(cssResource);
-        session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    associatedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch nestedResourceLatch = new CountDownLatch(1);
-        String imageUrl = "/image.gif";
-        Fields nestedRequestHeaders = createHeaders(imageUrl, cssResource);
-
-        session1.syn(new SynInfo(nestedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    nestedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(nestedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        // Create another client, and perform the same request for the main resource, we expect the css and the image being pushed
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(2);
-        Session session2 = startClient(version, address, null);
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                Assert.assertTrue(stream.isUnidirectional());
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-                    {
-                        return new Adapter()
-                        {
-                            @Override
-                            public void onData(Stream stream, DataInfo dataInfo)
-                            {
-                                dataInfo.consume(dataInfo.length());
-                                if (dataInfo.isClose())
-                                    pushDataLatch.countDown();
-                            }
-                        };
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testMainResourceWithReferrerIsNotPushed() throws Exception
-    {
-        InetSocketAddress address = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                    output.print("<html><head/><body>HELLO</body></html>");
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session session1 = startClient(version, address, null);
-
-        final CountDownLatch mainResourceLatch = new CountDownLatch(1);
-        Fields mainRequestHeaders = createHeadersWithoutReferrer(mainResource);
-
-        session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
-        String associatedResource = "/home.html";
-        Fields associatedRequestHeaders = createHeaders(associatedResource);
-
-        session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    associatedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        // Create another client, and perform the same request for the main resource, we expect nothing being pushed
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushLatch = new CountDownLatch(1);
-        Session session2 = startClient(version, address, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                pushLatch.countDown();
-                return null;
-            }
-        });
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertFalse(pushLatch.await(1, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testRequestWithIfModifiedSinceHeaderPreventsPush() throws Exception
-    {
-        InetSocketAddress address = startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                String url = request.getRequestURI();
-                PrintWriter output = response.getWriter();
-                if (url.endsWith(".html"))
-                    output.print("<html><head/><body>HELLO</body></html>");
-                else if (url.endsWith(".css"))
-                    output.print("body { background: #FFF; }");
-                baseRequest.setHandled(true);
-            }
-        }, 30000);
-        Session session1 = startClient(version, address, null);
-
-        final CountDownLatch mainResourceLatch = new CountDownLatch(1);
-        Fields mainRequestHeaders = createHeaders(mainResource);
-        mainRequestHeaders.put("If-Modified-Since", "Tue, 27 Mar 2012 16:36:52 GMT");
-        session1.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(mainResourceLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch associatedResourceLatch = new CountDownLatch(1);
-        Fields associatedRequestHeaders = createHeaders(cssResource);
-        session1.syn(new SynInfo(associatedRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    associatedResourceLatch.countDown();
-            }
-        });
-        Assert.assertTrue(associatedResourceLatch.await(5, TimeUnit.SECONDS));
-
-        // Create another client, and perform the same request for the main resource, we expect the css NOT being pushed as the main request contains an
-        // if-modified-since header
-
-        final CountDownLatch mainStreamLatch = new CountDownLatch(2);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        Session session2 = startClient(version, address, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(stream.isUnidirectional());
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-        });
-        session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                mainStreamLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    mainStreamLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(mainStreamLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertFalse("We don't expect data to be pushed as the main request contained an if-modified-since header", pushDataLatch.await(1, TimeUnit.SECONDS));
-    }
-
-    private void validateHeaders(Fields headers, CountDownLatch pushSynHeadersValid)
-    {
-        if (validateUriHeader(headers))
-            pushSynHeadersValid.countDown();
-    }
-
-    private boolean validateHeader(Fields headers, String name, String expectedValue)
-    {
-        Fields.Field header = headers.get(name);
-        if (header != null && expectedValue.equals(header.getValue()))
-            return true;
-        System.out.println(name + " not valid! Expected: " + expectedValue + " headers received:" + headers);
-        return false;
-    }
-
-    private boolean validateUriHeader(Fields headers)
-    {
-        Fields.Field uriHeader = headers.get(HTTPSPDYHeader.URI.name(version));
-        if (uriHeader != null)
-            if (version == SPDY.V2 && uriHeader.getValue().startsWith("http://"))
-                return true;
-            else if (version == SPDY.V3 && uriHeader.getValue().startsWith("/")
-                    && headers.get(HTTPSPDYHeader.HOST.name(version)) != null && headers.get(HTTPSPDYHeader.SCHEME.name(version)) != null)
-                return true;
-        System.out.println(HTTPSPDYHeader.URI.name(version) + " not valid!");
-        return false;
-    }
-
-    private Fields createHeaders(String resource)
-    {
-        return createHeaders(resource, mainResource);
-    }
-
-    private Fields createHeaders(String resource, String referrer)
-    {
-        Fields associatedRequestHeaders = createHeadersWithoutReferrer(resource);
-        associatedRequestHeaders.put("referer", "http://localhost:" + connector.getLocalPort() + referrer);
-        return associatedRequestHeaders;
-    }
-
-    private Fields createHeadersWithoutReferrer(String resource)
-    {
-        Fields requestHeaders = new Fields();
-        requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) " +
-                "Gecko/20100101 Firefox/16.0");
-        requestHeaders.put("accept-encoding", "gzip");
-        requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-        requestHeaders.put(HTTPSPDYHeader.URI.name(version), resource);
-        requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-        requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), "http");
-        requestHeaders.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + connector.getLocalPort());
-        return requestHeaders;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java
deleted file mode 100644
index 3a427ce..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyUnitTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.Set;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class ReferrerPushStrategyUnitTest
-{
-    public static final short VERSION = SPDY.V3;
-    public static final String SCHEME = "http";
-    public static final String HOST = "localhost";
-    public static final String MAIN_URI = "/index.html";
-    public static final String METHOD = "GET";
-
-    // class under test
-    private ReferrerPushStrategy referrerPushStrategy = new ReferrerPushStrategy();
-
-    @Mock
-    Stream stream;
-    @Mock
-    Session session;
-
-
-    @Before
-    public void setup()
-    {
-        referrerPushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
-    }
-
-    @Test
-    public void testReferrerCallsAfterTimeoutAreNotAddedAsPushResources() throws InterruptedException
-    {
-        Fields requestHeaders = getBaseHeaders(VERSION);
-        int referrerCallTimeout = 1000;
-        referrerPushStrategy.setReferrerPushPeriod(referrerCallTimeout);
-        setMockExpectations();
-
-        String referrerUrl = fillPushStrategyCache(requestHeaders);
-
-        // sleep to pretend that the user manually clicked on a linked resource instead the browser requesting sub
-        // resources immediately
-        Thread.sleep(referrerCallTimeout + 1);
-
-        requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image2.jpg");
-        requestHeaders.put("referer", referrerUrl);
-        Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources is empty", pushResources.size(), is(0));
-
-        requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        // as the image2.jpg request has been a link and not a sub resource, we expect that pushResources.size() is
-        // still 2
-        assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
-    }
-
-    @Test
-    public void testUserAgentFilter() throws InterruptedException
-    {
-        Fields requestHeaders = getBaseHeaders(VERSION);
-        setMockExpectations();
-
-        fillPushStrategyCache(requestHeaders);
-
-        Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources contains two elements image.jpg and style.css as no user-agent header is present",
-                pushResources.size(), is(2));
-
-        requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4");
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources contains two elements image.jpg and style.css as chrome is not blacklisted",
-                pushResources.size(), is(2));
-
-        requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20100101 Firefox/16.0");
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("no resources are returned as we want to filter firefox", pushResources.size(), is(0));
-    }
-
-    private Fields getBaseHeaders(short version)
-    {
-        Fields requestHeaders = new Fields();
-        requestHeaders.put(HTTPSPDYHeader.SCHEME.name(version), SCHEME);
-        requestHeaders.put(HTTPSPDYHeader.HOST.name(version), HOST);
-        requestHeaders.put(HTTPSPDYHeader.URI.name(version), MAIN_URI);
-        requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), METHOD);
-        return requestHeaders;
-    }
-
-    private void setMockExpectations()
-    {
-        when(stream.getSession()).thenReturn(session);
-        when(session.getVersion()).thenReturn(VERSION);
-    }
-
-    private String fillPushStrategyCache(Fields requestHeaders)
-    {
-        Set<String> pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources is empty", pushResources.size(), is(0));
-
-        String origin = SCHEME + "://" + HOST;
-        String referrerUrl = origin + MAIN_URI;
-
-        requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "image.jpg");
-        requestHeaders.put("referer", referrerUrl);
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources is empty", pushResources.size(), is(0));
-
-        requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), "style.css");
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources is empty", pushResources.size(), is(0));
-
-        requestHeaders.put(HTTPSPDYHeader.URI.name(VERSION), MAIN_URI);
-        pushResources = referrerPushStrategy.apply(stream, requestHeaders, new Fields());
-        assertThat("pushResources contains two elements image.jpg and style.css", pushResources.size(), is(2));
-        return referrerUrl;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java
deleted file mode 100644
index e0a6983..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SPDYTestUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server.http;
-
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class SPDYTestUtils
-{
-    public static Fields createHeaders(String host, int port, short version, String httpMethod, String path)
-    {
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.METHOD.name(version), httpMethod);
-        headers.put(HTTPSPDYHeader.URI.name(version), path);
-        headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-        headers.put(HTTPSPDYHeader.SCHEME.name(version), "http");
-        headers.put(HTTPSPDYHeader.HOST.name(version), host + ":" + port);
-        return headers;
-    }
-
-    public static SslContextFactory newSslContextFactory()
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setEndpointIdentificationAlgorithm("");
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-        sslContextFactory.setProtocol("TLSv1");
-        sslContextFactory.setIncludeProtocols("TLSv1");
-        return sslContextFactory;
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java
deleted file mode 100644
index 4756e1a..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SSLExternalServerTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class SSLExternalServerTest extends AbstractHTTPSPDYTest
-{
-    public SSLExternalServerTest(short version)
-    {
-        // Google Servers do not support SPDY/2 anymore
-        super(SPDY.V3);
-    }
-
-    @Override
-    protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool)
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        // Force TLSv1
-        sslContextFactory.setIncludeProtocols("TLSv1");
-        sslContextFactory.setEndpointIdentificationAlgorithm("");
-        return new SPDYClient.Factory(threadPool, null, sslContextFactory, 30000);
-    }
-
-    @Test
-    @Ignore("Relies on an external server")
-    public void testExternalServer() throws Exception
-    {
-        String host = "encrypted.google.com";
-        int port = 443;
-        InetSocketAddress address = new InetSocketAddress(host, port);
-
-        try
-        {
-            // Test whether there is connectivity to avoid fail the test when offline
-            Socket socket = new Socket();
-            socket.connect(address, 5000);
-            socket.close();
-        }
-        catch (IOException x)
-        {
-            Assume.assumeNoException(x);
-        }
-
-        Session session = startClient(version, address, null);
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.SCHEME.name(version), "https");
-        headers.put(HTTPSPDYHeader.HOST.name(version), host + ":" + port);
-        headers.put(HTTPSPDYHeader.METHOD.name(version), "GET");
-        headers.put(HTTPSPDYHeader.URI.name(version), "/");
-        headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-        final CountDownLatch latch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                Fields.Field versionHeader = headers.get(HTTPSPDYHeader.STATUS.name(version));
-                if (versionHeader != null)
-                {
-                    Matcher matcher = Pattern.compile("(\\d{3}).*").matcher(versionHeader.getValue());
-                    if (matcher.matches() && Integer.parseInt(matcher.group(1)) < 400)
-                        latch.countDown();
-                }
-            }
-        });
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
deleted file mode 100644
index 8012510..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ServerHTTPSPDYTest.java
+++ /dev/null
@@ -1,1625 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncEvent;
-import javax.servlet.AsyncListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.StdErrLog;
-import org.junit.Assert;
-import org.junit.Test;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.core.IsInstanceOf.instanceOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
-{
-    public static final String SUSPENDED_ATTRIBUTE = ServerHTTPSPDYTest.class.getName() + ".SUSPENDED";
-
-    public ServerHTTPSPDYTest(short version)
-    {
-        super(version);
-    }
-
-    @Test
-    public void testSimpleGET() throws Exception
-    {
-        final String path = "/foo";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("GET", httpRequest.getMethod());
-                assertEquals(path, target);
-                assertEquals(path, httpRequest.getRequestURI());
-                assertThat("accept-encoding is set to gzip, even if client didn't set it",
-                        httpRequest.getHeader("accept-encoding"), containsString("gzip"));
-                assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort()));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path);
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), is(true));
-                assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), is(notNullValue()));
-                assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), is(notNullValue()));
-                replyLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithQueryString() throws Exception
-    {
-        final String path = "/foo";
-        final String query = "p=1";
-        final String uri = path + "?" + query;
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("GET", httpRequest.getMethod());
-                assertEquals(path, target);
-                assertEquals(path, httpRequest.getRequestURI());
-                assertEquals(query, httpRequest.getQueryString());
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri);
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithCookies() throws Exception
-    {
-        final String path = "/foo";
-        final String uri = path;
-        final String cookie1 = "cookie1";
-        final String cookie2 = "cookie2";
-        final String cookie1Value = "cookie 1 value";
-        final String cookie2Value = "cookie 2 value";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.addCookie(new Cookie(cookie1, cookie1Value));
-                httpResponse.addCookie(new Cookie(cookie2, cookie2Value));
-                assertThat("method is GET", httpRequest.getMethod(), is("GET"));
-                assertThat("target is /foo", target, is(path));
-                assertThat("requestUri is /foo", httpRequest.getRequestURI(), is(path));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri);
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertThat("isClose is true", replyInfo.isClose(), is(true));
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertThat("response code is 200 OK", replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue()
-                        .contains("200"), is(true));
-                assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(0), is(cookie1 + "=\"" + cookie1Value +
-                        "\";Version=1"));
-                assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(1), is(cookie2 + "=\"" + cookie2Value +
-                        "\";Version=1"));
-                replyLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testHEAD() throws Exception
-    {
-        final String path = "/foo";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("HEAD", httpRequest.getMethod());
-                assertEquals(path, target);
-                assertEquals(path, httpRequest.getRequestURI());
-                httpResponse.getWriter().write("body that shouldn't be sent on a HEAD request");
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "HEAD", path);
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                fail("HEAD request shouldn't send any data");
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTWithDelayedContentBody() throws Exception
-    {
-        final String path = "/foo";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                // don't read the request body, reply immediately
-                request.setHandled(true);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path);
-        headers.put("content-type", "application/x-www-form-urlencoded");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        assertTrue(replyInfo.isClose());
-                        Fields replyHeaders = replyInfo.getHeaders();
-                        assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                        replyLatch.countDown();
-                    }
-                });
-        stream.data(new StringDataInfo("a", false));
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        stream.data(new StringDataInfo("b", true));
-    }
-
-    @Test
-    public void testPOSTWithParameters() throws Exception
-    {
-        final String path = "/foo";
-        final String data = "a=1&b=2";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("POST", httpRequest.getMethod());
-                assertEquals("1", httpRequest.getParameter("a"));
-                assertEquals("2", httpRequest.getParameter("b"));
-                assertNotNull(httpRequest.getRemoteHost());
-                assertNotNull(httpRequest.getRemotePort());
-                assertNotNull(httpRequest.getRemoteAddr());
-                assertNotNull(httpRequest.getLocalPort());
-                assertNotNull(httpRequest.getLocalName());
-                assertNotNull(httpRequest.getLocalAddr());
-                assertNotNull(httpRequest.getServerPort());
-                assertNotNull(httpRequest.getServerName());
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path);
-        headers.put("content-type", "application/x-www-form-urlencoded");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        assertTrue(replyInfo.isClose());
-                        Fields replyHeaders = replyInfo.getHeaders();
-                        assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                        replyLatch.countDown();
-                    }
-                });
-        stream.data(new StringDataInfo(data, true));
-
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTWithParametersInTwoFramesTwoReads() throws Exception
-    {
-        final String path = "/foo";
-        final String data1 = "a=1&";
-        final String data2 = "b=2";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("POST", httpRequest.getMethod());
-                assertEquals("1", httpRequest.getParameter("a"));
-                assertEquals("2", httpRequest.getParameter("b"));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path);
-        headers.put("content-type", "application/x-www-form-urlencoded");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        assertTrue(replyInfo.isClose());
-                        Fields replyHeaders = replyInfo.getHeaders();
-                        assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                        replyLatch.countDown();
-                    }
-                });
-        // Sleep between the data frames so that they will be read in 2 reads
-        stream.data(new StringDataInfo(data1, false));
-        Thread.sleep(1000);
-        stream.data(new StringDataInfo(data2, true));
-
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTWithParametersInTwoFramesOneRead() throws Exception
-    {
-        final String path = "/foo";
-        final String data1 = "a=1&";
-        final String data2 = "b=2";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("POST", httpRequest.getMethod());
-                assertEquals("1", httpRequest.getParameter("a"));
-                assertEquals("2", httpRequest.getParameter("b"));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path);
-        headers.put("content-type", "application/x-www-form-urlencoded");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-
-        // Send the data frames consecutively, so the server reads both frames in one read
-        stream.data(new StringDataInfo(data1, false));
-        stream.data(new StringDataInfo(data2, true));
-
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithSmallResponseContent() throws Exception
-    {
-        final String data = "0123456789ABCDEF";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data.getBytes(StandardCharsets.UTF_8));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                assertTrue(dataInfo.isClose());
-                assertEquals(data, dataInfo.asString(StandardCharsets.UTF_8, true));
-                dataLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithOneByteResponseContent() throws Exception
-    {
-        final char data = 'x';
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                assertTrue(dataInfo.isClose());
-                byte[] bytes = dataInfo.asBytes(true);
-                assertEquals(1, bytes.length);
-                assertEquals(data, bytes[0]);
-                dataLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithSmallResponseContentInTwoChunks() throws Exception
-    {
-        final String data1 = "0123456789ABCDEF";
-        final String data2 = "FEDCBA9876543210";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data1.getBytes(StandardCharsets.UTF_8));
-                output.flush();
-                output.write(data2.getBytes(StandardCharsets.UTF_8));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replyFrames = new AtomicInteger();
-            private final AtomicInteger dataFrames = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replyFrames.incrementAndGet());
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                int data = dataFrames.incrementAndGet();
-                assertTrue(data >= 1 && data <= 2);
-                if (data == 1)
-                    assertEquals(data1, dataInfo.asString(StandardCharsets.UTF_8, true));
-                else
-                    assertEquals(data2, dataInfo.asString(StandardCharsets.UTF_8, true));
-                dataLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithBigResponseContentInOneWrite() throws Exception
-    {
-        final byte[] data = new byte[128 * 1024];
-        Arrays.fill(data, (byte)'x');
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger contentBytes = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining());
-                if (dataInfo.isClose())
-                {
-                    assertEquals(data.length, contentBytes.get());
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithBigResponseContentInMultipleWrites() throws Exception
-    {
-        final byte[] data = new byte[4 * 1024];
-        Arrays.fill(data, (byte)'x');
-        final int writeTimes = 16;
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                for (int i = 0; i < writeTimes; i++)
-                {
-                    output.write(data);
-                }
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger contentBytes = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining());
-                if (dataInfo.isClose())
-                {
-                    assertEquals(data.length * writeTimes, contentBytes.get());
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithBigResponseContentInTwoWrites() throws Exception
-    {
-        final byte[] data = new byte[128 * 1024];
-        Arrays.fill(data, (byte)'y');
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data);
-                output.write(data);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger contentBytes = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining());
-                if (dataInfo.isClose())
-                {
-                    assertEquals(2 * data.length, contentBytes.get());
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithOutputStreamFlushedAndClosed() throws Exception
-    {
-        final String data = "0123456789ABCDEF";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(data.getBytes(StandardCharsets.UTF_8));
-                output.flush();
-                output.close();
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                ByteBuffer byteBuffer = dataInfo.asByteBuffer(true);
-                while (byteBuffer.hasRemaining())
-                    buffer.write(byteBuffer.get());
-                if (dataInfo.isClose())
-                {
-                    assertEquals(data, new String(buffer.toByteArray(), StandardCharsets.UTF_8));
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithResponseResetBuffer() throws Exception
-    {
-        final String data1 = "0123456789ABCDEF";
-        final String data2 = "FEDCBA9876543210";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setStatus(HttpServletResponse.SC_OK);
-                ServletOutputStream output = httpResponse.getOutputStream();
-                // Write some
-                output.write(data1.getBytes(StandardCharsets.UTF_8));
-                // But then change your mind and reset the buffer
-                httpResponse.resetBuffer();
-                output.write(data2.getBytes(StandardCharsets.UTF_8));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                ByteBuffer byteBuffer = dataInfo.asByteBuffer(true);
-                while (byteBuffer.hasRemaining())
-                    buffer.write(byteBuffer.get());
-                if (dataInfo.isClose())
-                {
-                    assertEquals(data2, new String(buffer.toByteArray(), StandardCharsets.UTF_8));
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithRedirect() throws Exception
-    {
-        final String suffix = "/redirect";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                String location = httpResponse.encodeRedirectURL(String.format("%s://%s:%d%s",
-                        request.getScheme(), request.getLocalAddr(), request.getLocalPort(), target + suffix));
-                httpResponse.sendRedirect(location);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replies = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replies.incrementAndGet());
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("302"));
-                assertTrue(replyHeaders.get("location").getValue().endsWith(suffix));
-                replyLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithSendError() throws Exception
-    {
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replies = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replies.incrementAndGet());
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("404"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                if (dataInfo.isClose())
-                    dataLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithException() throws Exception
-    {
-        StdErrLog log = StdErrLog.getLogger(HttpChannel.class);
-        log.setHideStacks(true);
-
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                throw new NullPointerException("thrown_explicitly_by_the_test");
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch latch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replies = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replies.incrementAndGet());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("500"));
-                replyLatch.countDown();
-                if (replyInfo.isClose())
-                    latch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                if (dataInfo.isClose())
-                    latch.countDown();
-            }
-        });
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(latch.await(5, TimeUnit.SECONDS));
-
-        log.setHideStacks(false);
-    }
-
-    @Test
-    public void testGETWithSmallResponseContentChunked() throws Exception
-    {
-        final String pangram1 = "the quick brown fox jumps over the lazy dog";
-        final String pangram2 = "qualche vago ione tipo zolfo, bromo, sodio";
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                httpResponse.setHeader("Transfer-Encoding", "chunked");
-                ServletOutputStream output = httpResponse.getOutputStream();
-                output.write(pangram1.getBytes(StandardCharsets.UTF_8));
-                httpResponse.setHeader("EXTRA", "X");
-                output.flush();
-                output.write(pangram2.getBytes(StandardCharsets.UTF_8));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replyFrames = new AtomicInteger();
-            private final AtomicInteger dataFrames = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replyFrames.incrementAndGet());
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                assertTrue(replyHeaders.get("extra").getValue().contains("X"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                int count = dataFrames.incrementAndGet();
-                if (count == 1)
-                {
-                    Assert.assertFalse(dataInfo.isClose());
-                    assertEquals(pangram1, dataInfo.asString(StandardCharsets.UTF_8, true));
-                }
-                else if (count == 2)
-                {
-                    assertTrue(dataInfo.isClose());
-                    assertEquals(pangram2, dataInfo.asString(StandardCharsets.UTF_8, true));
-                }
-                dataLatch.countDown();
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithMediumContentAsBufferByPassed() throws Exception
-    {
-        final byte[] data = new byte[2048];
-
-        final CountDownLatch handlerLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                request.getResponse().getHttpOutput().sendContent(ByteBuffer.wrap(data));
-                handlerLatch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger replyFrames = new AtomicInteger();
-            private final AtomicInteger contentLength = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertEquals(1, replyFrames.incrementAndGet());
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                contentLength.addAndGet(dataInfo.asBytes(true).length);
-                if (dataInfo.isClose())
-                {
-                    Assert.assertEquals(data.length, contentLength.get());
-                    dataLatch.countDown();
-                }
-            }
-        });
-        assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETWithMultipleMediumContentByPassed() throws Exception
-    {
-        final byte[] data = new byte[2048];
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                // The sequence of write/flush/write/write below triggers a condition where
-                // HttpGenerator._bypass is set to true on the second write(), and the
-                // third write causes an infinite spin loop on the third write().
-                request.setHandled(true);
-                OutputStream output = httpResponse.getOutputStream();
-                output.write(data);
-                output.flush();
-                output.write(data);
-                output.write(data);
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        final AtomicInteger contentLength = new AtomicInteger();
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.available());
-                contentLength.addAndGet(dataInfo.length());
-                if (dataInfo.isClose())
-                    dataLatch.countDown();
-            }
-        });
-        assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-        assertEquals(3 * data.length, contentLength.get());
-    }
-
-    @Test
-    public void testPOSTThenSuspendRequestThenReadOneChunkThenComplete() throws Exception
-    {
-        final byte[] data = new byte[2000];
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                final AsyncContext asyncContext = request.startAsync();
-                new Thread()
-                {
-                    @Override
-                    public void run()
-                    {
-                        try
-                        {
-                            readRequestData(request, data.length);
-                            asyncContext.complete();
-                            latch.countDown();
-                        }
-                        catch (IOException x)
-                        {
-                            x.printStackTrace();
-                        }
-                    }
-                }.start();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(data, true));
-
-        assertTrue(latch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTThenSuspendExpire() throws Exception
-    {
-        final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
-                {
-                    dispatchedAgainAfterExpire.countDown();
-                }
-                else
-                {
-                    AsyncContext asyncContext = request.startAsync();
-                    asyncContext.setTimeout(1000);
-                    asyncContext.addListener(new AsyncListenerAdapter());
-                    request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
-                }
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-
-        assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
-                TimeUnit.SECONDS));
-        assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTThenSuspendExpireWithRequestData() throws Exception
-    {
-        final byte[] data = new byte[2000];
-        final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
-                {
-                    dispatchedAgainAfterExpire.countDown();
-                }
-                else
-                {
-                    readRequestData(request, data.length);
-                    AsyncContext asyncContext = request.startAsync();
-                    asyncContext.setTimeout(1000);
-                    asyncContext.addListener(new AsyncListenerAdapter());
-                    request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
-                }
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(data, true));
-
-        assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5,
-                TimeUnit.SECONDS));
-        assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    private void readRequestData(Request request, int expectedDataLength) throws IOException
-    {
-        InputStream input = request.getInputStream();
-        byte[] buffer = new byte[512];
-        int read = 0;
-        while (read < expectedDataLength)
-            read += input.read(buffer);
-    }
-
-    @Test
-    public void testPOSTThenSuspendRequestThenReadTwoChunksThenComplete() throws Exception
-    {
-        final byte[] data = new byte[2000];
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                final AsyncContext asyncContext = request.startAsync();
-                new Thread()
-                {
-                    @Override
-                    public void run()
-                    {
-                        try
-                        {
-                            InputStream input = request.getInputStream();
-                            byte[] buffer = new byte[512];
-                            int read = 0;
-                            while (read < 2 * data.length)
-                                read += input.read(buffer);
-                            asyncContext.complete();
-                            latch.countDown();
-                        }
-                        catch (IOException x)
-                        {
-                            x.printStackTrace();
-                        }
-                    }
-                }.start();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                replyLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(data, false));
-        stream.data(new BytesDataInfo(data, true));
-
-        assertTrue(latch.await(5, TimeUnit.SECONDS));
-        assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTThenSuspendRequestThenResumeThenRespond() throws Exception
-    {
-        final byte[] data = new byte[1000];
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE)
-                {
-                    OutputStream output = httpResponse.getOutputStream();
-                    output.write(data);
-                }
-                else
-                {
-                    final AsyncContext asyncContext = request.startAsync();
-                    request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE);
-                    InputStream input = request.getInputStream();
-                    byte[] buffer = new byte[256];
-                    int read = 0;
-                    while (read < data.length)
-                        read += input.read(buffer);
-                    new Thread()
-                    {
-                        @Override
-                        public void run()
-                        {
-                            try
-                            {
-                                TimeUnit.SECONDS.sleep(1);
-                                asyncContext.dispatch();
-                                latch.countDown();
-                            }
-                            catch (InterruptedException x)
-                            {
-                                x.printStackTrace();
-                            }
-                        }
-                    }.start();
-                }
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch responseLatch = new CountDownLatch(2);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                responseLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                if (dataInfo.isClose())
-                    responseLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(data, true));
-
-        assertTrue(latch.await(5, TimeUnit.SECONDS));
-        assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPOSTThenResponseWithoutReadingContent() throws Exception
-    {
-        final byte[] data = new byte[1000];
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                latch.countDown();
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo");
-        final CountDownLatch responseLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"));
-                responseLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(data, false));
-        stream.data(new BytesDataInfo(5, TimeUnit.SECONDS, data, true));
-
-        assertTrue(latch.await(5, TimeUnit.SECONDS));
-        assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testIdleTimeout() throws Exception
-    {
-        final int idleTimeout = 500;
-        final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1);
-
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                try
-                {
-                    Thread.sleep(2 * idleTimeout);
-                }
-                catch (InterruptedException e)
-                {
-                    throw new RuntimeException(e);
-                }
-                request.setHandled(true);
-            }
-        }, 30000), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/");
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onFailure(Stream stream, Throwable x)
-                    {
-                        assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class));
-                        timeoutReceivedLatch.countDown();
-                    }
-                });
-        stream.setIdleTimeout(idleTimeout);
-
-        assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testIdleTimeoutSetOnConnectionOnly() throws Exception
-    {
-        final int idleTimeout = 500;
-        final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                try
-                {
-                    Thread.sleep(2 * idleTimeout);
-                }
-                catch (InterruptedException e)
-                {
-                    throw new RuntimeException(e);
-                }
-                request.setHandled(true);
-            }
-        }, idleTimeout), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/");
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onFailure(Stream stream, Throwable x)
-                    {
-                        assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class));
-                        timeoutReceivedLatch.countDown();
-                    }
-                });
-
-        assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSingleStreamIdleTimeout() throws Exception
-    {
-        final int idleTimeout = 500;
-        final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch replyReceivedLatch = new CountDownLatch(3);
-        Session session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                if ("true".equals(request.getHeader("slow")))
-                {
-                    try
-                    {
-                        Thread.sleep(2 * idleTimeout);
-                    }
-                    catch (InterruptedException e)
-                    {
-                        throw new RuntimeException(e);
-                    }
-                }
-                request.setHandled(true);
-            }
-        }, idleTimeout), null);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/");
-        Fields slowHeaders = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/");
-        slowHeaders.add("slow", "true");
-        sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers);
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, slowHeaders, true, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onFailure(Stream stream, Throwable x)
-                    {
-                        assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class));
-                        timeoutReceivedLatch.countDown();
-                    }
-                });
-        Thread.sleep(idleTimeout / 2);
-        sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers);
-        Thread.sleep(idleTimeout / 2);
-        sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers);
-        assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("received replies on 3 non idle requests", replyReceivedLatch.await(5, TimeUnit.SECONDS),
-                is(true));
-    }
-
-    private void sendSingleRequestThatIsNotExpectedToTimeout(final CountDownLatch replyReceivedLatch, Session session, Fields headers) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0),
-                new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        replyReceivedLatch.countDown();
-                    }
-                });
-    }
-
-    private class AsyncListenerAdapter implements AsyncListener
-    {
-        @Override
-        public void onStartAsync(AsyncEvent event) throws IOException
-        {
-        }
-
-        @Override
-        public void onComplete(AsyncEvent event) throws IOException
-        {
-        }
-
-        @Override
-        public void onTimeout(AsyncEvent event) throws IOException
-        {
-            event.getAsyncContext().dispatch();
-        }
-
-        @Override
-        public void onError(AsyncEvent event) throws IOException
-        {
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java
deleted file mode 100644
index 76740d6..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/SimpleHTTPBenchmarkTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.http;
-
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.handler.AbstractHandler;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.hamcrest.CoreMatchers;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore("So far only used for testing performance tweaks. So no need to run it in a build")
-public class SimpleHTTPBenchmarkTest extends AbstractHTTPSPDYTest
-{
-    private static final Logger LOG = Log.getLogger(SimpleHTTPBenchmarkTest.class);
-    private final int dataSize = 4096 * 100;
-    private Session session;
-    private int requestCount = 100;
-
-    public SimpleHTTPBenchmarkTest(short version)
-    {
-        super(version);
-    }
-
-    @Before
-    public void setUp() throws Exception
-    {
-        final byte[] data = new byte[dataSize];
-        new Random().nextBytes(data);
-        session = startClient(version, startHTTPServer(version, new AbstractHandler()
-        {
-            @Override
-            public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-                    throws IOException, ServletException
-            {
-                request.setHandled(true);
-                assertEquals("GET", httpRequest.getMethod());
-                assertThat("accept-encoding is set to gzip, even if client didn't set it",
-                        httpRequest.getHeader("accept-encoding"), containsString("gzip"));
-                assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort()));
-                httpResponse.getOutputStream().write(data);
-            }
-        }, 0), null);
-    }
-
-    @Test
-    public void testRunBenchmark() throws Exception
-    {
-        long overallStart = System.nanoTime();
-        int iterations = 20;
-        for (int j = 0; j < iterations; j++)
-        {
-            long start = System.nanoTime();
-            for (int i = 0; i < requestCount; i++)
-                sendGetRequestWithData();
-            long timeElapsed = System.nanoTime() - start;
-            LOG.info("Requests with {}b response took: {}ms", dataSize, timeElapsed / 1000 / 1000);
-        }
-        long timeElapsedOverall = (System.nanoTime() - overallStart) / 1000 / 1000;
-        LOG.info("Time elapsed overall: {}ms avg: {}ms", timeElapsedOverall, timeElapsedOverall / iterations);
-    }
-
-    private void sendGetRequest() throws Exception
-    {
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final String path = "/foo";
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertTrue(replyInfo.isClose());
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), CoreMatchers.is(true));
-                assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue()));
-                assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue()));
-                replyLatch.countDown();
-            }
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private void sendGetRequestWithData() throws Exception
-    {
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        final String path = "/foo";
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path);
-        session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields replyHeaders = replyInfo.getHeaders();
-                assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), CoreMatchers.is(true));
-                assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), CoreMatchers.is(notNullValue()));
-                assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), CoreMatchers.is(notNullValue()));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.available());
-                if (dataInfo.isClose())
-                    dataLatch.countDown();
-            }
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java
deleted file mode 100644
index c1a3fa7..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java
+++ /dev/null
@@ -1,408 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.client.util.StringContentProvider;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnector;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-@RunWith(Parameterized.class)
-public class ProxyHTTPToSPDYTest
-{
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    private final short version;
-    private HttpClient httpClient;
-    private HttpClient httpClient2;
-    private SPDYClient.Factory factory;
-    private Server server;
-    private Server proxy;
-    private ServerConnector proxyConnector;
-
-    public ProxyHTTPToSPDYTest(short version)
-    {
-        this.version = version;
-    }
-
-    protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
-    {
-        server = new Server();
-        SPDYServerConnector serverConnector = new SPDYServerConnector(server, listener);
-        serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener));
-        serverConnector.setPort(0);
-        server.addConnector(serverConnector);
-        server.start();
-        return new InetSocketAddress("localhost", serverConnector.getLocalPort());
-    }
-
-    protected InetSocketAddress startProxy(InetSocketAddress address) throws Exception
-    {
-        proxy = new Server();
-        ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector();
-        SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory);
-        proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine);
-        proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, address.getHostName(), address.getPort()));
-        proxyConnector = new HTTPSPDYProxyServerConnector(proxy, proxyEngineSelector);
-        proxyConnector.setPort(9999);
-        proxy.addConnector(proxyConnector);
-        proxy.start();
-        return new InetSocketAddress("localhost", proxyConnector.getLocalPort());
-    }
-
-    @Before
-    public void init() throws Exception
-    {
-        factory = new SPDYClient.Factory();
-        factory.start();
-        httpClient = new HttpClient();
-        httpClient.start();
-        httpClient2 = new HttpClient();
-        httpClient2.start();
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        httpClient.stop();
-        httpClient2.stop();
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-        if (proxy != null)
-        {
-            proxy.stop();
-            proxy.join();
-        }
-        factory.stop();
-    }
-
-    @Test
-    public void testClosingClientDoesNotCloseServer() throws Exception
-    {
-        final CountDownLatch closeLatch = new CountDownLatch(1);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
-                return null;
-            }
-
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                closeLatch.countDown();
-            }
-        }));
-
-        Request request = httpClient.newRequest("localhost", proxyAddress.getPort()).method("GET");
-        request.header("Connection", "close");
-        ContentResponse response = request.send();
-
-        assertThat("response status is 200 OK", response.getStatus(), is(200));
-
-        // Must not close, other clients may still be connected
-        Assert.assertFalse(closeLatch.await(1, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testGETThenNoContentFromTwoClients() throws Exception
-    {
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(synInfo.isClose());
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true);
-                stream.reply(replyInfo, new Callback.Adapter());
-                return null;
-            }
-        }));
-
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET)
-                .send();
-        assertThat("response code is 200 OK", response.getStatus(), is(200));
-
-        // Perform another request with another client
-        ContentResponse response2 = httpClient2.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET)
-                .send();
-        assertThat("response2 code is 200 OK", response2.getStatus(), is(200));
-    }
-
-    @Test
-    public void testHEADRequest() throws Exception
-    {
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(synInfo.isClose());
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                ReplyInfo replyInfo = new ReplyInfo(responseHeaders, true);
-                stream.reply(replyInfo, new Callback.Adapter());
-
-                return null;
-            }
-        }));
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.HEAD).send();
-        assertThat("response code is 200 OK", response.getStatus(), is(200));
-    }
-
-    @Test
-    public void testGETThenSmallResponseContent() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(synInfo.isClose());
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                responseHeaders.put("content-length", String.valueOf(data.length));
-
-                ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
-                stream.reply(replyInfo, new Callback.Adapter());
-                stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-
-                return null;
-            }
-        }));
-
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET)
-                .send();
-        assertThat("response code is 200 OK", response.getStatus(), is(200));
-        assertThat(Arrays.equals(response.getContent(), data), is(true));
-
-        // Perform another request so that we are sure we reset the states of parsers and generators
-        ContentResponse response2 = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET)
-                .send();
-        assertThat("response2 code is 200 OK", response2.getStatus(), is(200));
-        assertThat(Arrays.equals(response2.getContent(), data), is(true));
-    }
-
-    @Test
-    public void testPOSTWithSmallRequestContentThenRedirect() throws Exception
-    {
-        final String data = "0123456789ABCDEF";
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                        {
-                            Fields headers = new Fields();
-                            headers.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                            headers.put(HTTPSPDYHeader.STATUS.name(version), "303 See Other");
-                            headers.put(HttpHeader.LOCATION.asString(),"http://other.location");
-                            stream.reply(new ReplyInfo(headers, true), new Callback.Adapter());
-                        }
-                    }
-                };
-            }
-        }));
-
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.POST).content(new
-                StringContentProvider(data)).followRedirects(false).send();
-        assertThat("response code is 303", response.getStatus(), is(303));
-
-        // Perform another request so that we are sure we reset the states of parsers and generators
-        ContentResponse response2 = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod
-                .POST).content(new StringContentProvider(data)).followRedirects(false).send();
-        assertThat("response2 code is 303", response2.getStatus(), is(303));
-    }
-
-    @Test
-    public void testPOSTWithSmallRequestContentThenSmallResponseContent() throws Exception
-    {
-        String dataString = "0123456789ABCDEF";
-        final byte[] data = dataString.getBytes(StandardCharsets.UTF_8);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                        {
-                            Fields responseHeaders = new Fields();
-                            responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                            responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                            responseHeaders.put("content-length", String.valueOf(data.length));
-                            ReplyInfo replyInfo = new ReplyInfo(responseHeaders, false);
-                            stream.reply(replyInfo, new Callback.Adapter());
-                            stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                        }
-                    }
-                };
-            }
-        }));
-
-        ContentResponse response = httpClient.POST("http://localhost:" + proxyAddress.getPort() + "/").content(new
-                StringContentProvider(dataString)).send();
-        assertThat("response status is 200 OK", response.getStatus(), is(200));
-        assertThat("response content matches expected dataString", response.getContentAsString(), is(dataString));
-
-        // Perform another request so that we are sure we reset the states of parsers and generators
-        response = httpClient.POST("http://localhost:" + proxyAddress.getPort() + "/").content(new
-                StringContentProvider(dataString)).send();
-        assertThat("response status is 200 OK", response.getStatus(), is(200));
-        assertThat("response content matches expected dataString", response.getContentAsString(), is(dataString));
-    }
-
-    @Test
-    public void testGETThenSPDYPushIsIgnored() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-
-                Fields pushHeaders = new Fields();
-                pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
-                stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream pushStream)
-                    {
-                        pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                    }
-                });
-
-                stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
-                return null;
-            }
-        }));
-
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET).send();
-        assertThat("response code is 200 OK", response.getStatus(), is(200));
-    }
-
-    @Test
-    public void testGETThenReset() throws Exception
-    {
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(synInfo.isClose());
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-
-                stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
-
-                return null;
-            }
-        }));
-
-        ContentResponse response = httpClient.newRequest("localhost", proxyAddress.getPort()).method(HttpMethod.GET).send();
-        assertThat("response code is 502 Gateway Error", response.getStatus(), is(502));
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java
deleted file mode 100644
index a50f160..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.DefaultHandler;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.server.http.SPDYTestUtils;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static junit.framework.Assert.fail;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-@Ignore
-@RunWith(value = Parameterized.class)
-public abstract class ProxySPDYToHTTPLoadTest
-{
-    private static final Logger LOG = Log.getLogger(ProxySPDYToHTTPLoadTest.class);
-
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    private final short version;
-    private final NegotiatingServerConnectionFactory negotiator;
-    private final String server1String = "server1";
-    private final String server2String = "server2";
-    private SPDYClient.Factory factory;
-    private Server server1;
-    private Server server2;
-    private Server proxy;
-    private ServerConnector proxyConnector;
-    private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory();
-
-    public ProxySPDYToHTTPLoadTest(short version, NegotiatingServerConnectionFactory negotiator)
-    {
-        this.version = version;
-        this.negotiator = negotiator;
-    }
-
-    @Before
-    public void init() throws Exception
-    {
-        // change the ports if you want to trace the network traffic
-        server1 = startServer(new TestServerHandler(server1String, null), 0);
-        server2 = startServer(new TestServerHandler(server2String, null), 0);
-        factory = new SPDYClient.Factory(sslContextFactory);
-        factory.start();
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        stopServer(server1);
-        stopServer(server2);
-        if (proxy != null)
-        {
-            proxy.stop();
-            proxy.join();
-        }
-        factory.stop();
-    }
-
-    private void stopServer(Server server) throws Exception
-    {
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-    }
-
-    protected Server startServer(Handler handler, int port) throws Exception
-    {
-        QueuedThreadPool threadPool = new QueuedThreadPool(256);
-        threadPool.setName("upstreamServerQTP");
-        Server server = new Server(threadPool);
-        ServerConnector connector = new ServerConnector(server);
-        connector.setPort(port);
-        server.setHandler(handler);
-        server.addConnector(connector);
-        server.start();
-        return server;
-    }
-
-    private InetSocketAddress getServerAddress(Server server)
-    {
-        return new InetSocketAddress("localhost", ((ServerConnector)server.getConnectors()[0]).getLocalPort());
-    }
-
-    protected InetSocketAddress startProxy(InetSocketAddress server1, InetSocketAddress server2,
-                                           long proxyConnectorTimeout, long proxyEngineTimeout) throws Exception
-    {
-        QueuedThreadPool threadPool = new QueuedThreadPool(256);
-        threadPool.setName("proxyQTP");
-        proxy = new Server(threadPool);
-        ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector();
-        HttpClient httpClient = new HttpClient();
-        httpClient.start();
-        httpClient.setIdleTimeout(proxyEngineTimeout);
-        HTTPProxyEngine httpProxyEngine = new HTTPProxyEngine(httpClient);
-        proxyEngineSelector.putProxyEngine("http/1.1", httpProxyEngine);
-
-        proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("http/1.1",
-                server1.getHostName(), server1.getPort()));
-        // server2 will be available at two different ProxyServerInfos with different hosts
-        proxyEngineSelector.putProxyServerInfo("127.0.0.1", new ProxyEngineSelector.ProxyServerInfo("http/1.1",
-                server2.getHostName(), server2.getPort()));
-        proxyEngineSelector.putProxyServerInfo("127.0.0.2", new ProxyEngineSelector.ProxyServerInfo("http/1.1",
-                server2.getHostName(), server2.getPort()));
-
-        proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, new HttpConfiguration(), proxyEngineSelector, negotiator);
-        proxyConnector.setPort(0);
-        proxyConnector.setIdleTimeout(proxyConnectorTimeout);
-        proxy.addConnector(proxyConnector);
-        proxy.start();
-        return new InetSocketAddress("localhost", proxyConnector.getLocalPort());
-    }
-
-    @Test
-    public void testSimpleLoadTest() throws Exception
-    {
-        final InetSocketAddress proxyAddress = startProxy(getServerAddress(server1), getServerAddress(server2), 30000,
-                30000);
-
-        final int requestsPerClient = 50;
-
-        ExecutorService executorService = Executors.newFixedThreadPool(3);
-
-        Runnable client1 = createClientRunnable(proxyAddress, requestsPerClient, server1String, "localhost");
-        Runnable client2 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.1");
-        Runnable client3 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.2");
-
-        List<Future> futures = new ArrayList<>();
-
-        futures.add(executorService.submit(client1));
-        futures.add(executorService.submit(client2));
-        futures.add(executorService.submit(client3));
-
-        for (Future future : futures)
-        {
-            future.get(60, TimeUnit.SECONDS);
-        }
-    }
-
-    private Runnable createClientRunnable(final InetSocketAddress proxyAddress, final int requestsPerClient,
-                                          final String serverIdentificationString, final String serverHost)
-    {
-        Runnable client = new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-                    for (int i = 0; i < requestsPerClient; i++)
-                    {
-                        sendSingleClientRequest(proxyAddress, client, serverIdentificationString, serverHost);
-                    }
-                }
-                catch (InterruptedException | ExecutionException | TimeoutException e)
-                {
-                    e.printStackTrace();
-                    fail();
-                }
-            }
-        };
-        return client;
-    }
-
-    private void sendSingleClientRequest(InetSocketAddress proxyAddress, Session client, final String serverIdentificationString, String serverHost) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        final String data = UUID.randomUUID().toString();
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders(serverHost, proxyAddress.getPort(), version, "POST", "/");
-
-        Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                LOG.debug("Got reply: {}", replyInfo);
-                Fields headers = replyInfo.getHeaders();
-                assertThat("response comes from the given server", headers.get(serverIdentificationString),
-                        is(notNullValue()));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    LOG.debug("Got last dataFrame: {}", dataInfo);
-                    assertThat("received data matches send data", result.toString(), is(data));
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        stream.data(new StringDataInfo(data, true), new Callback.Adapter());
-
-        assertThat("reply has been received", replyLatch.await(15, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(15, TimeUnit.SECONDS), is(true));
-        LOG.debug("Successfully received response");
-    }
-
-    private class TestServerHandler extends DefaultHandler
-    {
-        private final String responseHeader;
-        private final byte[] responseData;
-
-        private TestServerHandler(String responseHeader, byte[] responseData)
-        {
-            this.responseHeader = responseHeader;
-            this.responseData = responseData;
-        }
-
-        @Override
-        public void handle(String target, Request baseRequest, HttpServletRequest request,
-                           HttpServletResponse response) throws IOException, ServletException
-        {
-            assertThat("Via Header is set", baseRequest.getHeader("X-Forwarded-For"), is(notNullValue()));
-            assertThat("X-Forwarded-For Header is set", baseRequest.getHeader("X-Forwarded-For"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Host Header is set", baseRequest.getHeader("X-Forwarded-Host"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Proto Header is set", baseRequest.getHeader("X-Forwarded-Proto"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Server Header is set", baseRequest.getHeader("X-Forwarded-Server"),
-                    is(notNullValue()));
-            baseRequest.setHandled(true);
-
-            IO.copy(request.getInputStream(), response.getOutputStream());
-
-            if (responseHeader != null)
-                response.addHeader(responseHeader, "bar");
-            if (responseData != null)
-                response.getOutputStream().write(responseData);
-        }
-    }
-
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java
deleted file mode 100644
index d129383..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java
+++ /dev/null
@@ -1,545 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.HttpChannel;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.DefaultHandler;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.PingInfo;
-import org.eclipse.jetty.spdy.api.PingResultInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.spdy.server.http.SPDYTestUtils;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.StdErrLog;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertThat;
-
-@RunWith(value = Parameterized.class)
-public abstract class ProxySPDYToHTTPTest
-{
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    private final short version;
-    private SPDYClient.Factory factory;
-    private Server server;
-    private Server proxy;
-    private ServerConnector proxyConnector;
-    private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory();
-
-    public ProxySPDYToHTTPTest(short version)
-    {
-        this.version = version;
-    }
-
-    protected InetSocketAddress startServer(Handler handler) throws Exception
-    {
-        server = new Server();
-        ServerConnector connector = new ServerConnector(server);
-        server.setHandler(handler);
-        server.addConnector(connector);
-        server.start();
-        return new InetSocketAddress("localhost", connector.getLocalPort());
-    }
-
-    protected InetSocketAddress startProxy(InetSocketAddress address, long proxyConnectorTimeout, long proxyEngineTimeout) throws Exception
-    {
-        proxy = new Server();
-        ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector();
-        HttpClient httpClient = new HttpClient();
-        httpClient.start();
-        httpClient.setIdleTimeout(proxyEngineTimeout);
-        HTTPProxyEngine httpProxyEngine = new HTTPProxyEngine(httpClient);
-        proxyEngineSelector.putProxyEngine("http/1.1", httpProxyEngine);
-        proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("http/1.1", address.getHostName(), address.getPort()));
-        proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector);
-        proxyConnector.setPort(0);
-        proxyConnector.setIdleTimeout(proxyConnectorTimeout);
-        proxy.addConnector(proxyConnector);
-        proxy.start();
-        return new InetSocketAddress("localhost", proxyConnector.getLocalPort());
-    }
-
-    @Before
-    public void init() throws Exception
-    {
-        factory = new SPDYClient.Factory(sslContextFactory);
-        factory.start();
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-        if (proxy != null)
-        {
-            proxy.stop();
-            proxy.join();
-        }
-        factory.stop();
-        ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
-    }
-
-    @Test
-    public void testSYNThenREPLY() throws Exception
-    {
-        final String header = "foo";
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-        headers.put(header, "bar");
-        headers.put("connection", "close");
-
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("Version header is set", headers.get(HTTPSPDYHeader.VERSION.name(version)), is(notNullValue()));
-                assertThat("Custom set header foo is set on response", headers.get(header), is(notNullValue()));
-                assertThat("HOP headers like connection are removed before forwarding",
-                        headers.get("connection"), is(nullValue()));
-                replyLatch.countDown();
-            }
-        });
-
-        assertThat("Reply is send to SPDY client", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSYNThenREPLYAndDATA() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        final String header = "foo";
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, data)), 30000, 30000);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-        headers.put(header, "bar");
-        headers.put("connection", "close");
-
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("Trailer header has been filtered by proxy", headers.get("trailer"),
-                        is(nullValue()));
-                assertThat("custom header exists in response", headers.get(header), is(notNullValue()));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    assertThat("received data matches send data", result.toByteArray(), is(data));
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testHttpServerCommitsResponseTwice() throws Exception
-    {
-        final long timeout = 1000;
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                response.addHeader("some response", "header");
-                response.flushBuffer();
-                try
-                {
-                    Thread.sleep(timeout * 2);
-                }
-                catch (InterruptedException e)
-                {
-                    e.printStackTrace();
-                }
-
-            }
-        }), 30000, timeout);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch resetLatch = new CountDownLatch(1);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                resetLatch.countDown();
-            }
-        });
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-        headers.put("connection", "close");
-
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyLatch.countDown();
-            }
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("stream is reset", resetLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testHttpServerSendsRedirect() throws Exception
-    {
-        InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                baseRequest.setHandled(true);
-                response.setStatus(HttpServletResponse.SC_FOUND);
-                response.setHeader("Location", "http://doesnot.exist");
-            }
-        }), 30000, 30000);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                assertThat("Status code is 302", replyInfo.getHeaders().get(HTTPSPDYHeader.STATUS.name(version)).getValue(),
-                        is("302"));
-                assertThat("Location header has been received", replyInfo.getHeaders().get("Location"), is(notNullValue()));
-                replyLatch.countDown();
-            }
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSYNWithRequestContentThenREPLYAndDATA() throws Exception
-    {
-        final String data = "0123456789ABCDEF";
-        final String header = "foo";
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/");
-        headers.put(header, "bar");
-        headers.put("connection", "close");
-
-        Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("custom header exists in response", headers.get(header), is(notNullValue()));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    assertThat("received data matches send data", data, is(result.toString()));
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        stream.data(new StringDataInfo(data, true), new Callback.Adapter());
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSYNWithSplitRequestContentThenREPLYAndDATA() throws Exception
-    {
-        final String data = "0123456789ABCDEF";
-        final String data2 = "ABCDEF";
-        final String header = "foo";
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(header, null)), 30000, 30000);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/");
-        headers.put(header, "bar");
-        headers.put("connection", "close");
-
-        Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("custom header exists in response", headers.get(header), is(notNullValue()));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    assertThat("received data matches send data", result.toString(), is(data + data2));
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        stream.data(new StringDataInfo(data, false), new Callback.Adapter());
-        stream.data(new StringDataInfo(data2, true), new Callback.Adapter());
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testClientTimeout() throws Exception
-    {
-        long timeout = 1000;
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new TestServerHandler(null, null)), timeout, 30000);
-
-        final CountDownLatch goAwayLatch = new CountDownLatch(1);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayReceivedInfo)
-            {
-                goAwayLatch.countDown();
-            }
-        });
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/");
-        ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
-        client.syn(new SynInfo(headers, false), null);
-        assertThat("goAway has been received by proxy", goAwayLatch.await(2 * timeout, TimeUnit.MILLISECONDS),
-                is(true));
-    }
-
-    @Test
-    public void testServerTimeout() throws Exception
-    {
-        final int timeout = 1000;
-        final String header = "foo";
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new DefaultHandler()
-        {
-            @Override
-            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
-            {
-                try
-                {
-                    Thread.sleep(2 * timeout);
-                }
-                catch (InterruptedException e)
-                {
-                    e.printStackTrace();
-                }
-            }
-        }), 30000, timeout);
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "POST", "/");
-        headers.put(header, "bar");
-        headers.put("connection", "close");
-
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("status is 504", headers.get(HTTPSPDYHeader.STATUS.name(version)).getValue(), is("504"));
-                replyLatch.countDown();
-            }
-
-        });
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testPING() throws Exception
-    {
-        // PING is per hop, and it does not carry the information to which server to ping to
-        // We just verify that it works
-
-        InetSocketAddress proxyAddress = startProxy(startServer(null), 30000, 30000);
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch pingLatch = new CountDownLatch(1);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onPing(Session session, PingResultInfo pingInfo)
-            {
-                pingLatch.countDown();
-            }
-        });
-
-        client.ping(new PingInfo(5, TimeUnit.SECONDS));
-
-        Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    private class TestServerHandler extends DefaultHandler
-    {
-        private final String responseHeader;
-        private final byte[] responseData;
-
-        private TestServerHandler(String responseHeader, byte[] responseData)
-        {
-            this.responseHeader = responseHeader;
-            this.responseData = responseData;
-        }
-
-        @Override
-        public void handle(String target, Request baseRequest, HttpServletRequest request,
-                           HttpServletResponse response) throws IOException, ServletException
-        {
-            assertThat("Via Header is set", baseRequest.getHeader("X-Forwarded-For"), is(notNullValue()));
-            assertThat("X-Forwarded-For Header is set", baseRequest.getHeader("X-Forwarded-For"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Host Header is set", baseRequest.getHeader("X-Forwarded-Host"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Proto Header is set", baseRequest.getHeader("X-Forwarded-Proto"),
-                    is(notNullValue()));
-            assertThat("X-Forwarded-Server Header is set", baseRequest.getHeader("X-Forwarded-Server"),
-                    is(notNullValue()));
-            baseRequest.setHandled(true);
-            BufferedReader bufferedReader = request.getReader();
-            int read;
-            while ((read = bufferedReader.read()) != -1)
-                response.getOutputStream().write(read);
-
-            // add some hop header to be removed on the proxy
-            response.addHeader("Trailer", "bla");
-            if (responseHeader != null)
-                response.addHeader(responseHeader, "bar");
-            if (responseData != null)
-                response.getOutputStream().write(responseData);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java
deleted file mode 100644
index 6f1a596..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.io.ByteArrayOutputStream;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnector;
-import org.eclipse.jetty.spdy.server.http.SPDYTestUtils;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static junit.framework.Assert.fail;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-@RunWith(value = Parameterized.class)
-public abstract class ProxySPDYToSPDYLoadTest
-{
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    private final short version;
-    private static final String UUID_HEADER_NAME = "uuidHeader";
-    private static final String SERVER_ID_HEADER = "serverId";
-    private SPDYClient.Factory factory;
-    private Server server;
-    private Server proxy;
-    private ServerConnector proxyConnector;
-    private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory();
-
-    public ProxySPDYToSPDYLoadTest(short version)
-    {
-        this.version = version;
-    }
-
-    protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
-    {
-        server = new Server();
-        SPDYServerConnector serverConnector = new SPDYServerConnector(server, sslContextFactory, listener);
-        serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener));
-        serverConnector.setPort(0);
-        server.addConnector(serverConnector);
-        server.start();
-        return new InetSocketAddress("localhost", serverConnector.getLocalPort());
-    }
-
-    protected InetSocketAddress startProxy(InetSocketAddress server1, InetSocketAddress server2) throws Exception
-    {
-        proxy = new Server();
-        ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector();
-
-        SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory);
-        proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine);
-
-        proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version,
-                "localhost", server1.getPort()));
-        // server2 will be available at two different ProxyServerInfos with different hosts
-        proxyEngineSelector.putProxyServerInfo("127.0.0.1", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version,
-                "127.0.0.1", server2.getPort()));
-        // ProxyServerInfo is mapped to 127.0.0.2 in the proxyEngineSelector. However to be able to connect the
-        // ProxyServerInfo contains 127.0.0.1 as target host
-        proxyEngineSelector.putProxyServerInfo("127.0.0.2", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version,
-                "127.0.0.1", server2.getPort()));
-
-        proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector);
-        proxyConnector.setPort(0);
-        proxy.addConnector(proxyConnector);
-        proxy.start();
-        return new InetSocketAddress("localhost", proxyConnector.getLocalPort());
-    }
-
-    @Before
-    public void init() throws Exception
-    {
-        factory = new SPDYClient.Factory(sslContextFactory);
-        factory.start();
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        server.stop();
-        server.join();
-        proxy.stop();
-        proxy.join();
-        factory.stop();
-    }
-
-    @Test
-    public void testSimpleLoadTest() throws Exception
-    {
-        String server1String = "server1";
-        String server2String = "server2";
-
-        InetSocketAddress server1 = startServer(new TestServerFrameListener(server1String));
-        InetSocketAddress server2 = startServer(new TestServerFrameListener(server2String));
-        final InetSocketAddress proxyAddress = startProxy(server1, server2);
-
-        final int requestsPerClient = 50;
-
-        ExecutorService executorService = Executors.newFixedThreadPool(3);
-
-        Runnable client1 = createClientRunnable(proxyAddress, requestsPerClient, server1String, "localhost");
-        Runnable client2 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.1");
-        Runnable client3 = createClientRunnable(proxyAddress, requestsPerClient, server2String, "127.0.0.2");
-
-        List<Future> futures = new ArrayList<>();
-
-        futures.add(executorService.submit(client1));
-        futures.add(executorService.submit(client2));
-        futures.add(executorService.submit(client3));
-
-        for (Future future : futures)
-        {
-            future.get(60, TimeUnit.SECONDS);
-        }
-    }
-
-    private Runnable createClientRunnable(final InetSocketAddress proxyAddress, final int requestsPerClient,
-                                          final String serverIdentificationString, final String serverHost)
-    {
-        Runnable client = new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                try
-                {
-                    Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-                    for (int i = 0; i < requestsPerClient; i++)
-                    {
-                        sendSingleClientRequest(proxyAddress, client, serverIdentificationString, serverHost);
-                    }
-                }
-                catch (InterruptedException | ExecutionException | TimeoutException e)
-                {
-                    fail();
-                    e.printStackTrace();
-                }
-            }
-        };
-        return client;
-    }
-
-    private void sendSingleClientRequest(InetSocketAddress proxyAddress, Session client, final String serverIdentificationString, String serverHost) throws ExecutionException, InterruptedException, TimeoutException
-    {
-        final String uuid = UUID.randomUUID().toString();
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-
-        Fields headers = SPDYTestUtils.createHeaders(serverHost, proxyAddress.getPort(), version, "POST", "/");
-        headers.add(UUID_HEADER_NAME, uuid);
-
-        Stream stream = client.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                assertThat("uuid matches expected uuid", headers.get(UUID_HEADER_NAME).getValue(), is(uuid));
-                assertThat("response comes from the given server", headers.get(SERVER_ID_HEADER).getValue(),
-                        is(serverIdentificationString));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    assertThat("received data matches send data", uuid, is(result.toString()));
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        stream.data(new StringDataInfo(uuid, true), new Callback.Adapter());
-
-        assertThat("reply has been received", replyLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("data has been received", dataLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private class TestServerFrameListener extends ServerSessionFrameListener.Adapter
-    {
-        private String serverId;
-
-        private TestServerFrameListener(String serverId)
-        {
-            this.serverId = serverId;
-        }
-
-        @Override
-        public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-        {
-            Fields requestHeaders = synInfo.getHeaders();
-            Assert.assertNotNull(requestHeaders.get("via"));
-            Fields.Field uuidHeader = requestHeaders.get(UUID_HEADER_NAME);
-            Assert.assertNotNull(uuidHeader);
-
-            Fields responseHeaders = new Fields();
-            responseHeaders.put(UUID_HEADER_NAME, uuidHeader.getValue());
-            responseHeaders.put(SERVER_ID_HEADER, serverId);
-            stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
-            return new StreamFrameListener.Adapter()
-            {
-                @Override
-                public void onData(Stream stream, DataInfo dataInfo)
-                {
-                    stream.data(dataInfo, new Callback.Adapter());
-                }
-            };
-        }
-    }
-
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java
deleted file mode 100644
index a74d54b..0000000
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java
+++ /dev/null
@@ -1,553 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import java.io.ByteArrayOutputStream;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.PingInfo;
-import org.eclipse.jetty.spdy.api.PingResultInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.spdy.http.HTTPSPDYHeader;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnector;
-import org.eclipse.jetty.spdy.server.http.SPDYTestUtils;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-@RunWith(value = Parameterized.class)
-public abstract class ProxySPDYToSPDYTest
-{
-    @Parameterized.Parameters
-    public static Collection<Short[]> parameters()
-    {
-        return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3});
-    }
-
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    private final short version;
-    private SPDYClient.Factory factory;
-    private Server server;
-    private Server proxy;
-    private ServerConnector proxyConnector;
-    private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory();
-
-    public ProxySPDYToSPDYTest(short version)
-    {
-        this.version = version;
-    }
-
-    protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
-    {
-        server = new Server();
-        SPDYServerConnector serverConnector = new SPDYServerConnector(server, sslContextFactory, listener);
-        serverConnector.addConnectionFactory(new SPDYServerConnectionFactory(version, listener));
-        serverConnector.setPort(0);
-        server.addConnector(serverConnector);
-        server.start();
-        return new InetSocketAddress("localhost", serverConnector.getLocalPort());
-    }
-
-    protected InetSocketAddress startProxy(InetSocketAddress address) throws Exception
-    {
-        proxy = new Server();
-        ProxyEngineSelector proxyEngineSelector = new ProxyEngineSelector();
-        SPDYProxyEngine spdyProxyEngine = new SPDYProxyEngine(factory);
-        proxyEngineSelector.putProxyEngine("spdy/" + version, spdyProxyEngine);
-        proxyEngineSelector.putProxyServerInfo("localhost", new ProxyEngineSelector.ProxyServerInfo("spdy/" + version, address.getHostName(), address.getPort()));
-        proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector);
-        proxyConnector.setPort(0);
-        proxy.addConnector(proxyConnector);
-        proxy.start();
-        return new InetSocketAddress("localhost", proxyConnector.getLocalPort());
-    }
-
-    @Before
-    public void init() throws Exception
-    {
-        factory = new SPDYClient.Factory(sslContextFactory);
-        factory.start();
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-        if (proxy != null)
-        {
-            proxy.stop();
-            proxy.join();
-        }
-        factory.stop();
-    }
-
-    @Test
-    public void testSYNThenREPLY() throws Exception
-    {
-        final String header = "foo";
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-                Assert.assertNotNull(requestHeaders.get(header));
-
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(header, "baz");
-                stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter());
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-        headers.put(header, "bar");
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                Assert.assertNotNull(headers.get(header));
-                replyLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-@Test
-    public void testSYNThenRSTFromUpstreamServer() throws Exception
-    {
-        final String header = "foo";
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-                Assert.assertNotNull(requestHeaders.get(header));
-                stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch resetLatch = new CountDownLatch(1);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                resetLatch.countDown();
-            }
-        });
-
-        Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
-        headers.put(header, "bar");
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter());
-
-        assertThat("reset is received by client", resetLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSYNThenREPLYAndDATA() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        final String header = "foo";
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-                Assert.assertNotNull(requestHeaders.get(header));
-
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(header, "baz");
-                stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
-                stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort());
-        headers.put(header, "bar");
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            private final ByteArrayOutputStream result = new ByteArrayOutputStream();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = replyInfo.getHeaders();
-                Assert.assertNotNull(headers.get(header));
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                result.write(dataInfo.asBytes(true), 0, dataInfo.length());
-                if (dataInfo.isClose())
-                {
-                    Assert.assertArrayEquals(data, result.toByteArray());
-                    dataLatch.countDown();
-                }
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSYNThenSPDYPushIsReceived() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
-
-                Fields pushHeaders = new Fields();
-                pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
-                stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream pushStream)
-                    {
-                        pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                    }
-                });
-
-                stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch pushSynLatch = new CountDownLatch(1);
-        final CountDownLatch pushDataLatch = new CountDownLatch(1);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort());
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                pushSynLatch.countDown();
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    dataLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushSynLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSYNThenSPDYNestedPushIsReceived() throws Exception
-    {
-        final byte[] data = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Fields responseHeaders = new Fields();
-                responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
-                responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK");
-                stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter());
-
-                final Fields pushHeaders = new Fields();
-                pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push");
-                stream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream pushStream)
-                    {
-                        pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/nestedpush");
-                        pushStream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>()
-                        {
-                            @Override
-                            public void succeeded(Stream pushStream)
-                            {
-                                pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/anothernestedpush");
-                                pushStream.push(new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>()
-                                {
-                                    @Override
-                                    public void succeeded(Stream pushStream)
-                                    {
-                                        pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                                    }
-                                });
-                                pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                            }
-                        });
-                        pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-                    }
-                });
-
-                stream.data(new BytesDataInfo(data, true), new Callback.Adapter());
-
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch pushSynLatch = new CountDownLatch(3);
-        final CountDownLatch pushDataLatch = new CountDownLatch(3);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, null);
-
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort());
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter()
-        {
-            // onPush for 1st push stream
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                pushSynLatch.countDown();
-                return new StreamFrameListener.Adapter()
-                {
-                    // onPush for 2nd nested push stream
-                    @Override
-                    public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-                    {
-                        pushSynLatch.countDown();
-                        return new Adapter()
-                        {
-                            // onPush for 3rd nested push stream
-                            @Override
-                            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-                            {
-                                pushSynLatch.countDown();
-                                return new Adapter()
-                                {
-                                    @Override
-                                    public void onData(Stream stream, DataInfo dataInfo)
-                                    {
-                                        dataInfo.consume(dataInfo.length());
-                                        if (dataInfo.isClose())
-                                            pushDataLatch.countDown();
-                                    }
-                                };
-                            }
-
-                            @Override
-                            public void onData(Stream stream, DataInfo dataInfo)
-                            {
-                                dataInfo.consume(dataInfo.length());
-                                if (dataInfo.isClose())
-                                    pushDataLatch.countDown();
-                            }
-                        };
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consume(dataInfo.length());
-                        if (dataInfo.isClose())
-                            pushDataLatch.countDown();
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    dataLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushSynLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testPING() throws Exception
-    {
-        // PING is per hop, and it does not carry the information to which server to ping to
-        // We just verify that it works
-
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch pingLatch = new CountDownLatch(1);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onPing(Session session, PingResultInfo pingInfo)
-            {
-                pingLatch.countDown();
-            }
-        });
-
-        client.ping(new PingInfo(5, TimeUnit.SECONDS));
-
-        Assert.assertTrue(pingLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSYNThenReset() throws Exception
-    {
-        InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(synInfo.isClose());
-                Fields requestHeaders = synInfo.getHeaders();
-                Assert.assertNotNull(requestHeaders.get("via"));
-
-                stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
-
-                return null;
-            }
-        }));
-        proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
-
-        final CountDownLatch resetLatch = new CountDownLatch(1);
-        Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                resetLatch.countDown();
-            }
-        });
-
-        Fields headers = new Fields();
-        headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort());
-        client.syn(new SynInfo(headers, true), null);
-
-        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
-
-        client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/resources/big_script.js b/jetty-spdy/spdy-http-server/src/test/resources/big_script.js
deleted file mode 100644
index 37202fd..0000000
--- a/jetty-spdy/spdy-http-server/src/test/resources/big_script.js
+++ /dev/null
@@ -1,791 +0,0 @@
-//----------------------------------------------------------------------
-//
-// Silly / Pointless Javascript to test GZIP compression.
-//
-//----------------------------------------------------------------------
-
-var LOGO = {
-  dat: [
-    0x50, 0x89, 0x47, 0x4e, 0x0a, 0x0d, 0x0a, 0x1a, 0x00, 0x00, 0x0d, 0x00, 0x48, 0x49, 0x52, 0x44,
-    0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x78, 0x00, 0x06, 0x08, 0x00, 0x00, 0x2a, 0x00, 0x21, 0x96,
-    0x00, 0x0f, 0x00, 0x00, 0x73, 0x04, 0x49, 0x42, 0x08, 0x54, 0x08, 0x08, 0x7c, 0x08, 0x64, 0x08,
-    0x00, 0x88, 0x00, 0x00, 0x70, 0x09, 0x59, 0x48, 0x00, 0x73, 0x04, 0x00, 0x00, 0x27, 0x04, 0x00,
-    0x01, 0x27, 0x4f, 0xd9, 0x80, 0x1d, 0x00, 0x00, 0x19, 0x00, 0x45, 0x74, 0x74, 0x58, 0x6f, 0x53,
-    0x74, 0x66, 0x61, 0x77, 0x65, 0x72, 0x77, 0x00, 0x77, 0x77, 0x69, 0x2e, 0x6b, 0x6e, 0x63, 0x73,
-    0x70, 0x61, 0x2e, 0x65, 0x72, 0x6f, 0x9b, 0x67, 0x3c, 0xee, 0x00, 0x1a, 0x20, 0x00, 0x49, 0x00,
-    0x41, 0x44, 0x78, 0x54, 0xed, 0x9c, 0x79, 0x9d, 0x1c, 0xd8, 0x95, 0x55, 0x3f, 0xff, 0xfb, 0xa7,
-    0xb2, 0xdd, 0x24, 0xef, 0x24, 0x81, 0x81, 0x2c, 0x20, 0x40, 0xd5, 0x91, 0x8b, 0xb0, 0x3f, 0xbb,
-    0x1d, 0x04, 0x54, 0x1c, 0x46, 0x74, 0x17, 0x18, 0xd1, 0x98, 0x19, 0xd1, 0x05, 0x11, 0x37, 0xf4,
-    0xe2, 0x8f, 0xcc, 0xb8, 0x28, 0x8c, 0x82, 0x02, 0x22, 0x8c, 0xe0, 0xe8, 0xe2, 0x86, 0x02, 0x88,
-    0x8e, 0xa2, 0x08, 0xe8, 0x42, 0x42, 0x4b, 0x08, 0xc2, 0xc8, 0x12, 0x12, 0xf6, 0x42, 0x7d, 0x90,
-    0xf7, 0x7d, 0x3e, 0xee, 0x47, 0xf3, 0x77, 0x75, 0xeb, 0x6a, 0xdf, 0x7e, 0xee, 0xea, 0xab, 0x7b,
-    0xdc, 0x93, 0xf3, 0xcf, 0xd0, 0xf0, 0xa9, 0x55, 0x53, 0xae, 0x6f, 0x5d, 0x3d, 0xd5, 0x9e, 0xf7,
-    0xee, 0x7b, 0x8a, 0xf9, 0xe2, 0xaa, 0x38, 0x70, 0x0e, 0x1c, 0xc3, 0x87, 0x99, 0x2e, 0x2f, 0xb4,
-    0xe1, 0xc0, 0x38, 0x70, 0x8e, 0x1c, 0x11, 0x83, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1,
-    0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87,
-    0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d,
-    0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48, 0x80, 0xe7,
-    0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3, 0x01, 0x48,
-    0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0xe7, 0x01, 0x1d, 0x80, 0x87, 0x0e, 0xe1, 0xc3,
-    0x01, 0x48, 0x80, 0xe7, 0x0e, 0x1d, 0xc3, 0x87, 0x48, 0xe1, 0x96, 0x81, 0x2f, 0xb4, 0x44, 0x40,
-    0x2c, 0x3a, 0xe9, 0x98, 0xa7, 0x55, 0xe1, 0x3a, 0x38, 0x70, 0x8e, 0x1c, 0x42, 0x26, 0xf0, 0xd2,
-    0x22, 0x4b, 0x16, 0x32, 0x0c, 0xb8, 0x02, 0xb8, 0xde, 0x38, 0xc9, 0x82, 0xe0, 0x4e, 0x80, 0xbf,
-    0xa9, 0x4f, 0xbf, 0x6a, 0x7b, 0x05, 0x88, 0xb1, 0x6c, 0xc8, 0xc3, 0xe0, 0xfb, 0xc0, 0xd1, 0x81,
-    0xcd, 0x86, 0x81, 0xe5, 0xc0, 0xe5, 0xab, 0xdf, 0x02, 0xea, 0xb6, 0xc3, 0x0e, 0x1c, 0xa3, 0x87,
-    0x44, 0x6e, 0x12, 0x64, 0x29, 0x70, 0x41, 0xf0, 0x7a, 0x60, 0xaf, 0xc2, 0x01, 0x77, 0x80, 0xf3,
-    0x55, 0x9b, 0x21, 0xf5, 0xf6, 0x0b, 0x81, 0xba, 0x81, 0xc7, 0x54, 0x5b, 0x77, 0xf5, 0xbf, 0x09,
-    0xd9, 0xeb, 0xed, 0xb7, 0x45, 0x80, 0x0b, 0x24, 0x04, 0x2c, 0x5b, 0x66, 0xec, 0x35, 0x28, 0xf1,
-    0xd7, 0xf0, 0xba, 0xaa, 0xb6, 0xd5, 0x11, 0x61, 0x23, 0x79, 0x27, 0xf0, 0x76, 0xdb, 0x5e, 0x81,
-    0x27, 0x3c, 0xc3, 0xfc, 0x6c, 0x14, 0x1c, 0x3b, 0xc7, 0x0e, 0x10, 0xa0, 0x23, 0x91, 0x67, 0x81,
-    0x91, 0x81, 0x9e, 0x75, 0x13, 0xaa, 0x4b, 0x38, 0x17, 0x55, 0xb2, 0x5b, 0x05, 0xd7, 0xa3, 0x9c,
-    0x0b, 0xaa, 0x7e, 0x93, 0x8d, 0x31, 0xe0, 0x39, 0x48, 0x2b, 0xf9, 0xc7, 0x9c, 0x02, 0xbc, 0x0b,
-    0xb6, 0xdb, 0x62, 0xd1, 0xe3, 0xa7, 0xdb, 0x66, 0x8b, 0x76, 0x03, 0xb4, 0xa5, 0x37, 0xdb, 0x64,
-    0x70, 0xe1, 0x06, 0x38, 0x2d, 0xcb, 0xef, 0xd4, 0x01, 0x0c, 0x01, 0x86, 0x8b, 0xf7, 0xab, 0x48,
-    0x7b, 0x25, 0x81, 0x43, 0x0d, 0x5f, 0x5e, 0xc2, 0x34, 0x84, 0x80, 0xe6, 0x50, 0x3f, 0x20, 0xfa,
-    0x98, 0x19, 0xfa, 0xfd, 0xd7, 0xc4, 0x0c, 0x9c, 0x96, 0x55, 0x92, 0x3c, 0x0b, 0x43, 0x3d, 0xe5,
-    0xcc, 0x33, 0x8c, 0x1a, 0x0e, 0x65, 0xab, 0x30, 0x31, 0xb4, 0x4d, 0xb9, 0xd6, 0x98, 0xb6, 0x6e,
-    0xf3, 0xef, 0x9f, 0x6a, 0xba, 0xb2, 0xfc, 0xb7, 0xc7, 0xa3, 0xc8, 0x88, 0x55, 0x04, 0x62, 0xdd,
-    0xa8, 0xd4, 0xe1, 0xc3, 0xd4, 0x70, 0x71, 0x40, 0xee, 0x7a, 0xd2, 0x82, 0xb0, 0xf6, 0x30, 0x8c,
-    0x58, 0x6b, 0x36, 0xb2, 0x55, 0x72, 0x81, 0x4f, 0xfd, 0x4d, 0x88, 0xe5, 0x34, 0xee, 0x69, 0xbc,
-    0x63, 0x38, 0xd6, 0xf6, 0x16, 0xf4, 0xd8, 0xd8, 0xb6, 0x57, 0x38, 0x77, 0xa8, 0x50, 0x78, 0x72,
-    0x56, 0x2c, 0xb0, 0x1d, 0xb4, 0x88, 0xa7, 0x03, 0xb6, 0x95, 0x1e, 0xa7, 0xe5, 0x97, 0x9f, 0x9a,
-    0x33, 0x0f, 0x73, 0x6a, 0xba, 0xdb, 0x9f, 0x02, 0x79, 0x3c, 0x7f, 0xb7, 0x34, 0xd7, 0x06, 0xa3,
-    0x39, 0xe3, 0xbf, 0xdb, 0xdd, 0x71, 0x76, 0x94, 0x9f, 0x2e, 0x66, 0xd8, 0xe0, 0xd4, 0xaf, 0x95,
-    0x70, 0xf4, 0xab, 0xeb, 0xfe, 0x7d, 0x87, 0x5d, 0xce, 0x03, 0x3b, 0x01, 0x8e, 0x1c, 0xe4, 0x66,
-    0xff, 0x5a, 0xa7, 0xc6, 0x6d, 0x0e, 0x8b, 0xe3, 0xdb, 0x53, 0xfd, 0x07, 0x02, 0xe5, 0xfc, 0x70,
-    0xbd, 0xc2, 0x07, 0x7e, 0x53, 0xbc, 0xab, 0x55, 0xc4, 0x39, 0xea, 0x6b, 0xa7, 0xb1, 0x89, 0xc0,
-    0xf6, 0x8b, 0x1d, 0xfa, 0xa7, 0x70, 0x56, 0xaa, 0xf8, 0x74, 0xb0, 0x95, 0x82, 0x1d, 0x15, 0x3e,
-    0x24, 0x2f, 0xc0, 0x0a, 0x73, 0x31, 0xfb, 0xcc, 0x65, 0xff, 0xe4, 0x4f, 0xbb, 0xc2, 0x1a, 0x96,
-    0x1a, 0x37, 0xe0, 0x25, 0xcf, 0x80, 0x69, 0x1a, 0x77, 0xfe, 0xdd, 0xcf, 0x78, 0x13, 0xf2, 0x16,
-    0x32, 0xc0, 0x46, 0xe3, 0x0e, 0x1d, 0x23, 0x87, 0x22, 0x21, 0x38, 0x72, 0x49, 0x70, 0x7b, 0x69,
-    0x46, 0x68, 0xc4, 0xf8, 0x64, 0xe4, 0x94, 0x03, 0xb7, 0x7b, 0xb3, 0xf5, 0x27, 0xa2, 0x6f, 0xe0,
-    0xb6, 0x2b, 0x45, 0x77, 0xef, 0x7b, 0xc7, 0xab, 0x83, 0xde, 0x72, 0x3b, 0xdf, 0x3c, 0xb0, 0x15,
-    0x3c, 0xb7, 0x09, 0xd1, 0xd8, 0x8a, 0xc0, 0x76, 0x47, 0x01, 0x63, 0x34, 0xd6, 0x4e, 0xc1, 0xb8,
-    0x16, 0x97, 0x3a, 0x44, 0x8f, 0x25, 0x37, 0x19, 0xe5, 0x1a, 0xd2, 0xac, 0xb1, 0x87, 0xc2, 0x2d,
-    0x21, 0xcc, 0x6f, 0x66, 0xde, 0xfb, 0xb2, 0xbc, 0x2b, 0xb8, 0xbb, 0xf0, 0xa8, 0x97, 0x1e, 0xea,
-    0x46, 0xa3, 0x0e, 0x1d, 0xa3, 0x87, 0x3e, 0x36, 0x2f, 0x8d, 0xfb, 0x1a, 0x43, 0xa1, 0x19, 0x5a,
-    0x22, 0xdf, 0x4e, 0x89, 0xfd, 0x70, 0xbe, 0xfa, 0xae, 0xf0, 0xcd, 0x1b, 0xeb, 0xda, 0xef, 0x0d,
-    0x66, 0xfa, 0x13, 0xa2, 0xb1, 0x14, 0x07, 0x3d, 0x74, 0x1c, 0xa7, 0xc0, 0x37, 0x9b, 0xd2, 0xff,
-    0xc0, 0xfc, 0x38, 0x08, 0xcc, 0x0f, 0x6e, 0x37, 0x87, 0xd4, 0x1c, 0x88, 0x1c, 0x03, 0xda, 0x52,
-    0x63, 0x3e, 0x96, 0x44, 0x7f, 0x64, 0xe4, 0xea, 0xd8, 0x2c, 0x27, 0x9b, 0x4c, 0x1f, 0x9f, 0x6e,
-    0xd8, 0x6b, 0x01, 0xe4, 0x88, 0x83, 0x0d, 0x1c, 0x0e, 0x5c, 0x07, 0x9c, 0xff, 0x46, 0x0a, 0x54,
-    0xc2, 0x6c, 0x32, 0x5b, 0x67, 0xf1, 0x46, 0x53, 0x64, 0x44, 0x5e, 0x08, 0xe1, 0xe2, 0x62, 0xdf,
-    0xe9, 0x7e, 0x37, 0x5b, 0x08, 0xf0, 0x15, 0xf0, 0x8d, 0x55, 0x9e, 0x84, 0x8e, 0x1c, 0x22, 0x30,
-    0x1e, 0x32, 0x48, 0xf8, 0xbb, 0x69, 0xe0, 0x45, 0x43, 0xaa, 0x8d, 0x93, 0xff, 0x46, 0x57, 0x77,
-    0x67, 0x8e, 0x03, 0x3a, 0x8e, 0x03, 0xc0, 0x15, 0x9b, 0x7f, 0x37, 0xb2, 0x4f, 0x77, 0x79, 0x9e,
-    0x08, 0xc1, 0x1a, 0xe3, 0xee, 0xe0, 0x27, 0x44, 0xd9, 0x29, 0xe5, 0xaf, 0x75, 0x4b, 0x1e, 0x50,
-    0x8e, 0x09, 0x98, 0x9e, 0xc2, 0x61, 0xb3, 0x34, 0xc1, 0x23, 0xdd, 0xae, 0xda, 0xca, 0x03, 0x17,
-    0x6a, 0x37, 0xaa, 0x91, 0x35, 0xee, 0x34, 0x6a, 0x30, 0x4a, 0x3c, 0xfc, 0xfc, 0xc2, 0x3f, 0xa8,
-    0x7e, 0x14, 0xe7, 0x06, 0x07, 0x80, 0x88, 0x85, 0x1b, 0xfc, 0x59, 0xf0, 0x3a, 0xcc, 0x30, 0xde,
-    0x88, 0x17, 0xa7, 0xc8, 0xf5, 0x55, 0x8d, 0x5b, 0xb1, 0x3e, 0xcc, 0x88, 0x8b, 0xc2, 0x8c, 0xf8,
-    0xf4, 0x6a, 0xab, 0xb9, 0x7a, 0xf0, 0xf5, 0xe0, 0xf2, 0x22, 0x55, 0x5e, 0x6c, 0xdd, 0xae, 0xd1,
-    0xff, 0x63, 0x9f, 0xe4, 0xb2, 0xf0, 0x01, 0x88, 0xef, 0x78, 0x56, 0xb8, 0x4f, 0x0e, 0xa0, 0x98,
-    0xb5, 0xfa, 0xe8, 0xe8, 0x1b, 0xf7, 0xe6, 0x55, 0xeb, 0x7f, 0x17, 0xb6, 0xfa, 0x37, 0xb5, 0xad,
-    0x69, 0xc3, 0x04, 0x2d, 0x22, 0x2d, 0x80, 0x33, 0xa5, 0x09, 0x1b, 0x6d, 0xe7, 0xe1, 0x4f, 0x15,
-    0xb2, 0x05, 0x21, 0x9f, 0x47, 0x1d, 0x70, 0x14, 0x67, 0xc0, 0x30, 0x8f, 0xe7, 0xdf, 0xe7, 0x99,
-    0x70, 0x1c, 0x44, 0x62, 0x38, 0xe4, 0x6a, 0xe0, 0x3a, 0xec, 0xf0, 0x5f, 0xc1, 0x3a, 0x8b, 0x37,
-    0x39, 0xc8, 0xce, 0x06, 0x13, 0x7d, 0x9d, 0x76, 0x89, 0x6f, 0x80, 0xf3, 0x52, 0xdb, 0xeb, 0xb0,
-    0x8f, 0xd8, 0x91, 0x10, 0xc0, 0x61, 0xfc, 0x27, 0xae, 0xfb, 0x6c, 0x39, 0x89, 0xf0, 0x00, 0x50,
-    0x74, 0xcf, 0xf9, 0xe6, 0xae, 0xd3, 0xef, 0x80, 0x04, 0xdb, 0x65, 0xdc, 0xde, 0xca, 0x5d, 0x73,
-    0x7e, 0x05, 0x23, 0xbb, 0x6f, 0x60, 0x70, 0x1b, 0xa2, 0x47, 0xf8, 0x93, 0x39, 0xb0, 0xb6, 0x02,
-    0x7e, 0x1f, 0xa2, 0x7e, 0xe6, 0x29, 0xcb, 0x7f, 0xbb, 0xbf, 0xe0, 0x55, 0xe1, 0xb4, 0x3b, 0x66,
-    0x05, 0x1e, 0x7e, 0x60, 0x01, 0xd0, 0x53, 0xaf, 0x35, 0xd5, 0x8d, 0x46, 0x18, 0x1e, 0x13, 0xfc,
-    0xf7, 0xbe, 0x3d, 0xa1, 0x3e, 0x63, 0xdc, 0xfe, 0xec, 0x1b, 0xce, 0x1c, 0x81, 0xa4, 0x67, 0xcf,
-    0x99, 0x71, 0x9b, 0xc5, 0xdb, 0x4a, 0xf1, 0x59, 0x3f, 0x9e, 0xf4, 0x93, 0x02, 0x15, 0x30, 0xeb,
-    0x9a, 0x66, 0xe6, 0xb5, 0x00, 0x38, 0x02, 0xb8, 0x5b, 0x18, 0x38, 0xda, 0x4c, 0x7f, 0xb3, 0x0b,
-    0x26, 0x86, 0x8d, 0x1d, 0x46, 0x46, 0x37, 0xbf, 0x6a, 0xa9, 0x85, 0x4f, 0x2f, 0xc3, 0xd7, 0xaf,
-    0xd7, 0xde, 0xf4, 0x37, 0x2a, 0x12, 0x75, 0x5d, 0xaa, 0xab, 0x26, 0x76, 0x89, 0x3a, 0xf4, 0x8f,
-    0x70, 0x1c, 0x19, 0x3a, 0x56, 0xd0, 0x82, 0x47, 0x32, 0x22, 0x38, 0x0e, 0xb4, 0xae, 0xca, 0x7d,
-    0x2c, 0xf0, 0xf3, 0x86, 0x58, 0xaf, 0x99, 0xd2, 0x4f, 0x67, 0x02, 0x70, 0x8d, 0xd8, 0x07, 0x7e,
-    0x79, 0x47, 0xda, 0x04, 0x81, 0x9e, 0xaf, 0xed, 0x89, 0x1d, 0xa5, 0xc9, 0x8b, 0xda, 0xf3, 0x3b,
-    0xb2, 0x9c, 0xf0, 0x38, 0x1e, 0xde, 0x60, 0xd3, 0x81, 0x13, 0xf5, 0x11, 0x87, 0xf5, 0xf0, 0x77,
-    0x84, 0xc9, 0x9e, 0x99, 0x79, 0x49, 0x73, 0xd3, 0x3c, 0x5d, 0xbb, 0xb2, 0xce, 0xfc, 0x17, 0x4d,
-    0x71, 0x11, 0xd8, 0x35, 0x71, 0x1d, 0x8b, 0x14, 0x5c, 0x56, 0xdf, 0xe5, 0xed, 0x77, 0xc9, 0xa1,
-    0xa3, 0x46, 0x7a, 0x2b, 0xdc, 0x0a, 0x2d, 0xbb, 0x59, 0x50, 0x37, 0x78, 0x9f, 0xf0, 0xec, 0x55,
-    0xba, 0x7d, 0x7b, 0x1e, 0x7a, 0x6b, 0xfc, 0x0b, 0x6b, 0x6c, 0x5e, 0xc0, 0x5e, 0x17, 0x8f, 0x31,
-    0xb1, 0x9a, 0x05, 0x99, 0x76, 0x5d, 0x6d, 0xc0, 0x84, 0x43, 0x67, 0xc3, 0x1d, 0x9b, 0xe6, 0x09,
-    0xe1, 0xfb, 0x67, 0xe5, 0x23, 0x02, 0x55, 0xc1, 0xba, 0xaa, 0xa8, 0xde, 0x28, 0xd1, 0xe2, 0x67,
-    0x48, 0x1b, 0x9d, 0x9d, 0xfc, 0xce, 0x3c, 0xef, 0x46, 0xe3, 0x73, 0xf7, 0x64, 0x44, 0xbe, 0x14,
-    0x29, 0x42, 0x0c, 0xa7, 0x1a, 0xcb, 0xbe, 0x75, 0xfb, 0x10, 0x6a, 0x77, 0xb3, 0xf4, 0x70, 0x19,
-    0xa6, 0xc0, 0xbd, 0x9f, 0xc2, 0x9c, 0x7b, 0x93, 0xbf, 0x03, 0xa3, 0x69, 0xbe, 0x73, 0x2a, 0x8e,
-    0x0d, 0xfc, 0xb5, 0x30, 0x71, 0xb4, 0x88, 0xc6, 0xe7, 0x2c, 0x4c, 0x8c, 0x8c, 0xf6, 0x73, 0x7e,
-    0x5f, 0x43, 0xf2, 0xb8, 0x77, 0xc5, 0x75, 0x55, 0x85, 0x57, 0xdf, 0xc3, 0xaf, 0x5f, 0x1b, 0xbd,
-    0xf6, 0x37, 0x0b, 0x91, 0xd1, 0x3e, 0xa8, 0x77, 0xb6, 0xea, 0x27, 0x44, 0x61, 0x09, 0x01, 0xc5,
-    0x47, 0x17, 0xc7, 0x82, 0xb6, 0x96, 0x9f, 0xa7, 0x25, 0x92, 0x78, 0x6b, 0xbc, 0x00, 0x49, 0x6a,
-    0xbe, 0x9e, 0xc0, 0xee, 0x4a, 0xdd, 0xfc, 0x23, 0x68, 0x1c, 0xcf, 0x04, 0xf3, 0x72, 0xcd, 0xbf,
-    0x59, 0xca, 0xde, 0xf8, 0x1b, 0x05, 0x25, 0x1d, 0x7f, 0x0b, 0xf2, 0xa7, 0x37, 0xb3, 0x23, 0x34,
-    0x34, 0x9c, 0xec, 0xcc, 0x7a, 0x6f, 0x33, 0xb6, 0x57, 0x4f, 0x45, 0xc1, 0x1c, 0x5e, 0x23, 0x03,
-    0x42, 0x22, 0x10, 0xa8, 0xb5, 0xc6, 0xe7, 0x09, 0x5f, 0x62, 0x57, 0xed, 0xda, 0xee, 0x08, 0x12,
-    0xf7, 0x3f, 0x61, 0x52, 0x51, 0xe9, 0xec, 0x23, 0xcb, 0x6d, 0x77, 0x29, 0x0a, 0x6e, 0x7e, 0x8c,
-    0xc0, 0x73, 0x89, 0x0d, 0x12, 0x4e, 0xad, 0x83, 0xf0, 0x11, 0xf8, 0x59, 0x82, 0x46, 0xc2, 0x36,
-    0x2f, 0xcf, 0x48, 0x2d, 0xfc, 0x37, 0x24, 0x5c, 0x76, 0x10, 0xd3, 0x3f, 0xc3, 0x7e, 0x89, 0xde,
-    0x6c, 0x57, 0x51, 0xdc, 0x50, 0x9d, 0xba, 0xa6, 0x8e, 0xf5, 0x17, 0x52, 0xfc, 0x0d, 0x89, 0x3b,
-    0x14, 0xc8, 0x15, 0x7c, 0x5e, 0xdf, 0x3c, 0x3b, 0xc2, 0x4b, 0x8e, 0x65, 0x71, 0x89, 0xf7, 0x99,
-    0x04, 0x8e, 0x03, 0xbc, 0x0a, 0x9f, 0xf1, 0xde, 0x32, 0x43, 0x38, 0x5c, 0xd9, 0x26, 0x77, 0x3b,
-    0xc6, 0xcb, 0x70, 0xbe, 0xc5, 0x0e, 0x54, 0x8f, 0x63, 0x75, 0xc3, 0x85, 0x04, 0x2f, 0xa8, 0x4e,
-    0xde, 0xc7, 0x37, 0xb7, 0x85, 0xf6, 0x98, 0x3b, 0x37, 0x77, 0xb7, 0x22, 0x96, 0xc6, 0x0e, 0x03,
-    0x60, 0x25, 0x28, 0x59, 0x11, 0xc0, 0xff, 0x9d, 0x3a, 0xb5, 0x16, 0x02, 0x36, 0x91, 0x65, 0x7c,
-    0x8f, 0x37, 0xc8, 0xee, 0xd1, 0x30, 0x16, 0x70, 0xba, 0xcc, 0x02, 0xbe, 0x82, 0x6b, 0xe5, 0x4f,
-    0xb5, 0x13, 0x47, 0x94, 0x08, 0x3b, 0x44, 0x09, 0x4c, 0x2a, 0x94, 0x77, 0x07, 0xd6, 0x74, 0xeb,
-    0xf7, 0x83, 0x6a, 0x77, 0xba, 0xe4, 0xab, 0x59, 0x67, 0xe1, 0x91, 0x70, 0x47, 0x17, 0x02, 0x22,
-    0x27, 0x65, 0x73, 0x3f, 0x7b, 0x58, 0x84, 0xa2, 0xdd, 0xc7, 0xe5, 0x79, 0xc1, 0x3b, 0xbb, 0x32,
-    0xe0, 0x05, 0xa6, 0xeb, 0x75, 0xec, 0x94, 0x16, 0x07, 0x6f, 0x29, 0xed, 0x7d, 0x70, 0x53, 0x82,
-    0xc4, 0x54, 0x03, 0x96, 0x27, 0x2e, 0x88, 0x98, 0x31, 0xc0, 0xd9, 0xa7, 0x80, 0xc8, 0xb4, 0x0e,
-    0x3b, 0x67, 0xe7, 0x81, 0x1b, 0x8c, 0x32, 0x0d, 0xe8, 0x0d, 0x6d, 0x28, 0x58, 0xd8, 0xeb, 0xff,
-    0xc1, 0x1a, 0x14, 0xe4, 0x33, 0x93, 0x94, 0xe6, 0x67, 0xb6, 0x64, 0x74, 0x60, 0x98, 0xa3, 0xb8,
-    0x6f, 0x34, 0xf1, 0x8f, 0x4c, 0xe8, 0xf4, 0xa8, 0x8d, 0xa9, 0x2f, 0x67, 0x9b, 0xf0, 0x93, 0x76,
-    0xc9, 0x4e, 0x47, 0x57, 0x53, 0x93, 0x6e, 0x5c, 0xae, 0x57, 0x31, 0x07, 0x2d, 0xb5, 0xfb, 0xc3,
-    0x27, 0xc7, 0xe4, 0x13, 0xee, 0xf9, 0x7e, 0xa6, 0x05, 0x76, 0x4d, 0x13, 0xa5, 0x7f, 0x2f, 0xaa,
-    0xb0, 0x55, 0x36, 0x77, 0xf7, 0xbe, 0x16, 0xa1, 0x77, 0x7b, 0xea, 0x6e, 0x5b, 0x67, 0xf2, 0x70,
-    0x41, 0xf7, 0x6d, 0x55, 0xf3, 0xc8, 0x2b, 0x6d, 0xba, 0x0b, 0x54, 0x3c, 0x0c, 0x97, 0xf1, 0x7c,
-    0xb3, 0x7c, 0x30, 0xb5, 0x05, 0x0a, 0xd7, 0x65, 0xc0, 0x96, 0x9b, 0x0d, 0x42, 0x97, 0xc8, 0x42,
-    0xbc, 0x5a, 0x59, 0x9e, 0xe0, 0x06, 0x3b, 0x0f, 0x9c, 0x73, 0xb8, 0xba, 0x6c, 0xe6, 0x41, 0xf5,
-    0xb9, 0xb1, 0xb2, 0x3f, 0x7c, 0xf6, 0x86, 0xc0, 0x58, 0xbd, 0x75, 0x17, 0xe9, 0x22, 0x53, 0x48,
-    0x16, 0x0e, 0xf6, 0x05, 0xad, 0xe0, 0xdb, 0xf1, 0xcb, 0x5e, 0x52, 0xdf, 0x0e, 0x44, 0x5e, 0x25,
-    0x63, 0x88, 0x30, 0x06, 0xb4, 0xa4, 0xc7, 0x61, 0x45, 0x59, 0x4a, 0x3a, 0x45, 0xbb, 0x8c, 0xe4,
-    0x9a, 0x06, 0x43, 0x78, 0x43, 0xe9, 0x38, 0x06, 0xf0, 0xc3, 0xb7, 0xd2, 0x82, 0x57, 0x30, 0xaa,
-    0x55, 0xe0, 0x9a, 0x22, 0x4d, 0xe3, 0xd5, 0xbd, 0x3f, 0x44, 0x52, 0xb0, 0x77, 0x55, 0x48, 0x88,
-    0x38, 0x06, 0x5f, 0x11, 0x79, 0x0d, 0xf4, 0x43, 0x2b, 0x00, 0x16, 0x92, 0x11, 0xea, 0xc3, 0x91,
-    0x25, 0xf0, 0x18, 0xf7, 0x7c, 0xa2, 0xaa, 0x3f, 0x47, 0x5c, 0x70, 0x2b, 0x60, 0x12, 0x01, 0xfa,
-    0x01, 0xee, 0xd7, 0x96, 0xf4, 0xb1, 0xb3, 0xe6, 0x8d, 0xfe, 0x0f, 0x2b, 0x4b, 0x6d, 0x3c, 0xb4,
-    0xb7, 0xae, 0xdf, 0x00, 0x18, 0xda, 0x84, 0x29, 0x35, 0xf1, 0xf6, 0x53, 0x15, 0xfa, 0xdc, 0x6e,
-    0x59, 0x10, 0x54, 0xea, 0x5e, 0xcd, 0x6c, 0x22, 0xe0, 0x39, 0x1f, 0xf2, 0x90, 0xab, 0x0d, 0x87,
-    0xad, 0xcb, 0x45, 0x47, 0x6b, 0xbf, 0x20, 0xdb, 0xdb, 0x5e, 0x03, 0xb7, 0x07, 0x18, 0xd2, 0x5e,
-    0xab, 0xc0, 0x56, 0xfd, 0xf7, 0x7f, 0x40, 0xcb, 0xc4, 0xa4, 0xb1, 0x61, 0xc4, 0xe0, 0xc0, 0x25,
-    0x78, 0x19, 0xf2, 0x21, 0x36, 0xf1, 0xaa, 0x2f, 0xf4, 0x01, 0xc8, 0x8b, 0xc0, 0xab, 0xe0, 0x02,
-    0xc0, 0xd7, 0x55, 0x03, 0x1f, 0x32, 0x91, 0x11, 0x00, 0xb7, 0x0c, 0xff, 0xcf, 0x9c, 0x1a, 0x20,
-    0x1b, 0x27, 0xbf, 0xf3, 0x77, 0x73, 0x9e, 0x47, 0x86, 0x83, 0xb3, 0x84, 0x98, 0xe2, 0x34, 0x39,
-    0x68, 0xc3, 0x13, 0xc3, 0xf3, 0xc0, 0xbf, 0xa2, 0x14, 0xe7, 0xf1, 0xe0, 0x4f, 0x3a, 0x2d, 0xdb,
-    0x77, 0x22, 0xef, 0x00, 0x53, 0xc4, 0xb2, 0xf2, 0x16, 0xc1, 0x79, 0x11, 0xaa, 0x8f, 0x32, 0x3e,
-    0x81, 0xd0, 0xf2, 0x22, 0xe0, 0x0e, 0xc0, 0xe3, 0xb0, 0x5b, 0x79, 0xd3, 0x16, 0xed, 0x2b, 0x91,
-    0xf5, 0x54, 0xa1, 0x27, 0x98, 0xeb, 0x5c, 0x02, 0x5c, 0x09, 0xaf, 0x86, 0x91, 0xd0, 0x36, 0x61,
-    0xc8, 0x89, 0x55, 0xbb, 0xd1, 0x35, 0x5e, 0xb4, 0x32, 0xb1, 0xdb, 0xdb, 0xdb, 0x4b, 0x5b, 0x63,
-    0xcb, 0x84, 0x26, 0x27, 0x8d, 0x1b, 0x68, 0xfe, 0x5f, 0x4b, 0xb3, 0xb8, 0x67, 0xf7, 0x7d, 0x55,
-    0x82, 0xb2, 0x13, 0xbd, 0x49, 0xf0, 0xd6, 0x0e, 0xef, 0x62, 0x5b, 0x67, 0x59, 0xfb, 0x17, 0xdb,
-    0xd8, 0x18, 0x4d, 0xcc, 0xbb, 0xfa, 0x61, 0xab, 0xb5, 0xbc, 0xf6, 0x29, 0xaf, 0x10, 0x6d, 0x34,
-    0x0a, 0xa7, 0x50, 0x7f, 0xfb, 0xd5, 0xb0, 0x53, 0x59, 0xfb, 0xce, 0x8a, 0x25, 0x37, 0xad, 0x3e,
-    0xe5, 0xaa, 0x9b, 0xae, 0x4c, 0x88, 0xbe, 0x04, 0x4f, 0x81, 0x79, 0x8f, 0xa5, 0x3f, 0x6f, 0x15,
-    0x31, 0xc4, 0xb8, 0x15, 0xe8, 0x18, 0x91, 0x13, 0x80, 0x07, 0x54, 0xeb, 0x30, 0x35, 0x20, 0xcd,
-    0x33, 0x22, 0x07, 0x81, 0xdf, 0x8b, 0x14, 0x19, 0xe7, 0xa6, 0x3b, 0x4b, 0xca, 0x0b, 0x2e, 0xa2,
-    0x1d, 0x7b, 0x73, 0xb1, 0x74, 0x6c, 0xa2, 0x28, 0xfa, 0x23, 0x30, 0x46, 0xaf, 0x04, 0x8a, 0x38,
-    0x26, 0x4d, 0x7f, 0x00, 0x91, 0x14, 0x86, 0x0f, 0x9d, 0x1d, 0x11, 0x1f, 0x15, 0x39, 0x0f, 0xb8,
-    0x55, 0xbb, 0x86, 0xd3, 0x3f, 0x00, 0x91, 0x16, 0xaa, 0xe9, 0x25, 0xfa, 0xfe, 0xdf, 0x00, 0x9f,
-    0xb3, 0xaf, 0x1d, 0x78, 0x45, 0xe0, 0xfe, 0xcc, 0x78, 0xb7, 0x7e, 0x9f, 0xe0, 0x9a, 0xd7, 0x7b,
-    0xbb, 0xe2, 0x1f, 0x67, 0xd4, 0x9f, 0xb0, 0xc6, 0xe0, 0xcc, 0x61, 0x6f, 0x6f, 0x01, 0x51, 0xe9,
-    0xff, 0x88, 0xf2, 0xa8, 0x6b, 0x95, 0xb1, 0xea, 0x78, 0xa7, 0x37, 0x85, 0x34, 0x42, 0xf4, 0x6c,
-    0x76, 0x0b, 0x6e, 0x7a, 0x01, 0x5f, 0x8a, 0xcc, 0x56, 0xfe, 0xfa, 0xc7, 0x57, 0xe8, 0x26, 0x44,
-    0x95, 0xe3, 0x4c, 0x35, 0x35, 0x8b, 0x7a, 0xaa, 0xf1, 0x5f, 0x32, 0x5a, 0xf2, 0x22, 0xc0, 0x8f,
-    0xec, 0x8b, 0xce, 0xff, 0x8e, 0x37, 0x3c, 0x36, 0xbc, 0x47, 0x44, 0x50, 0x26, 0xbe, 0x43, 0x22,
-    0xff, 0x7d, 0x4d, 0xf6, 0x38, 0x12, 0xf1, 0xdf, 0xc2, 0x2d, 0x86, 0xb1, 0xa5, 0x2b, 0xb1, 0x3c,
-    0x22, 0x27, 0x61, 0x94, 0x3b, 0x14, 0xc7, 0xb5, 0x28, 0x0f, 0x85, 0xdd, 0xe0, 0x16, 0x01, 0xd2,
-    0xb9, 0x8e, 0xfb, 0x01, 0x4b, 0x25, 0x7c, 0x4b, 0xf4, 0xb8, 0x44, 0x41, 0xc2, 0x2e, 0xf3, 0xbe,
-    0xd1, 0x2d, 0x27, 0x8a, 0x31, 0xf0, 0xe2, 0x28, 0x00, 0x24, 0x9e, 0x3f, 0x30, 0xb0, 0xaf, 0xcc,
-    0xf5, 0xb7, 0x52, 0xf3, 0x72, 0x50, 0xa1, 0x70, 0xfe, 0xaa, 0x82, 0xa1, 0x69, 0xbd, 0x6b, 0x78,
-    0x6b, 0x7f, 0x17, 0xb6, 0x39, 0x23, 0x1c, 0xf8, 0x9b, 0xf0, 0x27, 0x44, 0x00, 0x19, 0x21, 0x1b,
-    0x0b, 0xe8, 0x1f, 0x4b, 0x8f, 0x86, 0xde, 0x15, 0xb9, 0x7a, 0xa9, 0xd9, 0xae, 0x9c, 0xca, 0x5d,
-    0xbf, 0xef, 0xe8, 0x1b, 0xcc, 0xb5, 0x6a, 0x30, 0x9e, 0x30, 0xe1, 0xb7, 0x57, 0x9b, 0xcb, 0x7c,
-    0x16, 0xe8, 0x31, 0x4e, 0x0e, 0xbc, 0x4f, 0xf3, 0x72, 0xbb, 0xb5, 0x3c, 0x10, 0xaf, 0x54, 0xc2,
-    0xe9, 0x11, 0x53, 0xc0, 0xfa, 0x7f, 0xf0, 0x39, 0xb8, 0xae, 0x4c, 0xef, 0x13, 0x6e, 0x19, 0x4e,
-    0xe5, 0x96, 0x21, 0xb8, 0x5a, 0x19, 0x9f, 0x6a, 0x33, 0xaf, 0x02, 0x8e, 0x72, 0xbb, 0x86, 0xca,
-    0x02, 0xbe, 0xfa, 0x1b, 0x95, 0x95, 0x05, 0x3d, 0xe4, 0x76, 0x5e, 0x22, 0x15, 0xac, 0xc7, 0xaf,
-    0x57, 0xfb, 0x72, 0x22, 0xb0, 0x3e, 0x2f, 0x05, 0x08, 0x3c, 0x94, 0xc0, 0x0c, 0xb6, 0x3b, 0x7f,
-    0xba, 0xa1, 0x3e, 0x2f, 0xdd, 0xb2, 0x3d, 0xfc, 0xc8, 0xe8, 0xe2, 0x48, 0x88, 0x35, 0xf0, 0xf5,
-    0x51, 0xc6, 0x5f, 0x66, 0x02, 0xf1, 0xce, 0xf0, 0xad, 0x31, 0x38, 0x5c, 0x71, 0xa6, 0x0c, 0xe7,
-    0xcb, 0x3d, 0x7b, 0xbc, 0x2b, 0x5c, 0x3b, 0xd3, 0x76, 0xcc, 0x7e, 0x8c, 0xad, 0xb1, 0x95, 0x9f,
-    0x1a, 0xfb, 0x8a, 0xf7, 0x86, 0x6d, 0x8c, 0x88, 0xe7, 0xc1, 0x8e, 0xf4, 0xcf, 0x68, 0x49, 0x70,
-    0xa4, 0xc2, 0xa4, 0x9e, 0xbd, 0xc4, 0xc5, 0xdb, 0x8b, 0x72, 0xf9, 0x17, 0xfb, 0x8f, 0x21, 0xc8,
-    0x8c, 0xad, 0xb5, 0x6f, 0x9f, 0x7a, 0x4e, 0x8e, 0xd5, 0xf0, 0xf0, 0xab, 0x9b, 0xf9, 0xd7, 0x0f,
-    0x01, 0x22, 0x1d, 0x18, 0x56, 0xfd, 0xba, 0x9b, 0x0a, 0xb9, 0xe7, 0x5f, 0x16, 0xbb, 0x5f, 0x7b,
-    0x8a, 0x8b, 0x5c, 0x2e, 0xe8, 0xdf, 0x22, 0x5c, 0x6f, 0xa3, 0x31, 0x67, 0x58, 0x04, 0x63, 0x9e,
-    0xfe, 0x3c, 0x16, 0xec, 0xfa, 0xfe, 0x8e, 0xea, 0xdf, 0x2a, 0x9f, 0xa8, 0x1f, 0x67, 0x0f, 0xea,
-    0xe0, 0x3b, 0x36, 0x06, 0x83, 0x0d, 0x90, 0x26, 0xfa, 0x85, 0x0f, 0xff, 0xe7, 0x6b, 0xc3, 0x5c,
-    0x3d, 0xc9, 0xbc, 0xcf, 0x08, 0x10, 0x0a, 0x03, 0xcd, 0x5e, 0x2f, 0xd3, 0x72, 0x11, 0xad, 0xbe,
-    0x57, 0x02, 0xda, 0x1d, 0x27, 0xce, 0xb5, 0x26, 0xb9, 0x31, 0x79, 0xad, 0x6e, 0x9d, 0xf2, 0x35,
-    0x8f, 0x0a, 0xce, 0xec, 0xef, 0x71, 0x1c, 0xb6, 0x6f, 0x77, 0x64, 0x8d, 0x1e, 0x44, 0x3c, 0x0b,
-    0x17, 0x8a, 0x2a, 0x2a, 0xf4, 0xdf, 0xc6, 0x0b, 0xf0, 0xb4, 0x69, 0xd5, 0x1c, 0xf6, 0x25, 0x5f,
-    0x1a, 0xce, 0xb5, 0x91, 0x2a, 0x32, 0x45, 0xb5, 0xf8, 0x06, 0x83, 0x72, 0xeb, 0xef, 0xe0, 0xc2,
-    0xcc, 0xb3, 0x87, 0xf5, 0x33, 0xb7, 0x70, 0xcd, 0xb2, 0x69, 0x83, 0xbb, 0x06, 0x25, 0x4d, 0xab,
-    0x05, 0x1d, 0x1a, 0x6a, 0x34, 0x5c, 0xfc, 0xd6, 0x15, 0x73, 0xb7, 0x7a, 0x78, 0x33, 0xda, 0x6d,
-    0x7c, 0x46, 0x4c, 0xed, 0x06, 0x47, 0x39, 0x6e, 0x08, 0x6a, 0x5f, 0xa6, 0xd0, 0xe9, 0x1a, 0x7d,
-    0xdb, 0x54, 0x2c, 0x5a, 0x74, 0xc4, 0x69, 0x79, 0x45, 0xbb, 0x53, 0xe0, 0x25, 0x09, 0xff, 0x00,
-    0xea, 0x1c, 0x01, 0x94, 0x81, 0x2b, 0x98, 0x5f, 0x37, 0xb2, 0x4f, 0x77, 0xc7, 0x9e, 0x24, 0x1b,
-    0x58, 0x39, 0xd3, 0x0d, 0xe8, 0x21, 0x7a, 0xc0, 0x63, 0xc4, 0xb0, 0xcf, 0x80, 0x51, 0x32, 0x23,
-    0xb5, 0x1f, 0xb8, 0xc0, 0x28, 0xd1, 0x05, 0xd6, 0x9e, 0x18, 0x3e, 0x08, 0x1b, 0x2c, 0xf7, 0x81,
-    0xd3, 0xe2, 0x04, 0xbd, 0x6f, 0x38, 0x0b, 0x64, 0x9c, 0xcf, 0x9c, 0x38, 0x4e, 0xaf, 0xdf, 0x6b,
-    0x9d, 0x6f, 0x78, 0x2f, 0x02, 0xc2, 0x1c, 0x6f, 0xc2, 0xd5, 0x47, 0xad, 0xf0, 0x75, 0xc9, 0xc2,
-    0xb9, 0xc3, 0x42, 0x6c, 0x38, 0x6b, 0x78, 0x1e, 0x10, 0x18, 0xf7, 0x90, 0x90, 0x3b, 0xde, 0x9c,
-    0x4c, 0x81, 0x4c, 0x58, 0x4a, 0x64, 0xc6, 0x5b, 0xf3, 0xb8, 0x59, 0x8d, 0xff, 0x3f, 0x95, 0x54,
-    0xad, 0xc3, 0x8b, 0xca, 0xbc, 0xc6, 0x1b, 0xdb, 0x75, 0x54, 0x31, 0x63, 0xa3, 0xa7, 0x02, 0x3c,
-    0x75, 0x3d, 0xd6, 0x58, 0xf3, 0xb8, 0xb9, 0x8d, 0xb1, 0x4f, 0x4f, 0xc9, 0x04, 0x31, 0x00, 0x24,
-    0x19, 0x2f, 0x83, 0x5f, 0x60, 0x04, 0xf4, 0x74, 0x8d, 0xfb, 0x35, 0x2a, 0x3e, 0x0e, 0x6f, 0x81,
-    0xb3, 0xda, 0x7b, 0x16, 0xa3, 0x31, 0x6f, 0xdf, 0x6a, 0xaa, 0xdc, 0x7f, 0xf5, 0xb1, 0xd5, 0x60,
-    0xdb, 0x01, 0x40, 0x51, 0x5d, 0x4a, 0x61, 0x80, 0x3e, 0x2c, 0x86, 0x01, 0x87, 0x93, 0x17, 0x99,
-    0x58, 0x60, 0x99, 0xda, 0x77, 0x67, 0x14, 0x70, 0xc1, 0x98, 0xb8, 0x4b, 0x73, 0x2a, 0xc4, 0xc5,
-    0xfe, 0x36, 0xc2, 0x74, 0x66, 0x50, 0xbe, 0x9a, 0xcb, 0x18, 0xd2, 0x1c, 0x7c, 0x2a, 0xe8, 0xff,
-    0xfc, 0x21, 0xd8, 0xe2, 0x55, 0xa1, 0x37, 0xeb, 0x58, 0xdb, 0xe4, 0x5e, 0x9f, 0xa8, 0xba, 0xe7,
-    0xcf, 0x82, 0x13, 0x72, 0x9f, 0xae, 0x96, 0x0f, 0x1d, 0x97, 0xb6, 0x69, 0x8b, 0x4d, 0xb7, 0x79,
-    0xd7, 0x4b, 0x96, 0x76, 0xe7, 0x7f, 0x86, 0xd9, 0x03, 0xaf, 0xab, 0x6a, 0x10, 0x33, 0x01, 0x27,
-    0x75, 0x78, 0x11, 0x42, 0x67, 0x84, 0xf3, 0x3b, 0xb4, 0x3c, 0xd0, 0x33, 0x6f, 0xae, 0x7e, 0x06,
-    0xc1, 0x50, 0xd0, 0xde, 0xed, 0x7a, 0xd7, 0x3d, 0xe0, 0x55, 0x0d, 0x77, 0x1c, 0x94, 0x86, 0xac,
-    0x07, 0x35, 0x31, 0xdc, 0x38, 0x4c, 0x96, 0x7c, 0x01, 0x79, 0x95, 0x86, 0x83, 0x0b, 0x0a, 0x61,
-    0x7d, 0x55, 0xa8, 0xd5, 0x28, 0xd1, 0x10, 0x81, 0x4a, 0x55, 0x0c, 0x02, 0xf1, 0x13, 0x5f, 0x85,
-    0x3f, 0x5f, 0x85, 0xaa, 0x1d, 0x6f, 0x36, 0x69, 0x9f, 0xf4, 0x17, 0x36, 0x6d, 0x8d, 0xbe, 0xe1,
-    0x86, 0xe3, 0x96, 0xc6, 0x9c, 0x5c, 0x26, 0xdc, 0x69, 0x1c, 0x5d, 0x5a, 0xd1, 0xc1, 0xc2, 0x10,
-    0xb2, 0xcf, 0x75, 0x95, 0xd1, 0xd9, 0x54, 0x65, 0x8e, 0xb1, 0x58, 0xa5, 0xee, 0xdd, 0xa5, 0xb5,
-    0xa3, 0xed, 0x32, 0x3a, 0x32, 0x4c, 0xb4, 0x5c, 0x4a, 0xa5, 0x4f, 0x89, 0xd5, 0xeb, 0x62, 0xce,
-    0xcf, 0x96, 0x46, 0x0d, 0xe5, 0xe8, 0x7c, 0x72, 0xfd, 0x21, 0x49, 0x06, 0xde, 0x0e, 0x45, 0x5c,
-    0xf0, 0x72, 0xf8, 0x23, 0x3d, 0xa6, 0x41, 0x9b, 0xb0, 0x72, 0xc6, 0x1a, 0xa5, 0x5a, 0xe1, 0x62,
-    0xa3, 0x83, 0xdb, 0x4a, 0x9f, 0x47, 0x25, 0x96, 0xf8, 0x63, 0x59, 0x19, 0x38, 0xb5, 0x5f, 0x4f,
-    0xea, 0x4f, 0xe1, 0x05, 0xa8, 0x53, 0x54, 0x42, 0x19, 0x79, 0xd1, 0xc8, 0x19, 0x1d, 0x99, 0xee,
-    0xc4, 0x31, 0x16, 0xb8, 0x33, 0x6c, 0xe6, 0xf0, 0x2d, 0x51, 0x74, 0x7c, 0x74, 0x62, 0xe7, 0xae,
-    0x0b, 0x4c, 0x71, 0x4b, 0x8d, 0x1c, 0x34, 0x21, 0xc6, 0xef, 0x16, 0x39, 0xcb, 0x1c, 0x41, 0x63,
-    0x05, 0x9b, 0xaf, 0x2a, 0x3e, 0x61, 0x5f, 0x05, 0xbb, 0x75, 0x4b, 0x94, 0x96, 0x7c, 0x19, 0xdb,
-    0x4e, 0xc1, 0xf9, 0x9d, 0x67, 0x50, 0xc7, 0x20, 0xd3, 0x00, 0x8d, 0x7b, 0x1c, 0x90, 0xb9, 0x7c,
-    0xc0, 0xa7, 0xb7, 0x2f, 0x22, 0x07, 0x7b, 0xbf, 0xdb, 0x80, 0xd8, 0x2a, 0xa1, 0x6b, 0xc9, 0x4e,
-    0xd5, 0xc1, 0x24, 0x06, 0xab, 0x07, 0x72, 0x61, 0x90, 0x58, 0xfc, 0xc2, 0xf3, 0x6f, 0x30, 0x09,
-    0xa4, 0xa4, 0x54, 0x80, 0xc6, 0xe6, 0x3a, 0x23, 0x6b, 0x18, 0x12, 0xba, 0x13, 0x7f, 0xdd, 0x71,
-    0xf6, 0xd4, 0xb6, 0x48, 0x9b, 0xa3, 0xdd, 0xff, 0xf0, 0x7f, 0x46, 0x8f, 0x67, 0x87, 0xd9, 0x85,
-    0xcd, 0x43, 0xed, 0xfe, 0xe6, 0xf6, 0x25, 0x95, 0x75, 0xc1, 0x4b, 0xd9, 0x75, 0x54, 0x85, 0x77,
-    0xad, 0xc3, 0xff, 0xce, 0xbc, 0x42, 0x8a, 0xb8, 0x0c, 0x88, 0xeb, 0xc1, 0x00, 0x0c, 0xdc, 0x70,
-    0x8c, 0x90, 0x77, 0xf1, 0x4f, 0x7c, 0x3e, 0xf4, 0x54, 0x2d, 0xae, 0xd5, 0xbe, 0x01, 0x7e, 0xf6,
-    0xd5, 0x7c, 0x6a, 0xe7, 0x1c, 0x95, 0x2d, 0x0c, 0xbb, 0xdb, 0x55, 0x5d, 0x56, 0x77, 0xfc, 0x38,
-    0xf8, 0x7d, 0xb6, 0x8a, 0x62, 0xd4, 0x26, 0xef, 0x92, 0x03, 0xd5, 0x83, 0xe7, 0xb0, 0x6d, 0x80,
-    0xff, 0xcc, 0xec, 0xa6, 0xc3, 0x80, 0x2a, 0x21, 0x02, 0x5b, 0xa1, 0x0c, 0xfe, 0xc2, 0x26, 0x65,
-    0x0a, 0xb5, 0x1d, 0x6f, 0x70, 0x7d, 0xfe, 0x8d, 0xb4, 0xc6, 0xff, 0x08, 0xca, 0x1a, 0xb5, 0x4a,
-    0x52, 0x31, 0xd4, 0x71, 0xc6, 0xcf, 0xe5, 0x3e, 0xdf, 0x15, 0x7c, 0xb3, 0xf0, 0xfa, 0x59, 0x2c,
-    0x7d, 0xc3, 0x27, 0xc7, 0x46, 0xf6, 0x65, 0xd6, 0x7a, 0x0f, 0xf7, 0xfe, 0xc3, 0x6c, 0xeb, 0x9d,
-    0xa2, 0x2a, 0x73, 0x1d, 0x2d, 0xf0, 0xb1, 0xb1, 0xff, 0x31, 0xf0, 0x9b, 0x35, 0x3e, 0x02, 0x44,
-    0x53, 0x70, 0x72, 0x54, 0x8f, 0xb0, 0x92, 0x0a, 0x45, 0x83, 0xb2, 0xea, 0x35, 0xb7, 0x72, 0x5e,
-    0x9b, 0xf0, 0x4e, 0x89, 0x10, 0x92, 0x0e, 0x93, 0xdc, 0xf8, 0x87, 0xd2, 0x0b, 0x6c, 0x3f, 0x4c,
-    0x82, 0xd5, 0x52, 0x02, 0x03, 0x30, 0x0d, 0x3a, 0x86, 0x01, 0x88, 0x40, 0xa5, 0x2a, 0x92, 0x04,
-    0x7f, 0x32, 0xa1, 0x33, 0x78, 0xd5, 0xd6, 0x03, 0xbc, 0x8c, 0xec, 0x6b, 0x75, 0xbe, 0x43, 0x99,
-    0x18, 0x32, 0xc2, 0xd7, 0x34, 0x75, 0xb0, 0x86, 0x45, 0x48, 0xf9, 0x4a, 0xd5, 0x13, 0x4b, 0x1c,
-    0xf1, 0x39, 0x4c, 0x69, 0x30, 0x8b, 0xe1, 0x33, 0x62, 0xdc, 0x62, 0x52, 0x9c, 0x0a, 0xc2, 0x44,
-    0x60, 0xcf, 0x9d, 0xa9, 0xe4, 0x19, 0xb9, 0x3c, 0xba, 0x8f, 0x00, 0x25, 0xd9, 0x6f, 0x47, 0xd8,
-    0xee, 0xb0, 0x3f, 0x06, 0xd5, 0x56, 0x71, 0xf5, 0x8a, 0xc7, 0x05, 0xc8, 0xec, 0xc0, 0xec, 0x7a,
-    0x16, 0xdd, 0x1c, 0x95, 0x99, 0xfc, 0xae, 0xaa, 0x74, 0x4e, 0x84, 0x92, 0x79, 0x18, 0x44, 0x82,
-    0x24, 0x64, 0x9a, 0xf0, 0xf6, 0xd2, 0xb3, 0xe1, 0xb4, 0xb3, 0x35, 0x0f, 0x09, 0xeb, 0xad, 0x36,
-    0xb0, 0x2a, 0x73, 0x6b, 0xaf, 0xe0, 0x78, 0xf5, 0x02, 0x0a, 0xcd, 0x0c, 0x62, 0xf0, 0xb9, 0x94,
-    0x42, 0x6c, 0xb5, 0xb2, 0x07, 0x6f, 0x87, 0x0a, 0x0a, 0xb4, 0x8a, 0x63, 0xb9, 0x21, 0x86, 0xd3,
-    0x0f, 0x67, 0xf9, 0x8a, 0x03, 0xef, 0xf0, 0x81, 0x6f, 0xfc, 0x25, 0x93, 0x1d, 0x60, 0x1c, 0x03,
-    0xda, 0x52, 0x63, 0x3e, 0xd6, 0x44, 0x29, 0x78, 0x2a, 0xac, 0x66, 0xd7, 0x9d, 0xbd, 0x41, 0xa9,
-    0xb9, 0xef, 0x09, 0x2e, 0x3d, 0xc0, 0xe5, 0x79, 0x9b, 0x3b, 0x12, 0x22, 0x46, 0x80, 0x07, 0x25,
-    0x8d, 0x6f, 0x0e, 0x4a, 0xb4, 0x36, 0x64, 0xec, 0xa6, 0x1c, 0x17, 0x62, 0xe2, 0x67, 0xee, 0x73,
-    0xc2, 0x36, 0xcb, 0xcf, 0x5e, 0x53, 0x54, 0x7e, 0x94, 0x24, 0x95, 0x80, 0x1d, 0x5e, 0xe9, 0xde,
-    0x99, 0x1d, 0xd9, 0xc4, 0xf5, 0x7f, 0x6c, 0xf0, 0x9e, 0x67, 0x6d, 0xef, 0x67, 0xea, 0x4f, 0x45,
-    0x97, 0x81, 0x0a, 0x7b, 0x30, 0x28, 0x4d, 0xa5, 0xd6, 0x98, 0xe1, 0x9e, 0xa3, 0x6d, 0xf8, 0x5b,
-    0x00, 0xc0, 0xa8, 0x55, 0x4d, 0x1a, 0x4d, 0x69, 0xfc, 0xe4, 0x79, 0x3d, 0x3f, 0xc6, 0xa7, 0xb9,
-    0xb1, 0xea, 0x1e, 0x37, 0xc1, 0xd1, 0x86, 0xa5, 0xef, 0xaf, 0xcf, 0xcd, 0xf1, 0x77, 0xa7, 0x6c,
-    0x1a, 0x9d, 0xc7, 0xd0, 0xc9, 0x0e, 0x77, 0x30, 0xd9, 0x96, 0xaf, 0xea, 0xde, 0x3f, 0xcf, 0xd2,
-    0xab, 0x95, 0x25, 0x2a, 0xd6, 0xa2, 0xa7, 0x46, 0xc6, 0x2f, 0x15, 0x99, 0x04, 0x2f, 0x92, 0x6d,
-    0x7a, 0xbc, 0x55, 0xa1, 0xeb, 0x1f, 0x8c, 0xab, 0x82, 0x78, 0x8f, 0xcb, 0x3b, 0xec, 0x02, 0xbd,
-    0xbf, 0x30, 0xda, 0x18, 0x8f, 0x2d, 0x27, 0xc4, 0x0a, 0xb6, 0x1b, 0x47, 0x12, 0xae, 0x73, 0x16,
-    0x56, 0x9f, 0xea, 0xa9, 0x4a, 0xc6, 0x37, 0xc7, 0x02, 0x42, 0xf6, 0xf0, 0xfd, 0x4d, 0x0c, 0xec,
-    0xc6, 0x4e, 0x5a, 0xfe, 0x5f, 0x55, 0x60, 0xac, 0x4c, 0xef, 0x11, 0x7c, 0x5a, 0xd7, 0x07, 0x25,
-    0x07, 0xb7, 0xfd, 0xed, 0x51, 0xb6, 0x83, 0x92, 0x30, 0xd5, 0x21, 0xe5, 0xaf, 0xec, 0x6d, 0xff,
-    0x04, 0xb2, 0xb1, 0xac, 0x62, 0x2d, 0xcd, 0x7c, 0xde, 0xed, 0xb2, 0xbc, 0x42, 0xb8, 0xff, 0x61,
-    0x59, 0xd7, 0xf7, 0x5a, 0x5d, 0xda, 0x2f, 0x80, 0xed, 0xae, 0xa6, 0xe1, 0x91, 0x8d, 0x09, 0x64,
-    0xf7, 0x56, 0x8d, 0x7a, 0xdd, 0xc8, 0xfb, 0x5b, 0x7f, 0xb9, 0x8e, 0x47, 0xa7, 0x3b, 0x30, 0x77,
-    0x42, 0xc2, 0x7c, 0x4c, 0x5e, 0x4f, 0xd4, 0xd9, 0x5d, 0xef, 0xbf, 0x4c, 0x7e, 0x12, 0x23, 0x91,
-    0x6a, 0x9c, 0xa1, 0xb8, 0x2a, 0xef, 0x73, 0x28, 0xe7, 0x77, 0xb7, 0xe8, 0x8f, 0x14, 0x9d, 0x31,
-    0x04, 0xb8, 0x97, 0xf0, 0xb9, 0xdd, 0xef, 0x01, 0x3d, 0x6b, 0x1e, 0xcc, 0x35, 0x9a, 0xac, 0xfe,
-    0xe9, 0x2c, 0xb3, 0xca, 0xf8, 0x27, 0x56, 0xd0, 0xb9, 0x53, 0x74, 0x09, 0x4d, 0xae, 0x5c, 0x8b,
-    0xbc, 0xc4, 0x4b, 0xdb, 0x75, 0x55, 0x51, 0x57, 0x68, 0x51, 0x69, 0x74, 0x8d, 0xa7, 0xcf, 0x24,
-    0x5d, 0xc5, 0xf6, 0x79, 0xaf, 0xc6, 0xae, 0x45, 0x5d, 0x44, 0x80, 0x12, 0x0a, 0x7d, 0x27, 0x37,
-    0x1c, 0x93, 0x8c, 0x0c, 0x1b, 0x7e, 0x39, 0x24, 0x4d, 0x58, 0xa1, 0xe4, 0x98, 0x61, 0x10, 0xf2,
-    0xfa, 0xe7, 0x52, 0x37, 0x80, 0xa8, 0x60, 0x35, 0x7c, 0x8a, 0x49, 0xa3, 0x44, 0x23, 0x20, 0xb5,
-    0x18, 0x9a, 0xe6, 0x51, 0x16, 0x75, 0xdf, 0x46, 0x57, 0x00, 0xea, 0xaf, 0x86, 0xe1, 0xa6, 0x68,
-    0x84, 0x62, 0xb7, 0x7b, 0xf3, 0xf5, 0x3b, 0x3f, 0x14, 0xed, 0x5f, 0xed, 0x13, 0xd1, 0x94, 0x9f,
-    0xc7, 0x16, 0x0b, 0x18, 0xa5, 0x1d, 0xf7, 0x27, 0xad, 0xe6, 0x5f, 0x39, 0x2d, 0x48, 0xd9, 0x24,
-    0x9a, 0x50, 0xfe, 0x70, 0x6a, 0xd7, 0xbb, 0x75, 0x77, 0x98, 0x3e, 0x3b, 0x6c, 0xfc, 0xa3, 0xa1,
-    0xe4, 0x9d, 0x35, 0x3e, 0x02, 0x42, 0xc7, 0xf0, 0xfa, 0x5b, 0x10, 0xd9, 0x1c, 0x94, 0x44, 0x7c,
-    0x9f, 0x55, 0x60, 0xa8, 0x26, 0x6f, 0x64, 0x9e, 0xcd, 0x65, 0x62, 0xf6, 0x07, 0x24, 0x35, 0xe7,
-    0x72, 0x52, 0x1a, 0xb0, 0x6f, 0x0d, 0x8b, 0xa5, 0xbf, 0x6b, 0x94, 0xe6, 0x27, 0xb6, 0xcf, 0x4d,
-    0x72, 0x30, 0x59, 0xbc, 0xd4, 0x57, 0x4b, 0xb5, 0xbf, 0x59, 0x71, 0x2c, 0x7c, 0x8a, 0x69, 0xa3,
-    0x79, 0x86, 0x32, 0x99, 0x6b, 0xa6, 0x83, 0x4f, 0x48, 0xd7, 0xbe, 0xdc, 0xd2, 0x29, 0x04, 0x73,
-    0x72, 0xaf, 0x37, 0x4c, 0x09, 0x30, 0x33, 0xdf, 0x60, 0xb6, 0x9e, 0x6f, 0x8f, 0x77, 0x1f, 0x33,
-    0x5e, 0x8a, 0x75, 0x1e, 0x6b, 0xc0, 0xed, 0x81, 0xcf, 0xc5, 0xf0, 0xc3, 0xf0, 0x95, 0xd3, 0x3b,
-    0x47, 0x42, 0xe6, 0x29, 0xb4, 0xef, 0x6f, 0x12, 0x63, 0x3d, 0x98, 0xa3, 0x4f, 0x81, 0xc3, 0xfc,
-    0xb3, 0xf4, 0x35, 0xb7, 0x2c, 0xa7, 0x0e, 0xeb, 0xe3, 0xdc, 0xc0, 0xdd, 0x75, 0x2b, 0x76, 0x9e,
-    0xbe, 0x0a, 0x0d, 0x82, 0x54, 0xcd, 0xab, 0x01, 0x5b, 0x58, 0x6a, 0xd8, 0xbb, 0x75, 0x4e, 0x2a,
-    0xd0, 0x2f, 0x58, 0xce, 0x8b, 0x59, 0x2c, 0x9c, 0xab, 0x01, 0xc9, 0x6e, 0x1b, 0xc1, 0x12, 0xa2,
-    0xb6, 0x80, 0x07, 0x25, 0x8c, 0xad, 0xc1, 0x7e, 0x08, 0x4c, 0x54, 0xfa, 0x8d, 0x7c, 0x95, 0x81,
-    0x47, 0xe5, 0xe6, 0x4f, 0x04, 0xd0, 0xf2, 0x29, 0xb0, 0x86, 0xa2, 0x1a, 0xca, 0x82, 0xd0, 0x19,
-    0xda, 0xd3, 0x1c, 0x33, 0xb8, 0x61, 0x93, 0xf2, 0x1f, 0x02, 0xd9, 0x5d, 0xc8, 0x43, 0xdd, 0xd5,
-    0x7c, 0x07, 0x34, 0xac, 0x54, 0x3f, 0xcb, 0x2c, 0x5e, 0x59, 0xb7, 0x43, 0x73, 0xa8, 0x23, 0xf0,
-    0x7a, 0xd3, 0xde, 0x58, 0xb1, 0x1d, 0x89, 0xf3, 0x26, 0x92, 0x88, 0xb4, 0x10, 0x7c, 0x19, 0x5f,
-    0x94, 0xbb, 0xe5, 0x12, 0xae, 0xde, 0xcb, 0xaa, 0x71, 0x1a, 0xe2, 0xee, 0xe0, 0x9c, 0x8a, 0x36,
-    0xdc, 0xef, 0x16, 0x21, 0x04, 0xe6, 0xc9, 0xc3, 0xc0, 0x52, 0x55, 0xf7, 0x53, 0xf5, 0x9c, 0xf5,
-    0x44, 0x53, 0x8f, 0x7e, 0x22, 0xa7, 0xa4, 0x06, 0x80, 0x92, 0x17, 0xb5, 0x54, 0x58, 0x50, 0xe1,
-    0x4e, 0xfb, 0x10, 0x6f, 0xb0, 0x15, 0x64, 0x86, 0xce, 0xbc, 0xe5, 0x80, 0xd9, 0x6b, 0xc4, 0x0d,
-    0x8d, 0xce, 0x42, 0x36, 0xf0, 0x02, 0xed, 0xbe, 0xe1, 0xfd, 0xdd, 0xce, 0x55, 0x22, 0x7d, 0xfd,
-    0x7b, 0x05, 0xf0, 0x53, 0x22, 0x49, 0x48, 0x36, 0xf0, 0x72, 0x1a, 0x79, 0x39, 0x2c, 0x0d, 0x58,
-    0x5e, 0x13, 0x7e, 0xc2, 0xf9, 0xf8, 0x81, 0x89, 0x68, 0x7b, 0x1a, 0xc5, 0xef, 0xa1, 0xce, 0x01,
-    0xb9, 0x20, 0x67, 0x96, 0x58, 0x01, 0x7c, 0x07, 0x55, 0x5b, 0x55, 0x77, 0xa6, 0x38, 0x92, 0xfc,
-    0x59, 0xb6, 0x60, 0x12, 0x5f, 0x98, 0x01, 0xc1, 0x98, 0xdb, 0x7d, 0xff, 0x6f, 0x7a, 0xc5, 0x9e,
-    0xa4, 0xd1, 0x1e, 0xa2, 0x3a, 0xe0, 0x27, 0xd9, 0x18, 0x6d, 0x7f, 0xa8, 0xc1, 0x39, 0x3a, 0x52,
-    0x4c, 0x72, 0x7a, 0x08, 0xef, 0xb9, 0xa8, 0x73, 0x35, 0x31, 0x7c, 0xfb, 0x30, 0x2a, 0x98, 0x3f,
-    0xb2, 0xc0, 0x51, 0xa5, 0xb7, 0xce, 0xf1, 0xc8, 0x54, 0xf8, 0xec, 0x69, 0x28, 0x74, 0x53, 0x22,
-    0x75, 0x09, 0xeb, 0x85, 0x24, 0x44, 0x97, 0x83, 0x09, 0xb8, 0x49, 0x78, 0x53, 0x34, 0xcc, 0xdb,
-    0x22, 0x76, 0xf6, 0xd6, 0xc2, 0x15, 0xc7, 0x61, 0xaa, 0x27, 0xf7, 0x14, 0x1a, 0xb7, 0xad, 0xf6,
-    0xc0, 0x20, 0xaa, 0xb0, 0x33, 0xa8, 0x64, 0x7e, 0xe7, 0x69, 0x2d, 0x6b, 0xf8, 0x64, 0xee, 0xaf,
-    0xb0, 0x2d, 0x2f, 0xae, 0xba, 0xb2, 0x52, 0xa4, 0xba, 0x4f, 0xc9, 0x7e, 0x68, 0xc1, 0x49, 0xd9,
-    0x92, 0xdb, 0x5f, 0x83, 0xb9, 0xb3, 0xc6, 0x7a, 0xeb, 0x44, 0x3d, 0x63, 0x6b, 0x01, 0x00, 0xf9,
-    0x58, 0x09, 0x72, 0x22, 0x70, 0x15, 0x30, 0x1d, 0x4e, 0xb2, 0x97, 0x53, 0xc8, 0x89, 0x85, 0x5f,
-    0xd0, 0x1b, 0x00, 0x88, 0xf0, 0xc3, 0x86, 0x2c, 0x21, 0x07, 0xe9, 0x2c, 0x24, 0x8c, 0x94, 0x90,
-    0x31, 0xb1, 0x7b, 0xff, 0xf6, 0xdf, 0xf9, 0xd8, 0x4b, 0xdc, 0x7d, 0xaa, 0x18, 0xe7, 0x37, 0xd3,
-    0x48, 0xa5, 0x04, 0x28, 0xc0, 0x5d, 0xf9, 0x0b, 0xb0, 0x96, 0x97, 0x3a, 0x7c, 0xf7, 0x21, 0x57,
-    0xac, 0x9c, 0x98, 0x34, 0xb9, 0xfa, 0xb0, 0x49, 0x79, 0x5e, 0x86, 0xad, 0x29, 0x25, 0x31, 0x03,
-    0xdf, 0x1b, 0xd9, 0xbb, 0xcb, 0x4c, 0x8a, 0x8f, 0xbd, 0x58, 0x31, 0xc7, 0x0c, 0x02, 0x0e, 0xa5,
-    0xd5, 0x8e, 0x23, 0xce, 0x0e, 0x24, 0xd7, 0xd3, 0x01, 0x25, 0xf0, 0xf8, 0x1c, 0xae, 0x86, 0x4f,
-    0xad, 0xb2, 0xf4, 0xf1, 0xe3, 0xcc, 0x8d, 0xec, 0xae, 0x01, 0xc7, 0xa8, 0x8c, 0x5e, 0xe0, 0xe4,
-    0x0c, 0x5a, 0x0e, 0x48, 0xa3, 0x56, 0x2d, 0xa1, 0x31, 0x62, 0x56, 0x1c, 0x48, 0x7e, 0x4d, 0x46,
-    0x26, 0x10, 0x65, 0x1d, 0x45, 0x38, 0x1f, 0xbe, 0x7e, 0x5e, 0x70, 0x26, 0x5f, 0x13, 0xa7, 0xf1,
-    0x8b, 0xc8, 0x0c, 0xc8, 0x98, 0xbc, 0xbd, 0x7e, 0x17, 0xce, 0xad, 0x3c, 0x27, 0xd9, 0x35, 0x8a,
-    0xfd, 0x47, 0x83, 0x34, 0x43, 0x00, 0x1b, 0x19, 0xbf, 0xf3, 0xed, 0xf7, 0xae, 0x48, 0x65, 0xcc,
-    0x34, 0x3a, 0x62, 0x5a, 0x30, 0x45, 0xb5, 0x84, 0x55, 0x56, 0x21, 0x7b, 0xb9, 0xad, 0xc6, 0xbc,
-    0x16, 0x8e, 0xb0, 0x63, 0x94, 0x5a, 0xb7, 0xbf, 0x4f, 0x00, 0x23, 0x07, 0x2f, 0x1f, 0x40, 0x37,
-    0xc4, 0xf0, 0x88, 0x7a, 0xe6, 0x37, 0x89, 0xfd, 0xbb, 0xfd, 0x48, 0x88, 0x70, 0x3b, 0x69, 0x5a,
-    0x46, 0xdb, 0xbb, 0x75, 0x06, 0xc7, 0xff, 0x39, 0xd2, 0x9b, 0x79, 0x3c, 0x0e, 0xa5, 0xdd, 0x64,
-    0x80, 0x12, 0x25, 0x09, 0x3f, 0x07, 0x0c, 0x0e, 0xc7, 0xaf, 0x2d, 0x9e, 0xc1, 0xc9, 0x34, 0x6a,
-    0xf9, 0xba, 0x89, 0x99, 0x91, 0x2f, 0xc6, 0xc2, 0x77, 0xe8, 0x92, 0xd5, 0x05, 0x01, 0x3e, 0x18,
-    0x2f, 0x8b, 0xd1, 0x4c, 0x46, 0x00, 0x13, 0xe1, 0x28, 0x99, 0x34, 0xd2, 0x9f, 0xf5, 0xb7, 0x27,
-    0xf1, 0x89, 0xe6, 0x91, 0x9e, 0x8a, 0x78, 0x42, 0x64, 0xde, 0xd8, 0x50, 0xc0, 0x70, 0xfb, 0x9b,
-    0xad, 0x95, 0x11, 0xc1, 0x3f, 0xa7, 0x1c, 0xfc, 0x28, 0xe8, 0xad, 0x25, 0x5b, 0x13, 0xb5, 0x0b,
-    0xb8, 0x48, 0xa4, 0x25, 0xec, 0xfc, 0xc9, 0x0d, 0x29, 0xc0, 0x47, 0x86, 0xcf, 0xf4, 0xe6, 0x74,
-    0x55, 0x09, 0x6d, 0x3e, 0xef, 0xc4, 0xdb, 0x49, 0xe7, 0x01, 0xf9, 0x81, 0x0e, 0x15, 0x0d, 0x3d,
-    0xd7, 0x28, 0x4c, 0x34, 0x39, 0x39, 0x98, 0xec, 0x0e, 0xd2, 0x02, 0x5b, 0x8f, 0x0c, 0x8e, 0xed,
-    0xa7, 0xdc, 0x36, 0x48, 0x71, 0x72, 0xef, 0x7a, 0xfc, 0x9f, 0x92, 0xfb, 0x00, 0x4a, 0xea, 0x2e,
-    0xf3, 0xcc, 0xe0, 0x87, 0x89, 0x2a, 0xc0, 0x2d, 0xe3, 0xf7, 0x2d, 0x8e, 0xc2, 0xd6, 0xe7, 0xfe,
-    0xec, 0x7a, 0x48, 0xc5, 0x6e, 0x0e, 0xbe, 0x07, 0xe8, 0x97, 0x0d, 0x24, 0xd1, 0xa0, 0xa2, 0x9e,
-    0x05, 0x19, 0x5e, 0x18, 0xfa, 0x5f, 0xd6, 0xd0, 0x7c, 0x21, 0x8f, 0xf9, 0xc9, 0xc3, 0x5c, 0x24,
-    0xf8, 0x5f, 0x6f, 0xe4, 0xb8, 0xfa, 0xab, 0xe7, 0xa2, 0x81, 0x33, 0x03, 0x97, 0x80, 0xdb, 0x7c,
-    0xd0, 0xcd, 0x05, 0x33, 0x84, 0xec, 0x27, 0x9f, 0x0a, 0xb5, 0x9d, 0xcf, 0x7c, 0x34, 0x03, 0xe0,
-    0x1c, 0x43, 0xc1, 0x65, 0x3f, 0x01, 0x9d, 0x1a, 0x7c, 0x9f, 0xf7, 0xc6, 0xed, 0x39, 0x52, 0x8e,
-    0xf0, 0x0f, 0xa3, 0x74, 0x2d, 0xce, 0x93, 0x22, 0x75, 0xf0, 0x6d, 0x06, 0xfd, 0x54, 0xec, 0x1a,
-    0x31, 0xc8, 0xe5, 0x21, 0xcb, 0xbf, 0xac, 0x88, 0xcb, 0x30, 0x3a, 0xf0, 0x3d, 0xe6, 0x65, 0x79,
-    0x54, 0x69, 0xa1, 0x80, 0x56, 0x52, 0xda, 0x7a, 0x76, 0xef, 0xfb, 0x27, 0xc3, 0x92, 0x53, 0xca,
-    0x19, 0x29, 0x73, 0x81, 0x1a, 0x96, 0xc8, 0x51, 0x10, 0x0b, 0x10, 0x93, 0x37, 0xb5, 0xb0, 0xe6,
-    0xe4, 0x80, 0xdb, 0xe0, 0x91, 0x6b, 0x8c, 0x1c, 0x7e, 0x8e, 0x51, 0x6f, 0xee, 0xd5, 0x87, 0x0a,
-    0x18, 0x7f, 0x50, 0x98, 0x3d, 0x9f, 0x92, 0x7b, 0xd5, 0x83, 0xeb, 0x30, 0x6d, 0x80, 0x40, 0x64,
-    0xa9, 0x57, 0x15, 0x80, 0x5a, 0x4e, 0x7e, 0x98, 0x96, 0x4a, 0x8e, 0xc3, 0xfe, 0x4d, 0x6d, 0x02,
-    0x1f, 0x5b, 0x6b, 0x99, 0x2f, 0x2d, 0x8a, 0x71, 0x60, 0x13, 0xc4, 0x38, 0x00, 0x82, 0x9a, 0xc3,
-    0x02, 0x0a, 0x36, 0x0c, 0xb0, 0x12, 0x67, 0x86, 0x63, 0x85, 0x34, 0x87, 0x7d, 0x67, 0x47, 0xc7,
-    0x73, 0xa3, 0x8f, 0x7b, 0x3e, 0xf8, 0x6d, 0x5b, 0x37, 0x4c, 0x29, 0xf6, 0x83, 0x2b, 0xd1, 0xf3,
-    0xaa, 0x4f, 0xec, 0x6a, 0xad, 0xba, 0x49, 0x1a, 0x4e, 0x61, 0xb1, 0xb0, 0x6f, 0x05, 0xe4, 0x44,
-    0x7c, 0x30, 0x36, 0x0a, 0x28, 0x4d, 0x60, 0xc0, 0xba, 0xb5, 0xcc, 0x5d, 0x5d, 0xbb, 0x60, 0x12,
-    0x5f, 0x00, 0x3f, 0xa7, 0xf0, 0xaf, 0x34, 0x62, 0xdf, 0xdb, 0xff, 0x34, 0xde, 0x19, 0x27, 0x11,
-    0x78, 0x01, 0xc2, 0x4d, 0xe8, 0xd1, 0x9e, 0xca, 0xff, 0x02, 0x2d, 0xbd, 0xf9, 0x10, 0x0b, 0xdd,
-    0x1a, 0xdc, 0xac, 0x77, 0x64, 0x88, 0xb5, 0xeb, 0xba, 0xb7, 0xc0, 0xb7, 0x2d, 0xcf, 0x0e, 0x4a,
-    0xa3, 0x56, 0x43, 0xd1, 0xb2, 0x92, 0x6e, 0x03, 0x2a, 0x1f, 0x9b, 0x4c, 0x5d, 0x65, 0x61, 0x80,
-    0x41, 0x17, 0x86, 0x01, 0xcb, 0xc0, 0xcc, 0x73, 0xda, 0x9c, 0x9e, 0x5e, 0x93, 0x90, 0x11, 0xcf,
-    0xc3, 0x0c, 0x95, 0x34, 0x83, 0x00, 0x02, 0xad, 0xcd, 0x1c, 0x23, 0xca, 0x90, 0xd1, 0x63, 0xd9,
-    0xee, 0x50, 0x05, 0x28, 0xf2, 0xe6, 0x77, 0x4c, 0x1a, 0x94, 0xac, 0xed, 0x48, 0x62, 0xf6, 0xbb,
-    0x76, 0xf8, 0x85, 0xe0, 0x4f, 0x3a, 0x2c, 0x19, 0xd8, 0xf1, 0x09, 0xc4, 0x36, 0x58, 0xdb, 0xaa,
-    0x30, 0x0d, 0xf1, 0x65, 0xe0, 0x43, 0xa3, 0x7e, 0x50, 0x17, 0x05, 0x99, 0x87, 0xc4, 0x03, 0x84,
-    0x83, 0x92, 0xd6, 0x67, 0x01, 0x20, 0x63, 0x78, 0x8a, 0xb4, 0xf7, 0xde, 0x75, 0x54, 0x85, 0x47,
-    0x2f, 0xc3, 0x37, 0xc1, 0xaa, 0xa8, 0xde, 0xc9, 0x88, 0x86, 0xe0, 0xe4, 0xaa, 0x9d, 0x35, 0xba,
-    0x49, 0xd1, 0x44, 0x1a, 0x5a, 0xc3, 0x62, 0xeb, 0xb6, 0x4f, 0x63, 0x7c, 0x3e, 0x8e, 0x4b, 0x2d,
-    0xb0, 0xd6, 0xd8, 0x2f, 0x3a, 0xbc, 0x80, 0x56, 0xbf, 0xc1, 0x14, 0x23, 0x4f, 0x12, 0x72, 0xfe,
-    0xed, 0x77, 0xd6, 0x52, 0x8b, 0x05, 0x3c, 0x7c, 0x0a, 0x1b, 0x04, 0x55, 0x21, 0x47, 0x1c, 0x16,
-    0x25, 0x60, 0x86, 0x01, 0xad, 0x09, 0x1b, 0xe6, 0x66, 0x88, 0x47, 0x66, 0x12, 0x2e, 0x5c, 0x5a,
-    0xd3, 0xe8, 0x3d, 0x76, 0xf4, 0x95, 0x4a, 0x3b, 0x4e, 0x8d, 0xb2, 0xc0, 0xca, 0x2a, 0xac, 0xbe,
-    0x10, 0xbb, 0x5f, 0x9e, 0xd7, 0x9f, 0x25, 0x80, 0x69, 0x1b, 0xff, 0xcf, 0xe5, 0x42, 0xde, 0xcc,
-    0xf0, 0xe3, 0x56, 0x85, 0x16, 0x53, 0x40, 0x60, 0x77, 0x55, 0xc8, 0x8b, 0xc0, 0x45, 0x80, 0xe7,
-    0x00, 0x0f, 0x0d, 0x63, 0x0e, 0x5f, 0xb3, 0xc0, 0x73, 0x78, 0xf7, 0xa3, 0x97, 0x87, 0xc5, 0x1f,
-    0x0e, 0x49, 0x93, 0x5e, 0x02, 0x50, 0x73, 0x70, 0xf2, 0xbf, 0xcd, 0x83, 0xa0, 0x81, 0x3f, 0x50,
-    0x25, 0xd5, 0xeb, 0x00, 0xb7, 0xb2, 0xa7, 0x35, 0x7f, 0x7c, 0x44, 0x73, 0xf0, 0x72, 0x44, 0x86,
-    0x69, 0x27, 0x8d, 0x20, 0x16, 0xf4, 0x15, 0x4d, 0x2e, 0x7e, 0xaf, 0xb2, 0x12, 0x81, 0xe6, 0x38,
-    0xe4, 0xb4, 0xb4, 0xd7, 0xa9, 0xfc, 0x5a, 0x1c, 0xe9, 0x3d, 0x7a, 0xc4, 0xf6, 0x91, 0x2c, 0x98,
-    0x00, 0x49, 0x3d, 0xce, 0x47, 0xc8, 0x8f, 0xbf, 0xc9, 0xed, 0xe7, 0x87, 0x1e, 0x75, 0x7d, 0xf6,
-    0xbb, 0x4e, 0x99, 0x52, 0xc0, 0xd2, 0x48, 0x25, 0xc4, 0xc5, 0x93, 0x97, 0xdb, 0x4b, 0x87, 0x33,
-    0xca, 0x64, 0x50, 0x0a, 0x30, 0xa6, 0x50, 0x94, 0xfe, 0x56, 0xa4, 0xbb, 0xc0, 0x24, 0x56, 0xb0,
-    0xd7, 0x55, 0x74, 0x0c, 0x90, 0x6d, 0xe7, 0x4a, 0x00, 0xa0, 0xee, 0x3c, 0x51, 0xdf, 0xf0, 0xec,
-    0x5b, 0xfc, 0xbf, 0xf1, 0xb9, 0xb4, 0x98, 0x00, 0xda, 0x55, 0x45, 0xa8, 0xf0, 0x02, 0xa8, 0xd6,
-    0xe0, 0xe4, 0x54, 0x4f, 0x5d, 0x75, 0xb1, 0xdc, 0xf2, 0x22, 0x80, 0xff, 0xeb, 0x13, 0xf7, 0xb1,
-    0x14, 0xed, 0x07, 0x24, 0xd1, 0xab, 0xe1, 0xc8, 0x53, 0x52, 0x60, 0x25, 0xc8, 0x89, 0xe0, 0x30,
-    0xd2, 0xa4, 0x61, 0xf6, 0x65, 0xc7, 0x3a, 0x19, 0x79, 0x2a, 0x35, 0x03, 0x22, 0x88, 0x65, 0x1f,
-    0x92, 0x65, 0x2d, 0xb1, 0x71, 0xc2, 0x04, 0x16, 0x96, 0x18, 0x2c, 0xa4, 0xd0, 0xc0, 0xdc, 0xac,
-    0x3d, 0xb7, 0x82, 0xb2, 0x3f, 0xc0, 0x1b, 0xff, 0xae, 0x5c, 0xb8, 0x63, 0xd2, 0xb3, 0xd0, 0x55,
-    0xfa, 0xb0, 0xf3, 0xd1, 0xc2, 0x55, 0xb5, 0x6a, 0x5d, 0x60, 0x3d, 0x94, 0xa4, 0x26, 0x6f, 0x5e,
-    0x8e, 0x01, 0xf8, 0xe1, 0xd4, 0x1a, 0x0c, 0xd7, 0x32, 0xcd, 0xf0, 0xdc, 0x70, 0x04, 0x61, 0x42,
-    0xd0, 0x81, 0xaf, 0x12, 0x04, 0x54, 0x76, 0x18, 0x3a, 0x57, 0x09, 0xbe, 0x5b, 0xa8, 0xf0, 0x72,
-    0xa8, 0xb6, 0x60, 0xe4, 0xc2, 0xb5, 0x01, 0x1b, 0x87, 0x91, 0x24, 0x5a, 0xbf, 0x07, 0x95, 0x1d,
-    0xac, 0x1c, 0xcf, 0x66, 0x8d, 0x38, 0x16, 0xf4, 0x0a, 0xe5, 0xd9, 0x58, 0x2f, 0x16, 0x6d, 0x04,
-    0x18, 0x9a, 0x06, 0x01, 0xdc, 0xff, 0x1c, 0xec, 0x23, 0x7c, 0x19, 0xfc, 0x6a, 0x73, 0x9e, 0xbb,
-    0x9c, 0x01, 0x40, 0x7c, 0xc1, 0x80, 0x5d, 0x46, 0x98, 0xe1, 0x92, 0x04, 0xe7, 0x32, 0xc4, 0x1d,
-    0xb8, 0x0e, 0x23, 0x4f, 0x41, 0xc5, 0x81, 0xba, 0xfb, 0x3f, 0xad, 0xb6, 0x94, 0x76, 0xdc, 0x9e,
-    0x0f, 0x9b, 0x33, 0xcf, 0xff, 0xed, 0xbf, 0xf3, 0xd1, 0xc1, 0x1f, 0x59, 0x54, 0xf0, 0xa7, 0x9d,
-    0x1d, 0x3c, 0x5f, 0x28, 0x33, 0x78, 0x9f, 0x85, 0x58, 0x8b, 0x6e, 0xad, 0x23, 0x17, 0x60, 0xc0,
-    0x10, 0x45, 0x16, 0xa0, 0xe4, 0x44, 0x7c, 0x2c, 0x94, 0x1d, 0x24, 0x5a, 0xbf, 0x00, 0x95, 0x17,
-    0x7c, 0x1c, 0x55, 0x40, 0x73, 0x63, 0x44, 0x0a, 0x74, 0xe4, 0xbc, 0xe0, 0xec, 0x7a, 0x11, 0xdd,
-    0x39, 0x2f, 0x24, 0xb8, 0x49, 0xd1, 0x4c, 0x1a, 0xba, 0x43, 0x22, 0x74, 0x0a, 0x32, 0x9a, 0xaf,
-    0x00, 0x0d, 0x66, 0xd3, 0x69, 0x65, 0x6a, 0x1f, 0x80, 0x41, 0xc5, 0xe1, 0xdc, 0xc8, 0x5f, 0xac,
-    0xa1, 0x80, 0x90, 0xee, 0x85, 0x78, 0x1f, 0x22, 0x7c, 0x1b, 0x69, 0xdb, 0x35, 0x87, 0x8c, 0xcb,
-    0x31, 0x69, 0x7c, 0xbf, 0x99, 0xa3, 0xe3, 0xf9, 0x1c, 0xce, 0x82, 0x3b, 0xd7, 0x2f, 0xa5, 0x83,
-    0xfa, 0xb9, 0x31, 0x62, 0xf2, 0x96, 0x85, 0xb2, 0x04, 0x94, 0x8c, 0x18, 0xff, 0xcd, 0x2a, 0x42,
-    0x0c, 0x02, 0xa9, 0x4f, 0xbd, 0x6a, 0xc0, 0x82, 0x9b, 0x4d, 0x25, 0x80, 0x87, 0x22, 0x5b, 0xe0,
-    0x6b, 0x77, 0xba, 0xa3, 0x40, 0xdd, 0x03, 0x9d, 0x19, 0x11, 0xbc, 0x0d, 0xc6, 0x89, 0x35, 0xd6,
-    0xa3, 0x88, 0xaf, 0x17, 0xad, 0x3d, 0xb0, 0x26, 0x42, 0x61, 0xb0, 0x72, 0x08, 0x9a, 0xdd, 0x42,
-    0x83, 0x92, 0x45, 0x37, 0x3a, 0x97, 0x93, 0x55, 0xb4, 0x38, 0xa3, 0x42, 0x2a, 0x62, 0xe2, 0x67,
-    0x4d, 0x1b, 0x98, 0xdb, 0x5d, 0xff, 0xd4, 0xfe, 0x02, 0x80, 0x81, 0x0c, 0xaa, 0x06, 0xa2, 0x96,
-    0xab, 0x20, 0xe4, 0x96, 0xeb, 0xe9, 0x1a, 0xae, 0xb2, 0xae, 0x0c, 0xbf, 0x42, 0xa4, 0xd6, 0x02,
-    0x16, 0x39, 0x4a, 0x9c, 0x73, 0x33, 0xb6, 0xcf, 0xf8, 0x48, 0x1e, 0xf9, 0xe7, 0xdf, 0xb3, 0xb4,
-    0xa1, 0x85, 0x23, 0x81, 0x62, 0xe0, 0x4b, 0xf2, 0x76, 0xb9, 0xc4, 0xf2, 0x61, 0x56, 0x7d, 0xba,
-    0x86, 0x01, 0x17, 0x86, 0x48, 0xe0, 0x14, 0x61, 0x07, 0xbf, 0x5c, 0x58, 0xd0, 0xe1, 0xfc, 0xb3,
-    0x56, 0x1b, 0xe7, 0x46, 0x9e, 0x15, 0x11, 0x19, 0x12, 0x39, 0x57, 0xf8, 0xdd, 0xe0, 0x84, 0xf8,
-    0x0c, 0x6e, 0x27, 0xd3, 0x9f, 0x22, 0xd5, 0x50, 0x71, 0x48, 0xa2, 0x8a, 0xe0, 0xe4, 0xa5, 0x85,
-    0x5a, 0xed, 0x00, 0x24, 0xb2, 0x7f, 0x9f, 0xa5, 0x41, 0xf5, 0xc1, 0xc9, 0x55, 0x47, 0xf1, 0xf5,
-    0x63, 0xb8, 0xc9, 0x8b, 0x17, 0x70, 0x63, 0xd5, 0xee, 0xef, 0xc9, 0x78, 0x47, 0xc1, 0x9d, 0x13,
-    0x00, 0xc4, 0xf2, 0x8d, 0xf6, 0x18, 0x7f, 0xe7, 0xcc, 0xab, 0x86, 0xcd, 0xa8, 0x1b, 0x13, 0xd1,
-    0x4c, 0x33, 0x96, 0x98, 0x81, 0xbc, 0x44, 0x1a, 0x0f, 0x91, 0x21, 0xab, 0x98, 0xaa, 0x92, 0x04,
-    0xaf, 0x32, 0x75, 0x1b, 0x26, 0xf0, 0xf5, 0x60, 0xe0, 0x16, 0x60, 0xfe, 0xb9, 0xf8, 0x78, 0x13,
-    0xb7, 0xd0, 0xb6, 0x9d, 0xc3, 0x00, 0x55, 0x46, 0x59, 0x5d, 0xf0, 0xe1, 0x38, 0x5a, 0xcb, 0x01,
-    0xec, 0xa2, 0x02, 0x31, 0xf5, 0x0c, 0xff, 0xae, 0xe2, 0xcd, 0xa3, 0x09, 0x70, 0x00, 0x7b, 0x78,
-    0x29, 0x86, 0x05, 0x86, 0x62, 0x18, 0x05, 0x84, 0x09, 0xaa, 0x58, 0x30, 0xff, 0x9d, 0x10, 0x2d,
-    0xb7, 0x79, 0xfb, 0xd7, 0x83, 0x92, 0x07, 0x6e, 0x6c, 0xde, 0x02, 0xf4, 0xb4, 0xa2, 0xb7, 0x01,
-    0xc8, 0x8b, 0x55, 0x14, 0x2e, 0xbd, 0x6f, 0xf4, 0x4b, 0x75, 0xc6, 0x00, 0x0e, 0x48, 0x1b, 0x56,
-    0x5e, 0x8d, 0xaf, 0x5d, 0x6f, 0xbd, 0x88, 0xc4, 0x0c, 0x2e, 0x04, 0xfa, 0x69, 0x06, 0x53, 0xd4,
-    0x50, 0x15, 0xb2, 0x40, 0x82, 0x51, 0x9a, 0xb2, 0x54, 0x73, 0x15, 0x55, 0xf2, 0x91, 0x3c, 0xd3,
-    0x92, 0x66, 0xf4, 0xf0, 0x92, 0xef, 0xf8, 0x97, 0x26, 0x7c, 0x1d, 0xfa, 0x93, 0xbf, 0x08, 0x0f,
-    0x9c, 0x30, 0x21, 0x62, 0xb5, 0x44, 0xab, 0xb4, 0x00, 0x8a, 0x85, 0x83, 0xfa, 0x1e, 0xbb, 0xc3,
-    0x54, 0x72, 0x80, 0x18, 0xca, 0xa7, 0xae, 0xe2, 0xf1, 0x48, 0x07, 0xfa, 0xd3, 0x43, 0x56, 0x11,
-    0x4a, 0x3b, 0x02, 0x31, 0x66, 0x0c, 0x7f, 0xe7, 0x4c, 0x9b, 0x7d, 0x94, 0xcc, 0x90, 0x46, 0x06,
-    0x36, 0x94, 0x70, 0x9a, 0x58, 0x59, 0x1e, 0xe0, 0x5e, 0x9b, 0x15, 0xe2, 0xae, 0x23, 0x1a, 0x52,
-    0xbe, 0xfd, 0xfb, 0x15, 0xd7, 0xce, 0xc5, 0xcf, 0x42, 0x78, 0x00, 0x36, 0xc8, 0x88, 0xea, 0x54,
-    0x1c, 0x94, 0x7f, 0xbc, 0x2e, 0x7b, 0x44, 0x5c, 0x09, 0x64, 0xdb, 0xf0, 0x63, 0xb8, 0xcb, 0x8b,
-    0x3f, 0x5b, 0x8f, 0x50, 0xdf, 0xbd, 0xc8, 0xec, 0x7c, 0xf1, 0xde, 0xd0, 0xc0, 0xf3, 0x89, 0x03,
-    0x62, 0x4e, 0xba, 0x88, 0x65, 0x3d, 0xc0, 0xb1, 0x9c, 0xc1, 0xf6, 0xd2, 0xa3, 0xa4, 0x8c, 0x32,
-    0x60, 0x9a, 0x18, 0x36, 0xcf, 0x9a, 0xe6, 0x45, 0x57, 0x66, 0xe6, 0x85, 0x01, 0x66, 0x51, 0x96,
-    0x61, 0xec, 0xb2, 0xbf, 0xcf, 0x28, 0x97, 0x8d, 0x5d, 0xd5, 0x6c, 0x65, 0xc1, 0x23, 0x1f, 0x22,
-    0x05, 0xd6, 0x2a, 0x18, 0x3f, 0x2d, 0xe0, 0x12, 0xc3, 0x78, 0xbf, 0xf3, 0x85, 0x79, 0x96, 0x8b,
-    0x87, 0x75, 0x48, 0x33, 0x95, 0x9b, 0x82, 0xb2, 0x58, 0x4a, 0xc1, 0x80, 0x47, 0x46, 0x46, 0x29,
-    0xc1, 0x80, 0x03, 0xa8, 0xc7, 0x3e, 0x00, 0xbe, 0xb2, 0xc3, 0x14, 0x06, 0x48, 0x2e, 0xfc, 0x3b,
-    0x95, 0x0c, 0x7f, 0xe7, 0xf0, 0x3b, 0xec, 0x0a, 0x9e, 0x00, 0x97, 0x8a, 0xa2, 0xe9, 0x55, 0x2d,
-    0x38, 0x3a, 0xfb, 0xe7, 0x7e, 0x77, 0x72, 0x6a, 0xc7, 0x1b, 0x4e, 0x18, 0xbc, 0x20, 0x4b, 0x6b,
-    0x5f, 0xbf, 0xf1, 0x0e, 0x11, 0x68, 0xf8, 0xc9, 0x00, 0xd6, 0x90, 0x9b, 0xbc, 0x00, 0xca, 0xbe,
-    0xf2, 0x7a, 0xe1, 0x4f, 0xc6, 0x8d, 0xb6, 0x6b, 0x7d, 0x77, 0x7b, 0x32, 0x69, 0x56, 0x50, 0xc4,
-    0x50, 0x35, 0xc0, 0xe0, 0xe8, 0xc6, 0xf5, 0x77, 0x73, 0xc0, 0x00, 0xb3, 0xe1, 0x0f, 0x71, 0x0b,
-    0x80, 0x35, 0x09, 0x7f, 0x44, 0x2d, 0xbb, 0x4f, 0x70, 0xae, 0x69, 0x99, 0x19, 0xed, 0xaa, 0xe3,
-    0x31, 0x3e, 0x37, 0xcb, 0x95, 0x9a, 0xc0, 0x05, 0xbe, 0x7d, 0xb4, 0xed, 0x72, 0xd7, 0x41, 0x82,
-    0xa4, 0x05, 0x19, 0x21, 0xc9, 0x38, 0x28, 0xb0, 0xd3, 0xfb, 0x01, 0x51, 0x86, 0x86, 0x7f, 0xd6,
-    0xa6, 0x86, 0x60, 0x13, 0x83, 0x98, 0xd1, 0xaf, 0xb9, 0x4f, 0x10, 0x73, 0xb6, 0x28, 0x2f, 0xf2,
-    0xda, 0x53, 0x6d, 0x19, 0xbd, 0x78, 0x77, 0xf7, 0x05, 0x36, 0x7f, 0x22, 0x78, 0x2d, 0x14, 0x62,
-    0xc5, 0xdd, 0x5f, 0xa8, 0x12, 0x5d, 0x7f, 0x80, 0x9d, 0xd9, 0x41, 0x67, 0xd4, 0x30, 0x1a, 0xbe,
-    0x59, 0xf8, 0xb1, 0xdc, 0xa4, 0xc5, 0xbf, 0xb3, 0xc7, 0xaf, 0x05, 0x5e, 0xc1, 0xc9, 0x26, 0x9f,
-    0x89, 0x3a, 0x1a, 0x41, 0x6c, 0xd1, 0xc2, 0x07, 0x69, 0xcf, 0xff, 0xaf, 0xa1, 0x2d, 0x5f, 0xaa,
-    0xeb, 0xc0, 0xd5, 0x3d, 0x34, 0x1b, 0x01, 0xdd, 0x08, 0xdc, 0x15, 0xdc, 0x6f, 0xda, 0x44, 0x35,
-    0x95, 0x05, 0xb0, 0x13, 0x58, 0x66, 0x7e, 0xa8, 0x4d, 0x55, 0xb0, 0xfe, 0xc8, 0x49, 0xcd, 0xe3,
-    0x5e, 0xfb, 0x9a, 0x1a, 0x9b, 0xd7, 0x3f, 0xe9, 0x4c, 0xe8, 0x1d, 0x0b, 0x67, 0xa5, 0x0d, 0x82,
-    0x17, 0x4c, 0x35, 0x5e, 0x86, 0xa1, 0x22, 0x20, 0xf1, 0x23, 0x9c, 0x55, 0x21, 0xb3, 0xf0, 0xc0,
-    0x67, 0x4c, 0xc3, 0xc3, 0xe0, 0xcf, 0x44, 0xeb, 0xcc, 0x8c, 0xb3, 0x0a, 0x77, 0x0c, 0x76, 0x22,
-    0x95, 0xe7, 0xc1, 0xa5, 0xb1, 0xdf, 0x82, 0xb8, 0x00, 0xb0, 0xae, 0x58, 0x0c, 0xff, 0x02, 0xf1,
-    0xe1, 0x0c, 0x2b, 0x62, 0x0f, 0xc7, 0x18, 0xcd, 0xbe, 0x77, 0xee, 0x15, 0x49, 0x53, 0xa1, 0x14,
-    0xc9, 0x6e, 0x98, 0xc1, 0xef, 0xd1, 0xbe, 0x0d, 0xd7, 0x5a, 0xfe, 0x61, 0xdf, 0x11, 0xc5, 0x34,
-    0x2a, 0xfe, 0x58, 0x39, 0x46, 0x8d, 0x59, 0x3c, 0x58, 0xcd, 0x0b, 0x01, 0x55, 0x00, 0x49, 0xbd,
-    0xfe, 0x44, 0x37, 0x8c, 0xae, 0x12, 0x7b, 0x25, 0x03, 0x70, 0x09, 0x5e, 0xc0, 0xb6, 0x8b, 0x72,
-    0x00, 0xb0, 0x8d, 0x83, 0xd5, 0x10, 0xbe, 0xda, 0x38, 0x42, 0xaf, 0x8b, 0xb1, 0xcc, 0x54, 0x16,
-    0x62, 0x86, 0xff, 0x9c, 0x03, 0xbf, 0x8d, 0x9b, 0x1e, 0x1b, 0x3d, 0x1c, 0x6b, 0x78, 0xd7, 0x08,
-    0xfc, 0xc7, 0x24, 0xdb, 0xc6, 0xff, 0xed, 0x11, 0xa7, 0x86, 0x14, 0x47, 0x0e, 0x5e, 0xf6, 0x96,
-    0xb1, 0x79, 0x03, 0x4a, 0x0b, 0x53, 0xfd, 0x93, 0x47, 0x1b, 0x6c, 0x25, 0x6a, 0x90, 0xf4, 0x21,
-    0x00, 0x7b, 0xd6, 0x96, 0xbe, 0x73, 0x3c, 0xe2, 0xd4, 0xe2, 0xf6, 0xd2, 0x23, 0xe9, 0x0d, 0xb2,
-    0x4a, 0x2f, 0xe6, 0x1f, 0x3d, 0x89, 0x42, 0x79, 0x62, 0xbf, 0x02, 0xf0, 0x86, 0x0c, 0xd7, 0x3b,
-    0x04, 0x95, 0x44, 0x18, 0x5c, 0xe4, 0x6d, 0x7c, 0x8d, 0xb4, 0x16, 0x55, 0xa3, 0xf3, 0xa9, 0xf7,
-    0x4b, 0x54, 0x20, 0x3d, 0x28, 0x39, 0x97, 0x24, 0x5c, 0x00, 0x99, 0xdc, 0x7f, 0xe7, 0x92, 0x82,
-    0x5b, 0x83, 0x3b, 0x81, 0x8e, 0xe3, 0x4e, 0x2d, 0x7c, 0x03, 0x1e, 0xb2, 0xcd, 0x7b, 0x39, 0x22,
-    0x8d, 0x58, 0xfe, 0xba, 0xc5, 0xa2, 0xe3, 0x6c, 0xc3, 0xf2, 0x72, 0x3a, 0x30, 0xbc, 0xba, 0x69,
-    0x06, 0xf9, 0x46, 0x21, 0xa1, 0x80, 0x83, 0x62, 0xaa, 0xa0, 0xd8, 0x8b, 0xe7, 0x27, 0x28, 0xd5,
-    0xd7, 0xec, 0xae, 0x15, 0xfd, 0x92, 0x63, 0x64, 0x1c, 0x04, 0xab, 0x23, 0x1b, 0x77, 0xf1, 0x5e,
-    0x34, 0x93, 0x01, 0xc9, 0x06, 0xdb, 0xcf, 0x98, 0xc4, 0x39, 0x31, 0xbf, 0x70, 0xde, 0x69, 0x47,
-    0x6f, 0x75, 0xe0, 0x81, 0x0a, 0xea, 0x89, 0x26, 0x4d, 0xc8, 0x3a, 0xc0, 0xf0, 0xbc, 0x06, 0xd7,
-    0xfb, 0xbc, 0xc7, 0x97, 0x7e, 0x4b, 0xfb, 0xcd, 0x8b, 0xfe, 0xee, 0xdb, 0xd5, 0x54, 0xbe, 0x5d,
-    0x05, 0xf3, 0x8f, 0x7e, 0x8e, 0xe9, 0x78, 0x1f, 0xcf, 0xfa, 0xae, 0x21, 0x91, 0x15, 0x80, 0x17,
-    0x78, 0x55, 0xc4, 0x21, 0x44, 0xdd, 0xbf, 0xaf, 0x6f, 0xd2, 0x11, 0xcb, 0x9a, 0x8a, 0x34, 0xa5,
-    0xf0, 0x2d, 0x51, 0x42, 0x31, 0xce, 0xf2, 0x8e, 0xa4, 0x12, 0x16, 0x71, 0xb6, 0x8a, 0x49, 0x54,
-    0x6b, 0x0e, 0x79, 0xa6, 0x8f, 0xf2, 0xe3, 0x00, 0x3b, 0x4b, 0xaf, 0xcf, 0x02, 0x41, 0xeb, 0xf0,
-    0x75, 0xd1, 0xb7, 0xb8, 0x92, 0x86, 0xfd, 0x25, 0x08, 0x7c, 0xb3, 0xdf, 0x8b, 0x5e, 0x66, 0xbd,
-    0x1c, 0x91, 0x46, 0xac, 0x5d, 0xbd, 0xe3, 0xaa, 0x15, 0xf1, 0xb7, 0x04, 0xff, 0x31, 0x65, 0xbb,
-    0x81, 0x4d, 0x9b, 0x9d, 0x0d, 0x02, 0xfc, 0xc2, 0x91, 0x70, 0x0b, 0x70, 0x1d, 0xa4, 0x0a, 0xa2,
-    0xba, 0x60, 0x58, 0x81, 0x5d, 0x13, 0xd1, 0xbe, 0xe7, 0x81, 0x9a, 0x4c, 0xed, 0x81, 0x72, 0x22,
-    0xaa, 0xa9, 0x66, 0xc6, 0x12, 0x51, 0x58, 0x72, 0x5a, 0x13, 0xde, 0xcc, 0x18, 0xab, 0x75, 0x67,
-    0xbe, 0x28, 0x7c, 0x9e, 0x88, 0x2d, 0x42, 0xc8, 0xe2, 0xe0, 0x61, 0x62, 0xe0, 0x84, 0x69, 0xef,
-    0xdf, 0x35, 0x5a, 0xf9, 0xfd, 0x19, 0x17, 0x4d, 0xf2, 0x37, 0x29, 0xfc, 0xe0, 0x39, 0x17, 0x6f,
-    0xab, 0xff, 0x8d, 0x8a, 0x2d, 0xa2, 0xd6, 0x55, 0x37, 0x8c, 0xa1, 0x43, 0xb9, 0x9f, 0x90, 0x8d,
-    0x7c, 0x1c, 0xb7, 0xa5, 0x5e, 0x10, 0xdf, 0xab, 0x75, 0x49, 0xc1, 0xc9, 0xd4, 0xcf, 0xaf, 0x63,
-    0x24, 0x99, 0xab, 0x07, 0xef, 0x51, 0x9b, 0xdb, 0xfa, 0xc2, 0xe3, 0x5f, 0xa6, 0x19, 0x21, 0x83,
-    0x04, 0xed, 0x00, 0x92, 0x47, 0xa6, 0xd5, 0xc0, 0x7f, 0x9c, 0x30, 0x13, 0x78, 0x16, 0x44, 0x40,
-    0xaa, 0xae, 0xef, 0xf0, 0x4b, 0x13, 0x46, 0x1f, 0x05, 0x64, 0x11, 0xd3, 0x13, 0xdb, 0x66, 0x86,
-    0x30, 0x31, 0x77, 0x4d, 0xf0, 0x32, 0x88, 0xa4, 0x8d, 0x9c, 0xf7, 0xef, 0x57, 0x80, 0xc3, 0x84,
-    0x27, 0x34, 0x9c, 0x1b, 0x6d, 0x9f, 0x98, 0x11, 0xf8, 0x63, 0xc9, 0xfd, 0x2c, 0x29, 0xf1, 0xa8,
-    0x4e, 0x19, 0x5c, 0x41, 0x00, 0xa5, 0x17, 0xcc, 0x0c, 0x91, 0x5a, 0xbe, 0x93, 0x06, 0x84, 0xdb,
-    0x0c, 0xa3, 0x35, 0x4f, 0xdc, 0xc5, 0x35, 0xa7, 0x61, 0x45, 0xf7, 0x84, 0xd3, 0xe1, 0xae, 0x6c,
-    0x02, 0x55, 0x94, 0x30, 0x79, 0xc3, 0xaa, 0x87, 0xab, 0x6e, 0xf8, 0x70, 0x80, 0x7b, 0xea, 0xa3,
-    0xd7, 0xb5, 0x92, 0x2c, 0xd5, 0x83, 0xac, 0x68, 0xb6, 0x03, 0xfe, 0xb2, 0x5c, 0xd7, 0xa1, 0x85,
-    0x04, 0x04, 0x54, 0x42, 0x1a, 0xc7, 0x80, 0x76, 0xaa, 0x7b, 0x30, 0x08, 0xcb, 0x0c, 0x87, 0x08,
-    0x2e, 0x19, 0x10, 0x60, 0x05, 0x53, 0xd9, 0xa9, 0xe0, 0xc8, 0xb4, 0x49, 0x51, 0xc5, 0xd0, 0x8e,
-    0x33, 0x8c, 0xc0, 0x9c, 0x70, 0x02, 0x9b, 0x58, 0xdb, 0xf0, 0x43, 0x99, 0x75, 0x39, 0xb6, 0x78,
-    0x99, 0xd1, 0xe3, 0xe9, 0x8f, 0x80, 0x92, 0x12, 0x9b, 0xa0, 0xc1, 0x60, 0xdf, 0x01, 0x64, 0x7c,
-    0x1f, 0x07, 0xc4, 0x3e, 0xe3, 0xbb, 0x00, 0x58, 0x0f, 0x00, 0x49, 0x3b, 0x41, 0x44, 0xa4, 0x54,
-    0x88, 0xd5, 0xd7, 0xad, 0xcd, 0x0c, 0x2a, 0x26, 0x50, 0xaa, 0x8b, 0x0b, 0xf2, 0xbb, 0x16, 0x74,
-    0xcb, 0x6a, 0x37, 0xe0, 0x72, 0x2d, 0x23, 0x11, 0xb2, 0xae, 0x28, 0xa4, 0x30, 0xc0, 0x18, 0x0b,
-    0xda, 0x55, 0x63, 0x69, 0xc5, 0x95, 0xce, 0xa2, 0x7d, 0xc8, 0xb5, 0x2a, 0x75, 0xad, 0x00, 0x49,
-    0x89, 0x6e, 0x0e, 0x4a, 0x38, 0xe6, 0x24, 0x88, 0xab, 0x07, 0xef, 0x51, 0xb5, 0x5f, 0x80, 0xec,
-    0x87, 0xdb, 0x87, 0x0a, 0xb6, 0xcf, 0xc0, 0x20, 0x1c, 0x10, 0x87, 0x01, 0x18, 0x05, 0xd3, 0x8c,
-    0x02, 0x6c, 0x43, 0x0c, 0x18, 0x32, 0x3f, 0xb7, 0x45, 0xb6, 0x24, 0xb8, 0xe1, 0x61, 0x1b, 0x73,
-    0xd7, 0x3c, 0x67, 0x95, 0x57, 0x69, 0x3c, 0x39, 0x5e, 0x3a, 0xc6, 0x44, 0x28, 0xc4, 0x95, 0x0e,
-    0x5d, 0x33, 0x85, 0x43, 0x8d, 0xd8, 0xc6, 0xf1, 0x2d, 0x51, 0x31, 0x3c, 0x7b, 0xdb, 0xb6, 0xb5,
-    0x94, 0xe6, 0xbd, 0x75, 0xd6, 0x05, 0x2a, 0xf4, 0xfa, 0x6b, 0xbc, 0x0a, 0xa7, 0xda, 0x54, 0xe4,
-    0x6b, 0xc9, 0x72, 0x71, 0x8b, 0x54, 0xa3, 0x93, 0x79, 0x0a, 0x7d, 0xd5, 0x81, 0x9f, 0xc2, 0x82,
-    0x77, 0x1f, 0xd8, 0xe5, 0x5f, 0xd2, 0xee, 0xbe, 0x84, 0x19, 0x10, 0x04, 0xfc, 0x6c, 0x71, 0xa6,
-    0xc2, 0x2d, 0xd3, 0xed, 0x1c, 0xbd, 0x9e, 0xc6, 0x97, 0x82, 0xb8, 0x10, 0xb7, 0xae, 0x9a, 0xc0,
-    0x65, 0x3e, 0x6f, 0x6d, 0xce, 0x81, 0xc6, 0xbc, 0x96, 0xfc, 0x67, 0xd2, 0xfc, 0x0d, 0x95, 0x9e,
-    0x05, 0xbd, 0xfb, 0xe6, 0x74, 0x3a, 0x56, 0x36, 0xec, 0x0f, 0x69, 0xca, 0xcf, 0xcd, 0xa9, 0xef,
-    0xb3, 0x86, 0x63, 0xb3, 0xed, 0xde, 0x0b, 0x66, 0x5f, 0x3f, 0xaf, 0x80, 0x7f, 0xce, 0x92, 0x4d,
-    0xaf, 0x83, 0x11, 0xf6, 0x83, 0xac, 0x4f, 0xc1, 0x49, 0x2b, 0x16, 0x40, 0x8f, 0x0b, 0xcb, 0xec,
-    0x6e, 0xfc, 0xe4, 0x8c, 0xcf, 0xe0, 0x94, 0xd3, 0xac, 0x1c, 0xcd, 0x46, 0x58, 0x0e, 0xa6, 0x44,
-    0x47, 0x00, 0xb6, 0x94, 0x9f, 0xa7, 0x25, 0x9a, 0xb8, 0x6b, 0xd6, 0x93, 0x5b, 0xb5, 0xb7, 0x59,
-    0xf0, 0x2c, 0x2c, 0x90, 0x61, 0x4a, 0xbd, 0x52, 0xea, 0x19, 0x97, 0x0a, 0x91, 0xb1, 0x75, 0x05,
-    0xd4, 0xdd, 0x3d, 0x64, 0x5b, 0x50, 0x70, 0x7c, 0xb7, 0x45, 0x01, 0xdf, 0x37, 0x83, 0x1a, 0xdf,
-    0xc0, 0x76, 0x81, 0x2b, 0xc1, 0x63, 0x62, 0x5b, 0x35, 0xb1, 0x89, 0xa7, 0xf2, 0x17, 0xc3, 0xd7,
-    0x16, 0xf8, 0x7c, 0x61, 0x96, 0x4b, 0x86, 0x93, 0x7c, 0x0d, 0x1c, 0x6c, 0x3e, 0x87, 0x27, 0xb5,
-    0x09, 0xb0, 0xf7, 0x2c, 0x88, 0xef, 0x50, 0xc9, 0x4a, 0x36, 0xc6, 0x47, 0xfa, 0xcb, 0xa6, 0x3f,
-    0x70, 0xc6, 0xbf, 0xe8, 0xed, 0xae, 0x38, 0x0d, 0xa4, 0xe0, 0x4a, 0xcb, 0xe1, 0x6a, 0xa3, 0x0d,
-    0x78, 0x5a, 0x93, 0x43, 0x6a, 0x96, 0x52, 0xad, 0x23, 0x80, 0x5d, 0x10, 0x5d, 0x34, 0xa5, 0x6c,
-    0xb5, 0xca, 0xcb, 0x7c, 0x23, 0xbf, 0x04, 0xa9, 0xde, 0xe0, 0x72, 0xbc, 0x32, 0x5b, 0xc0, 0x09,
-    0x4b, 0x46, 0x42, 0x0e, 0x94, 0x93, 0x8c, 0x9d, 0x9e, 0xa3, 0xdf, 0xa7, 0xf8, 0x7a, 0xc5, 0x79,
-    0x39, 0x53, 0xe9, 0x42, 0xe9, 0x56, 0xff, 0xcf, 0x48, 0x5a, 0x8a, 0xc0, 0x31, 0x79, 0x95, 0x36,
-    0xf4, 0x3e, 0x4e, 0xdb, 0x6b, 0x3f, 0x42, 0x22, 0xd3, 0x73, 0xc0, 0xdd, 0x31, 0x4b, 0xad, 0x87,
-    0x6f, 0xf0, 0xdf, 0x3c, 0xff, 0xb5, 0xb0, 0xdc, 0x3d, 0xe5, 0x36, 0x05, 0x07, 0xf7, 0xf2, 0x7a,
-    0x08, 0x8b, 0xc6, 0xfd, 0x89, 0x50, 0xa6, 0xbd, 0xfc, 0x27, 0x5b, 0x2c, 0x0b, 0xec, 0x25, 0x35,
-    0x49, 0x83, 0x1a, 0xc0, 0x11, 0x9a, 0x34, 0x4e, 0x12, 0x3c, 0x88, 0x87, 0xf3, 0xde, 0x60, 0x1e,
-    0xbe, 0x38, 0xf5, 0x8c, 0x24, 0x9a, 0x37, 0x07, 0xc7, 0xf7, 0x94, 0xa9, 0x17, 0x3d, 0xac, 0x77,
-    0xbc, 0x88, 0x78, 0x16, 0x3d, 0x43, 0x9a, 0xf6, 0x72, 0x51, 0x1a, 0xb0, 0x95, 0xfb, 0xae, 0x03,
-    0xc0, 0x26, 0x91, 0x60, 0x5d, 0x40, 0xd3, 0x61, 0xaa, 0x21, 0x01, 0x18, 0xd5, 0x86, 0xb5, 0x78,
-    0x01, 0x4c, 0xf8, 0x4f, 0x52, 0xbd, 0xe8, 0x7d, 0x99, 0x03, 0x7d, 0x8d, 0xce, 0x1a, 0x7d, 0xce,
-    0xc2, 0xb2, 0xfb, 0x02, 0xfc, 0x67, 0xbf, 0x1b, 0xaa, 0x8c, 0x35, 0x26, 0x15, 0x2d, 0x84, 0x96,
-    0xc4, 0xac, 0xf6, 0x5b, 0xc0, 0x03, 0x77, 0x6f, 0xc2, 0xe4, 0xbd, 0xe1, 0x25, 0xa6, 0x84, 0xaf,
-    0x20, 0xab, 0x54, 0xf1, 0x71, 0x05, 0x83, 0x91, 0x98, 0x81, 0x7b, 0x77, 0xaa, 0xbd, 0x2e, 0xae,
-    0x3f, 0xd6, 0x27, 0x2e, 0xcd, 0x3d, 0x61, 0x19, 0xb1, 0x24, 0xc0, 0x2f, 0xbd, 0x2b, 0x36, 0x05,
-    0xd7, 0x06, 0x3d, 0xcf, 0x27, 0x8e, 0x50, 0x82, 0x16, 0xa6, 0xc0, 0x09, 0xa3, 0x9b, 0x8f, 0x4b,
-    0x4b, 0x6c, 0x56, 0x0e, 0x97, 0xb3, 0xf5, 0x3a, 0xe0, 0x38, 0xcf, 0x72, 0x93, 0x28, 0xa3, 0x85,
-    0x6b, 0x5f, 0xfe, 0x61, 0x10, 0x77, 0xb0, 0x15, 0x92, 0x4c, 0x00, 0x86, 0x92, 0xc3, 0x09, 0x68,
-    0xb9, 0xc8, 0xc5, 0x78, 0x01, 0xcb, 0x9e, 0x2f, 0xf4, 0xf3, 0xd8, 0x41, 0xcd, 0x88, 0xd6, 0x8b,
-    0xae, 0x5b, 0x1e, 0x54, 0x7e, 0xf1, 0xec, 0xa0, 0xef, 0x75, 0xd6, 0xd9, 0xce, 0x1f, 0x6c, 0x8e,
-    0xe6, 0x5a, 0x15, 0x46, 0x1e, 0x88, 0x2e, 0x2b, 0xbb, 0xb9, 0xb4, 0xbf, 0x4f, 0x63, 0xf9, 0x5e,
-    0x8e, 0xcd, 0xa3, 0xfd, 0x11, 0x53, 0x2c, 0xf3, 0x54, 0x57, 0x3a, 0xf7, 0x88, 0x18, 0x57, 0x11,
-    0x9d, 0x89, 0xb5, 0xff, 0xca, 0xb1, 0x66, 0x22, 0xbe, 0x24, 0x78, 0x13, 0x69, 0x47, 0x16, 0xa3,
-    0xc0, 0x09, 0x6e, 0x9f, 0x0f, 0xed, 0x5f, 0x2f, 0xab, 0x9c, 0x95, 0xaa, 0x6f, 0xea, 0x00, 0xcf,
-    0x55, 0xde, 0xbd, 0x8f, 0xc9, 0x18, 0xc7, 0xc1, 0x41, 0x9b, 0xb0, 0x72, 0x35, 0x1a, 0x0f, 0xb9,
-    0x19, 0x11, 0x97, 0x85, 0x07, 0xa5, 0xe1, 0xc0, 0xb2, 0xb3, 0x0c, 0x74, 0x2f, 0x33, 0xb0, 0xc0,
-    0xe9, 0xe2, 0x48, 0xe0, 0x42, 0xb0, 0x23, 0xe5, 0x58, 0x93, 0x60, 0x17, 0x30, 0xa8, 0x13, 0x2f,
-    0x3c, 0x48, 0x18, 0x3b, 0xb1, 0x1b, 0x16, 0xc1, 0x57, 0xd6, 0xed, 0xd5, 0x75, 0x78, 0x01, 0xc1,
-    0x23, 0x2f, 0x8e, 0xf3, 0x91, 0xcd, 0x72, 0x5e, 0x12, 0x53, 0x8d, 0xfa, 0xc0, 0x7d, 0xc5, 0x93,
-    0x3f, 0xcf, 0xff, 0xf1, 0xf5, 0xc3, 0x23, 0xeb, 0x2e, 0x4b, 0x92, 0x9a, 0xe5, 0xb8, 0x2f, 0x6c,
-    0xc3, 0x47, 0x07, 0xec, 0x83, 0x0d, 0xff, 0x9d, 0xa9, 0x4d, 0x09, 0x9d, 0x75, 0xb4, 0x24, 0x16,
-    0xaf, 0x00, 0xe7, 0xc6, 0x1a, 0x8f, 0xaf, 0x64, 0x47, 0xa9, 0x50, 0xbf, 0x08, 0xfb, 0x2c, 0xf8,
-    0x77, 0xff, 0x14, 0x6d, 0x58, 0xe0, 0x74, 0xb3, 0x02, 0x50, 0xa6, 0x0c, 0xaa, 0xb1, 0x0b, 0x2b,
-    0x1d, 0x15, 0xa0, 0x4d, 0xfc, 0x88, 0xb7, 0x0f, 0x57, 0xf4, 0x92, 0xcc, 0x50, 0x3e, 0x35, 0x09,
-    0x0a, 0x18, 0xab, 0xcc, 0xf8, 0x72, 0xfd, 0xf7, 0x9f, 0x1b, 0xdd, 0x5d, 0x2b, 0xcb, 0xcd, 0xbd,
-    0xb7, 0x1d, 0x96, 0xdd, 0xb0, 0xd3, 0xdb, 0x64, 0xbe, 0x33, 0xa8, 0x92, 0x01, 0x0f, 0x2c, 0xe5,
-    0x85, 0xd2, 0x79, 0x9d, 0x23, 0xfe, 0xf8, 0xda, 0x1d, 0x34, 0xd6, 0x95, 0x7f, 0x93, 0x4d, 0x7e,
-    0xec, 0x4f, 0x03, 0xfe, 0xc1, 0x9d, 0xc0, 0x54, 0xe0, 0xca, 0xea, 0x95, 0x4d, 0x34, 0x82, 0x8c,
-    0x94, 0xd7, 0x87, 0xd2, 0x24, 0x5a, 0x1f, 0x00, 0x9e, 0xd8, 0x85, 0xe3, 0xf3, 0xe0, 0x1c, 0xfb,
-    0x9b, 0xf0, 0x63, 0xb8, 0x64, 0x45, 0x70, 0x32, 0x3d, 0x69, 0x9a, 0xf6, 0x72, 0x59, 0x1a, 0xb0,
-    0x3a, 0xb5, 0xfb, 0x60, 0x38, 0x05, 0x0e, 0x52, 0x17, 0x3f, 0xfc, 0x09, 0x14, 0xee, 0x18, 0x04,
-    0xe3, 0x76, 0x13, 0xad, 0x09, 0x5c, 0x2c, 0x2c, 0x5c, 0xed, 0x5d, 0xd6, 0xae, 0xe0, 0xfb, 0x2d,
-    0x18, 0x47, 0x11, 0xb2, 0x15, 0x74, 0x67, 0x94, 0x05, 0x83, 0x9f, 0xe3, 0xd5, 0x53, 0x55, 0x9d,
-    0x72, 0xbe, 0xf0, 0x2f, 0x69, 0x48, 0x6f, 0x63, 0xf9, 0x5e, 0xf2, 0xc0, 0xb0, 0xee, 0x6f, 0x66,
-    0x51, 0x53, 0xbb, 0x4d, 0x28, 0xb6, 0x11, 0x36, 0x16, 0xc8, 0xea, 0xfd, 0x5e, 0xba, 0xda, 0x1e,
-    0x76, 0x99, 0xd0, 0x65, 0x54, 0xea, 0xc0, 0x72, 0x6e, 0x77, 0xe7, 0xee, 0xdb, 0xd7, 0xfb, 0x9b,
-    0x4d, 0xda, 0x37, 0x30, 0x6e, 0xf8, 0xc5, 0xef, 0x60, 0x13, 0x0e, 0x18, 0x58, 0x9c, 0x79, 0xda,
-    0xd0, 0xc2, 0xa3, 0x2c, 0x66, 0xb2, 0x8b, 0xa3, 0x73, 0x3b, 0x35, 0x5a, 0xb1, 0x39, 0x09, 0x26,
-    0x0d, 0xc0, 0x24, 0x89, 0xaf, 0x00, 0x53, 0xc4, 0xaa, 0x5c, 0x5e, 0xdd, 0x03, 0xb4, 0xf5, 0xfa,
-    0x91, 0x66, 0xac, 0x1c, 0xad, 0x46, 0x38, 0x0e, 0x80, 0xa8, 0xba, 0x74, 0xf5, 0xf5, 0x60, 0xbf,
-    0xfe, 0x7f, 0x0d, 0xb7, 0xad, 0x38, 0x3d, 0xb4, 0x23, 0xa3, 0xbc, 0x63, 0xc2, 0x08, 0xde, 0x9a,
-    0x00, 0x88, 0xbf, 0x83, 0xe6, 0xec, 0xfc, 0x57, 0xf0, 0xff, 0xd5, 0xb9, 0x07, 0x3d, 0x42, 0x4d,
-    0x82, 0xcb, 0xf9, 0x3d, 0xc8, 0x70, 0xea, 0xb5, 0x50, 0xb3, 0x11, 0x7c, 0x82, 0x3f, 0xfe, 0x57,
-    0xf0, 0x0e, 0xf3, 0x8a, 0xbd, 0x9f, 0x93, 0xb4, 0x96, 0xe5, 0xf1, 0x97, 0x96, 0x0c, 0xd1, 0x79,
-    0xdf, 0xf9, 0x6f, 0xc0, 0xd5, 0x54, 0x81, 0xbb, 0x97, 0x5f, 0xfb, 0xb6, 0x2e, 0x15, 0xb1, 0x7c,
-    0x5b, 0x8b, 0x4b, 0xa3, 0x9a, 0x30, 0xf5, 0x82, 0x1a, 0x7d, 0x1c, 0x16, 0x6c, 0x08, 0xf2, 0x5c,
-    0x17, 0x52, 0xbe, 0xff, 0x52, 0x3e, 0xf7, 0xbb, 0x25, 0x80, 0x5c, 0x46, 0x89, 0xe5, 0xc7, 0x62,
-    0x74, 0xea, 0xdc, 0xa0, 0xda, 0xa0, 0x3f, 0x08, 0xdf, 0xcf, 0xaf, 0x9b, 0xdf, 0x78, 0x91, 0x6b,
-    0x7c, 0x00, 0x77, 0x74, 0xb0, 0x3e, 0x0c, 0xd4, 0x6c, 0xaf, 0xdd, 0xed, 0xc7, 0x71, 0xa7, 0x16,
-    0x3f, 0x33, 0x8f, 0x5a, 0xc7, 0xbd, 0x47, 0x76, 0x07, 0x24, 0x11, 0xd7, 0xa6, 0x9a, 0x56, 0x69,
-    0x3b, 0x12, 0xb0, 0xe0, 0xd0, 0x12, 0x23, 0xc4, 0x8c, 0x32, 0xc4, 0x3a, 0x00, 0xba, 0x6e, 0xc3,
-    0x89, 0x7c, 0x96, 0x48, 0x0a, 0x08, 0x24, 0x30, 0x8d, 0x2c, 0x0b, 0x56, 0xe6, 0xd5, 0x55, 0x39,
-    0x5e, 0xf5, 0xed, 0x3c, 0xc0, 0x5b, 0x59, 0x0b, 0xe9, 0xbe, 0x2e, 0xb9, 0xb5, 0x7e, 0xff, 0xbd,
-    0x6f, 0x80, 0x1e, 0xc4, 0xe4, 0x1b, 0xaf, 0xfc, 0x55, 0x1f, 0x19, 0x7d, 0x4c, 0x4f, 0xcc, 0xbc,
-    0xee, 0xb2, 0x67, 0x02, 0xe9, 0x2f, 0x1b, 0xe4, 0xfa, 0x1b, 0xc5, 0xfc, 0x9a, 0x2e, 0x41, 0x82,
-    0xc6, 0xfe, 0x01, 0x8f, 0x4b, 0x1b, 0x79, 0x1b, 0x2b, 0x85, 0xe9, 0x5f, 0x92, 0xe1, 0xba, 0x97,
-    0xae, 0x9b, 0x68, 0x7c, 0xd2, 0x4c, 0x8d, 0xdc, 0xb2, 0xc0, 0x46, 0xd2, 0xe1, 0x5e, 0x6b, 0xf3,
-    0x79, 0x7a, 0xf3, 0xcb, 0x3c, 0x5d, 0x23, 0xb0, 0x93, 0x47, 0x39, 0xfd, 0x4e, 0x1a, 0xe5, 0x95,
-    0xc1, 0x47, 0x5f, 0xf9, 0xed, 0x0b, 0xdc, 0xcc, 0x75, 0x2a, 0x6a, 0x06, 0x00, 0x91, 0x19, 0x8c,
-    0x56, 0xfd, 0x00, 0x93, 0x18, 0xfc, 0xd2, 0x30, 0xbd, 0xa2, 0xa2, 0xa6, 0xd8, 0x96, 0x78, 0xf1,
-    0x8e, 0x7c, 0x46, 0xc8, 0x79, 0xf8, 0xda, 0xcb, 0x3b, 0x02, 0x6d, 0x5e, 0x01, 0x32, 0xf4, 0x86,
-    0x7f, 0xe6, 0x7c, 0xfd, 0xcf, 0x08, 0x0f, 0x09, 0x6f, 0x03, 0xfa, 0x11, 0x96, 0x7b, 0x73, 0x75,
-    0x90, 0xdc, 0xfe, 0x5e, 0x62, 0x61, 0x67, 0x1b, 0xc8, 0x8c, 0xb9, 0x32, 0x98, 0x4d, 0x9a, 0xd4,
-    0xa0, 0x39, 0x5b, 0xd6, 0x0b, 0x56, 0x56, 0xcf, 0x55, 0x43, 0x2f, 0x6f, 0xb8, 0xf6, 0x83, 0xff,
-    0xe7, 0x62, 0x7b, 0x73, 0xf9, 0x4e, 0xea, 0xec, 0x3e, 0x1e, 0xa6, 0xbf, 0xbf, 0x87, 0xdb, 0x1a,
-    0xdb, 0xca, 0xb4, 0xc7, 0xa5, 0x30, 0x2b, 0xcd, 0x79, 0xef, 0x9b, 0x58, 0xdc, 0x30, 0xf8, 0x70,
-    0x8e, 0x2f, 0x42, 0xde, 0x83, 0x44, 0x25, 0xf7, 0xdd, 0x55, 0x3e, 0x12, 0x55, 0x4e, 0x15, 0x5f,
-    0x37, 0x91, 0xe9, 0xe3, 0x1f, 0x20, 0xda, 0x51, 0xcb, 0xff, 0xfd, 0x6d, 0x72, 0xfc, 0x3f, 0x5b,
-    0x0f, 0xc7, 0x70, 0xcd, 0x84, 0xd9, 0x8e, 0x36, 0x92, 0x1d, 0x4a, 0x61, 0x70, 0x9b, 0x9b, 0x68,
-    0x9b, 0x27, 0xc6, 0x99, 0x10, 0xa3, 0xce, 0x53, 0x21, 0xf4, 0x31, 0x3c, 0x87, 0x84, 0x69, 0x81,
-    0x9d, 0xa5, 0xef, 0x0f, 0xf1, 0xca, 0xae, 0xf0, 0x63, 0x1c, 0x84, 0x5b, 0x8f, 0x77, 0xe5, 0x6b,
-    0x11, 0xec, 0x26, 0x59, 0x9f, 0x16, 0x89, 0xe1, 0xc2, 0xad, 0x56, 0xb8, 0x2e, 0x31, 0x68, 0x5d,
-    0x2a, 0x83, 0xf6, 0xef, 0xfe, 0x61, 0x76, 0x9d, 0x60, 0x2a, 0x87, 0xc5, 0x85, 0xff, 0x22, 0xe4,
-    0x4b, 0x08, 0x48, 0x13, 0x8a, 0x00, 0x3b, 0x48, 0xc9, 0x21, 0x06, 0xc1, 0xbb, 0xd9, 0xd1, 0x3d,
-    0x52, 0x49, 0x6a, 0x44, 0x93, 0x09, 0xc8, 0x8b, 0x8a, 0x5e, 0x7e, 0x8d, 0x0b, 0x26, 0xc3, 0x59,
-    0xbb, 0xad, 0x92, 0xaa, 0x46, 0x0b, 0xbe, 0xd6, 0xaa, 0xa0, 0x36, 0x5f, 0x34, 0x6a, 0x88, 0x84,
-    0x0a, 0xfc, 0xa8, 0xb8, 0xbd, 0xb4, 0xa4, 0xf4, 0xc6, 0xe1, 0x88, 0x55, 0x5d, 0x4e, 0xc9, 0xdc,
-    0x7d, 0xa2, 0x71, 0x0d, 0x18, 0x1e, 0x16, 0x1d, 0x17, 0x11, 0xb3, 0x91, 0x92, 0xf0, 0xc6, 0x1b,
-    0x3a, 0x54, 0x80, 0x8f, 0x11, 0x71, 0x9b, 0x02, 0x16, 0xf4, 0x8f, 0xf0, 0x37, 0xf2, 0xea, 0xa8,
-    0x95, 0x61, 0x8e, 0x8f, 0x22, 0x22, 0xc0, 0xef, 0x51, 0x0b, 0x18, 0x8d, 0xd8, 0xe8, 0x0b, 0x76,
-    0x3e, 0xa5, 0x28, 0xc3, 0x6f, 0xde, 0xf1, 0xf4, 0x55, 0x7d, 0x48, 0xfd, 0xe3, 0xa5, 0x64, 0x45,
-    0x70, 0x3c, 0xbe, 0x0f, 0x06, 0x22, 0xc8, 0x95, 0x89, 0x0a, 0x56, 0xd6, 0x8a, 0x36, 0x42, 0xbe,
-    0xe6, 0x20, 0x00, 0x5c, 0xaa, 0xc6, 0x2e, 0xea, 0x19, 0x11, 0xfc, 0x07, 0x38, 0x08, 0x30, 0x7f,
-    0xb1, 0xe7, 0xfd, 0x71, 0x1c, 0x37, 0xc1, 0xd1, 0x4c, 0x3f, 0x16, 0x4c, 0x4d, 0x06, 0x69, 0xca,
-    0x3b, 0x8b, 0x79, 0xfd, 0x05, 0x0c, 0x8c, 0x60, 0xee, 0xaa, 0x91, 0x16, 0xf1, 0xab, 0x8a, 0x55,
-    0xf1, 0xb2, 0x85, 0xfc, 0xa7, 0xde, 0x6f, 0x32, 0xd3, 0x1f, 0xfd, 0xc2, 0x0d, 0xc7, 0x74, 0x4d,
-    0xcb, 0xae, 0x77, 0x96, 0xd3, 0xf3, 0x0a, 0xa0, 0x97, 0xd1, 0xf5, 0x54, 0xb8, 0xba, 0x45, 0x63,
-    0x1f, 0xe4, 0xef, 0x80, 0x63, 0xd4, 0xef, 0xef, 0x74, 0x56, 0x93, 0xf3, 0xfe, 0x60, 0x97, 0xcb,
-    0xf5, 0x55, 0x89, 0x0b, 0x92, 0x4e, 0xb5, 0x22, 0xe3, 0x0e, 0xc4, 0x5e, 0xc9, 0x0b, 0xc8, 0x52,
-    0xc1, 0x43, 0x0a, 0x6e, 0x6e, 0xee, 0xe9, 0xd2, 0x58, 0xe1, 0x08, 0xd5, 0x93, 0xdd, 0x96, 0x57,
-    0x8b, 0x06, 0x2f, 0xb4, 0x3b, 0x0a, 0x00, 0x5f, 0x9d, 0x55, 0x14, 0x57, 0xfe, 0xee, 0xbe, 0x19,
-    0x61, 0xa5, 0x63, 0x81, 0x6a, 0xf0, 0x1e, 0xf8, 0xdc, 0xa0, 0xf4, 0x98, 0xaa, 0x0b, 0x40, 0xfa,
-    0xea, 0xb1, 0xb7, 0xce, 0xb7, 0x80, 0x3b, 0x56, 0x09, 0xb6, 0xa5, 0x92, 0x84, 0x0b, 0x01, 0xca,
-    0x51, 0x86, 0xad, 0xd5, 0x1a, 0xc5, 0x9f, 0xba, 0x2b, 0xc5, 0x30, 0x66, 0xd2, 0xbc, 0xa5, 0xb1,
-    0xcd, 0x3a, 0x73, 0x29, 0x49, 0x47, 0x58, 0xe3, 0xb7, 0x55, 0xeb, 0x15, 0x7f, 0x0d, 0xf8, 0x12,
-    0x55, 0x02, 0x92, 0x3a, 0xe7, 0x60, 0xdf, 0xfa, 0x3a, 0x3a, 0x01, 0x35, 0xf0, 0x06, 0xe5, 0x85,
-    0xdd, 0x21, 0xef, 0xe7, 0x84, 0xda, 0x08, 0x22, 0xa2, 0xab, 0x83, 0x92, 0x25, 0x15, 0x8b, 0x00,
-    0x4f, 0x6a, 0xc9, 0x01, 0xa4, 0xc1, 0x62, 0xf6, 0x07, 0x24, 0x19, 0xbb, 0x5d, 0xe0, 0x36, 0x69,
-    0xf5, 0x6a, 0xef, 0x22, 0x73, 0xc7, 0xb6, 0xc2, 0x03, 0xc9, 0x53, 0x9f, 0x4d, 0xd5, 0x1e, 0x03,
-    0x00, 0xd9, 0xa4, 0x44, 0x44, 0x45, 0x15, 0x2e, 0xdb, 0x91, 0x09, 0xf0, 0xd8, 0x30, 0x0b, 0x08,
-    0x29, 0x55, 0x1e, 0xd2, 0x58, 0xa1, 0xed, 0xda, 0xe0, 0x64, 0xec, 0x83, 0x2b, 0x5b, 0x30, 0x7a,
-    0x90, 0xb0, 0x5f, 0x1a, 0x55, 0x38, 0xa6, 0x5d, 0x6f, 0xaa, 0x4e, 0x03, 0x6e, 0x00, 0x0b, 0xc6,
-    0x35, 0x5d, 0x37, 0x23, 0xea, 0xa9, 0x81, 0xa2, 0x52, 0x0e, 0x9c, 0xd5, 0x7e, 0xaa, 0x98, 0x05,
-    0x5c, 0x0c, 0xf3, 0x41, 0x07, 0x3e, 0x81, 0x6b, 0xf1, 0x7f, 0x50, 0xef, 0x9b, 0x8f, 0xc2, 0xf0,
-    0x97, 0xaf, 0xbf, 0x00, 0x52, 0x02, 0x57, 0x59, 0xfc, 0x75, 0x0c, 0x90, 0x1a, 0x47, 0x17, 0x0e,
-    0xf0, 0x0d, 0x3f, 0x6e, 0x97, 0x80, 0x99, 0x60, 0x37, 0x6a, 0xcc, 0xe9, 0xd9, 0x11, 0x09, 0xc4,
-    0x09, 0x60, 0x00, 0x25, 0x06, 0x2f, 0xb6, 0x8e, 0xaf, 0x68, 0xa9, 0x29, 0xab, 0xa9, 0xaa, 0xa7,
-    0x45, 0xcb, 0x0c, 0xe4, 0x85, 0xbc, 0x27, 0xd5, 0xa6, 0x00, 0x72, 0xa5, 0xc0, 0x72, 0xf1, 0xef,
-    0x71, 0x42, 0x0c, 0x1b, 0x02, 0xdb, 0x44, 0x40, 0x0b, 0xde, 0x15, 0x7c, 0x43, 0xdf, 0xe2, 0x52,
-    0x0b, 0x2c, 0x9f, 0xf5, 0x24, 0xab, 0xc4, 0x69, 0xaa, 0xa2, 0xe0, 0x39, 0xe0, 0x2e, 0x11, 0x2e,
-    0x11, 0x39, 0x0f, 0x38, 0x5e, 0x6f, 0x2a, 0x70, 0xa3, 0x5e, 0x9c, 0xdc, 0xe8, 0xd5, 0x63, 0x6b,
-    0x70, 0x05, 0xf0, 0x27, 0xbd, 0x70, 0x0d, 0x4b, 0xf5, 0x54, 0xe0, 0x79, 0x11, 0x4a, 0x16, 0xb9,
-    0x03, 0x2f, 0x58, 0xf5, 0x39, 0xbc, 0xa9, 0xc9, 0xff, 0xc5, 0x94, 0x6a, 0xa8, 0x51, 0x05, 0x0b,
-    0x82, 0xfe, 0xa0, 0xd7, 0xd5, 0xc4, 0xae, 0xb7, 0x45, 0xfc, 0x4a, 0x2f, 0x07, 0x72, 0x87, 0x70,
-    0x1c, 0x88, 0x97, 0x8d, 0x59, 0x30, 0x3d, 0xfa, 0x80, 0xd3, 0xd8, 0x09, 0xaa, 0x8f, 0xbc, 0x03,
-    0xfc, 0x0a, 0xaf, 0x00, 0x70, 0x16, 0xa4, 0xec, 0xaa, 0xa3, 0xe3, 0x76, 0xd2, 0x85, 0x11, 0xef,
-    0x91, 0x91, 0x1c, 0xc0, 0x67, 0xbc, 0x50, 0xf8, 0x67, 0xbc, 0x32, 0x78, 0xf5, 0xde, 0xed, 0x27,
-    0x67, 0x01, 0x12, 0xf0, 0x46, 0x7d, 0x49, 0xe3, 0x75, 0xfc, 0x3a, 0x54, 0xe2, 0xf0, 0xe6, 0x71,
-    0xbf, 0x55, 0x14, 0xaa, 0x28, 0xe0, 0xec, 0x65, 0x5e, 0x7f, 0x16, 0x44, 0x97, 0x02, 0x92, 0x13,
-    0x34, 0x9f, 0x4b, 0xc4, 0xd3, 0x78, 0xe5, 0x6b, 0x99, 0x29, 0xa3, 0xa4, 0xad, 0xd1, 0xe5, 0x39,
-    0xc9, 0x07, 0x00, 0x24, 0x65, 0x03, 0x6b, 0x27, 0xb7, 0xb1, 0x48, 0xbf, 0x56, 0x0e, 0xe6, 0xa3,
-    0xb9, 0x46, 0x42, 0x18, 0xe8, 0xfa, 0x07, 0x80, 0x87, 0xee, 0xc8, 0x88, 0xc0, 0x21, 0x89, 0x8f,
-    0x58, 0xe9, 0x08, 0xb4, 0x6b, 0xbc, 0x79, 0xac, 0x56, 0x5f, 0xa6, 0x4b, 0x89, 0x6f, 0x88, 0xe2,
-    0xc0, 0x69, 0x93, 0x51, 0x1f, 0x63, 0xda, 0xaa, 0xe7, 0x8b, 0xfe, 0xf4, 0xf6, 0x92, 0x34, 0xb5,
-    0x55, 0x0a, 0x41, 0x5d, 0x8c, 0x48, 0x2d, 0x22, 0x64, 0x44, 0xf0, 0x22, 0xc0, 0x77, 0x44, 0x67,
-    0xb4, 0xc4, 0x2b, 0x97, 0x85, 0xe0, 0x4b, 0xe1, 0x77, 0x0e, 0x83, 0x04, 0x74, 0xe8, 0x6d, 0x4c,
-    0xf0, 0xcb, 0x84, 0xe9, 0x60, 0x4b, 0x21, 0x6a, 0x73, 0xa6, 0x49, 0x1d, 0x2c, 0x22, 0x72, 0xae,
-    0xd7, 0xb8, 0xc5, 0xf8, 0x22, 0x00, 0x76, 0xf2, 0x85, 0x7c, 0x8e, 0x30, 0x92, 0x1f, 0x02, 0xe1,
-    0x12, 0x83, 0xc5, 0x80, 0xc1, 0xc4, 0x0d, 0x53, 0x5b, 0xd8, 0xe8, 0x95, 0x4d, 0x24, 0x81, 0xc0,
-    0x2a, 0x34, 0x24, 0x6a, 0x47, 0x7f, 0xf3, 0x8c, 0x15, 0x6d, 0xda, 0xf8, 0x1d, 0xe1, 0x6d, 0x1c,
-    0x00, 0xb8, 0x4c, 0x74, 0xfa, 0xd1, 0xaa, 0x35, 0xce, 0xba, 0x51, 0xa8, 0xc3, 0x87, 0x22, 0x10,
-    0x21, 0xf2, 0xbc, 0xbc, 0xa6, 0x8d, 0x6f, 0x6d, 0x74, 0x66, 0xb8, 0x64, 0xe6, 0x7f, 0xe3, 0x50,
-    0xef, 0x59, 0x02, 0x31, 0xeb, 0x0c, 0x69, 0x2a, 0x5a, 0xe3, 0x73, 0xe4, 0x8d, 0xfe, 0xcd, 0xab,
-    0x00, 0x4b, 0x46, 0x06, 0x0d, 0xbf, 0x57, 0xb2, 0xe2, 0x4d, 0x69, 0xb0, 0xda, 0x69, 0x22, 0x17,
-    0xde, 0x65, 0xdf, 0xe4, 0x3b, 0x98, 0x18, 0x6b, 0xda, 0xd3, 0x25, 0xbd, 0x36, 0x1c, 0xa5, 0x56,
-    0x8e, 0x2c, 0x60, 0x17, 0x38, 0x70, 0x3b, 0xf6, 0x64, 0x44, 0x5e, 0x34, 0xd8, 0xe3, 0x6d, 0x74,
-    0xd8, 0xcd, 0xe1, 0x16, 0x31, 0xc2, 0x5c, 0x2d, 0xb6, 0x34, 0xb7, 0x95, 0x6e, 0x8e, 0x2e, 0x31,
-    0x02, 0xac, 0x20, 0x9e, 0x05, 0x45, 0x86, 0x01, 0x10, 0x54, 0xe3, 0x91, 0xad, 0xf0, 0x9e, 0x3d,
-    0x96, 0xda, 0x7d, 0xe1, 0x25, 0x06, 0x45, 0x00, 0x48, 0xe4, 0xcd, 0xe0, 0xec, 0x06, 0x4e, 0x2d,
-    0x92, 0x74, 0xa1, 0x26, 0x5e, 0xe9, 0x26, 0x8a, 0x30, 0x21, 0x34, 0x47, 0x44, 0x67, 0xea, 0xd6,
-    0x59, 0xa4, 0x39, 0xb5, 0x87, 0x22, 0x3f, 0x63, 0x52, 0xe3, 0xda, 0xbc, 0x80, 0x01, 0x45, 0x17,
-    0xdd, 0x32, 0xcd, 0x89, 0x8c, 0x22, 0xc2, 0xc8, 0x16, 0xa8, 0x44, 0x61, 0x18, 0x56, 0x15, 0x99,
-    0x66, 0x46, 0x64, 0x61, 0x18, 0x56, 0x22, 0xd5, 0xce, 0x8c, 0xe7, 0x0a, 0xcc, 0x8e, 0xba, 0xf2,
-    0x2d, 0x91, 0xd7, 0xd6, 0x37, 0xc7, 0xbb, 0xe1, 0xc9, 0x3d, 0xf1, 0xbf, 0x93, 0x8f, 0x28, 0xdb,
-    0xf4, 0x28, 0x32, 0x0e, 0xa2, 0xb3, 0x35, 0x5f, 0x02, 0x4e, 0xda, 0xb0, 0xf7, 0xe8, 0xcb, 0x50,
-    0x9a, 0xf6, 0xe7, 0x1a, 0xe3, 0x80, 0x4f, 0x29, 0xb5, 0x04, 0xfd, 0x8a, 0x95, 0x8c, 0x09, 0xa4,
-    0x0e, 0x58, 0x13, 0x47, 0xa8, 0x13, 0x34, 0xec, 0xf6, 0x7f, 0x2b, 0x30, 0xf2, 0xe2, 0xca, 0xcd,
-    0x44, 0xff, 0x75, 0xeb, 0xfd, 0xa7, 0x8f, 0x6e, 0x6f, 0xf4, 0x6e, 0x7c, 0x0f, 0x75, 0x5b, 0x9f,
-    0x97, 0x5d, 0xc6, 0x38, 0xaa, 0xe3, 0x2d, 0x5a, 0x22, 0x8f, 0xcc, 0xb0, 0x82, 0xcc, 0xa6, 0xbd,
-    0x00, 0xe6, 0xcf, 0x2a, 0x50, 0xd0, 0x0e, 0xca, 0x4d, 0xb8, 0x27, 0xec, 0x86, 0x8c, 0xe4, 0xaa,
-    0xc1, 0xec, 0xd9, 0x7e, 0x87, 0x4d, 0x51, 0xa3, 0x1d, 0x94, 0x88, 0xf0, 0x30, 0xac, 0x20, 0xfb,
-    0xbe, 0x76, 0xf2, 0xbb, 0x1f, 0xca, 0x0e, 0x83, 0x13, 0x78, 0x6c, 0xf0, 0x97, 0x4a, 0x62, 0x53,
-    0xd0, 0x21, 0xa5, 0xc8, 0x5f, 0x3b, 0xe0, 0x1a, 0x17, 0xdf, 0x9b, 0x01, 0x68, 0x1b, 0x6a, 0xcf,
-    0xa6, 0x41, 0xe3, 0x46, 0x70, 0x1c, 0xfb, 0x3c, 0xb0, 0x1c, 0x3b, 0xe5, 0x7c, 0xf4, 0x21, 0x77,
-    0x62, 0x2c, 0x2a, 0x5d, 0xee, 0xd2, 0xec, 0x70, 0x88, 0x57, 0x11, 0xc8, 0x42, 0xf8, 0x67, 0x8e,
-    0xc8, 0x8c, 0xd4, 0x1e, 0xce, 0x0d, 0xdb, 0x03, 0xf4, 0x73, 0x43, 0x05, 0xbf, 0xad, 0xa1, 0x4c,
-    0x6e, 0xa4, 0x55, 0x00, 0x0b, 0x5d, 0x07, 0xbc, 0x19, 0x6f, 0x3d, 0x4f, 0x80, 0xe4, 0x53, 0x7f,
-    0xdf, 0xd5, 0xc2, 0x0f, 0xc5, 0xde, 0xfa, 0x78, 0xf5, 0xd6, 0xfb, 0xda, 0xaa, 0xba, 0xae, 0xfe,
-    0xf3, 0xce, 0x8a, 0xa4, 0x41, 0x0b, 0xe3, 0xc7, 0x01, 0x1b, 0x35, 0xdb, 0x83, 0xfc, 0x91, 0x4d,
-    0xf2, 0xe7, 0x76, 0x0f, 0xc0, 0xaf, 0x68, 0xe1, 0x81, 0x18, 0xb3, 0xf0, 0x02, 0x8d, 0xcd, 0x36,
-    0x01, 0x4a, 0x94, 0xe2, 0x7e, 0xaa, 0xc2, 0x91, 0x44, 0xa5, 0xd5, 0x50, 0x45, 0x87, 0xf5, 0xe4,
-    0x3b, 0xc0, 0xd9, 0x81, 0x1b, 0x24, 0x29, 0x98, 0xd4, 0x9e, 0x7f, 0xe7, 0xea, 0xa9, 0x83, 0xab,
-    0xf7, 0xb4, 0x88, 0x98, 0x87, 0x9c, 0xf6, 0xb7, 0x35, 0xf8, 0xd8, 0x35, 0x4b, 0xfb, 0xde, 0xd1,
-    0x81, 0xc6, 0x6e, 0x0e, 0x9c, 0x76, 0x8e, 0x03, 0x95, 0x27, 0x74, 0x10, 0xc2, 0x9f, 0x82, 0x8f,
-    0x4d, 0x75, 0x78, 0xf3, 0x91, 0xeb, 0x8e, 0x1d, 0x91, 0xfd, 0x80, 0x80, 0x39, 0xc9, 0xb1, 0x07,
-    0xbe, 0x03, 0x63, 0x65, 0x58, 0x5f, 0x74, 0x2e, 0x4d, 0x35, 0xe6, 0xb4, 0x55, 0x5c, 0x62, 0xe7,
-    0x3e, 0x71, 0x55, 0x5a, 0x03, 0xe7, 0x6d, 0xf3, 0x6b, 0xd9, 0x0e, 0x56, 0x88, 0xe6, 0x35, 0x50,
-    0x09, 0x52, 0xdf, 0x41, 0xad, 0xbb, 0xad, 0x9f, 0xf4, 0xc1, 0x07, 0xfa, 0x84, 0x0f, 0x9e, 0x5e,
-    0xa0, 0xe3, 0x3c, 0xa5, 0x6e, 0x02, 0x6f, 0x11, 0xc1, 0x35, 0xc8, 0xc1, 0xce, 0xe2, 0x5f, 0x3c,
-    0x13, 0x58, 0xac, 0xa9, 0xc5, 0xf9, 0xc3, 0xb4, 0x8e, 0xcf, 0x71, 0xf4, 0x38, 0x0e, 0xeb, 0x1e,
-    0xe8, 0x21, 0x39, 0xad, 0x9a, 0xe5, 0x36, 0x68, 0x9d, 0xe0, 0xac, 0x76, 0x1c, 0x3b, 0xa5, 0x8d,
-    0xfe, 0xb8, 0x84, 0xf7, 0xf6, 0xd2, 0xc3, 0x89, 0x0c, 0xb2, 0x1c, 0xcb, 0x9a, 0x40, 0x83, 0x98,
-    0x97, 0xe4, 0xfa, 0xdb, 0x77, 0x39, 0x17, 0x69, 0xc1, 0x9d, 0x4d, 0xaa, 0x54, 0x7f, 0xff, 0xd5,
-    0xe9, 0x4a, 0x1c, 0x92, 0x84, 0x4d, 0x41, 0x0b, 0xb3, 0xc7, 0x19, 0x6f, 0xa5, 0x92, 0xe3, 0x46,
-    0x15, 0x8a, 0x6c, 0xdd, 0x66, 0x08, 0xbc, 0x68, 0xa7, 0x80, 0xea, 0xf3, 0xec, 0x70, 0x9c, 0x8f,
-    0x6f, 0x89, 0x5f, 0x05, 0x42, 0xd2, 0xfb, 0xfb, 0x0b, 0x3b, 0xf3, 0x3b, 0xb2, 0xdc, 0x8f, 0xb1,
-    0x6e, 0x1f, 0xe8, 0x89, 0xef, 0xc2, 0xfe, 0x02, 0x85, 0x3e, 0x72, 0x4b, 0x21, 0x34, 0x01, 0xce,
-    0x63, 0xc7, 0x04, 0x6d, 0x33, 0xbc, 0x7c, 0xa7, 0x55, 0x7a, 0x0f, 0x0f, 0x45, 0x04, 0xf3, 0xa5,
-    0xe5, 0xc0, 0xfb, 0x2e, 0xb1, 0xd9, 0x73, 0x1f, 0x7f, 0x96, 0x40, 0xe3, 0xc0, 0x76, 0xf6, 0xaf,
-    0x2b, 0x2b, 0x0a, 0x7b, 0x7f, 0xde, 0x05, 0xbd, 0xbf, 0x7e, 0x17, 0x23, 0x25, 0x2e, 0x62, 0x5b,
-    0xf0, 0x27, 0x55, 0x4e, 0xc5, 0x7d, 0x25, 0xf2, 0x9a, 0x3a, 0xe7, 0x14, 0xe3, 0x80, 0xea, 0x31,
-    0x0b, 0x80, 0x8b, 0xc0, 0x05, 0x5d, 0xdd, 0x1e, 0xe3, 0x93, 0x6b, 0xcb, 0x79, 0x7b, 0x3f, 0xb5,
-    0x06, 0x52, 0x2b, 0xe6, 0x3a, 0xaa, 0xf1, 0xaf, 0x1d, 0x96, 0x6b, 0x0e, 0x52, 0x04, 0xd7, 0x7e,
-    0x69, 0xf7, 0x2b, 0x58, 0x69, 0xb6, 0xf5, 0x50, 0xbc, 0x7a, 0x85, 0x79, 0x42, 0x9c, 0x95, 0x5e,
-    0x60, 0x5c, 0x72, 0x1b, 0xe4, 0xaa, 0xb6, 0xf1, 0xe6, 0x77, 0xec, 0xb4, 0x5f, 0x6c, 0xd1, 0xe9,
-    0x28, 0xb0, 0x25, 0x40, 0xc2, 0x5e, 0xbe, 0x73, 0x06, 0xcb, 0xd2, 0x3c, 0xd0, 0x71, 0x75, 0x20,
-    0xb9, 0xaa, 0x90, 0x1d, 0xc8, 0x88, 0xe0, 0x4a, 0xf0, 0x48, 0x07, 0x8a, 0x1c, 0xcc, 0x41, 0x92,
-    0x27, 0xd9, 0xa9, 0xd0, 0x2f, 0x78, 0x64, 0x6d, 0x79, 0x5f, 0x06, 0xbf, 0xa1, 0xf6, 0xe3, 0xc1,
-    0xf7, 0xd6, 0xb8, 0x69, 0xac, 0x1e, 0xdf, 0x9f, 0x17, 0x00, 0xd1, 0xb9, 0x63, 0xaf, 0x46, 0x7f,
-    0x2e, 0x44, 0x7e, 0x01, 0xf6, 0x96, 0x34, 0x75, 0xdd, 0x01, 0xf7, 0xc0, 0x2f, 0x80, 0x15, 0x14,
-    0x1c, 0xe4, 0x32, 0x8e, 0x01, 0xce, 0x20, 0xc7, 0x5f, 0x22, 0x3e, 0x02, 0xd9, 0x6f, 0x01, 0x6c,
-    0x18, 0x4f, 0x5a, 0xfe, 0x6d, 0x55, 0xa1, 0xce, 0xc3, 0x82, 0x48, 0x31, 0xe4, 0x44, 0xe0, 0x28,
-    0x3c, 0x19, 0xc0, 0x39, 0x91, 0x83, 0xc0, 0xe5, 0x81, 0x77, 0xa8, 0x1f, 0xf6, 0xea, 0x2f, 0xb4,
-    0xd1, 0xc6, 0x38, 0x9c, 0x1c, 0x07, 0x88, 0x83, 0x07, 0x4c, 0xc6, 0x9e, 0xe3, 0x5e, 0x08, 0xb1,
-    0x98, 0xf8, 0x3e, 0xaa, 0xc9, 0x6e, 0xc3, 0x9e, 0x1c, 0x61, 0x99, 0x11, 0xdc, 0x01, 0x1c, 0x07,
-    0xf6, 0x97, 0x18, 0xb5, 0x13, 0xa2, 0xe9, 0x58, 0xef, 0xfb, 0xe2, 0xe5, 0x97, 0xff, 0xea, 0xa9,
-    0x34, 0xca, 0xcc, 0x2f, 0x7f, 0xb1, 0x1c, 0xe0, 0x05, 0x70, 0x64, 0x44, 0xf0, 0x0c, 0xe0, 0x19,
-    0xc0, 0x63, 0x2a, 0x10, 0x9c, 0x44, 0xdc, 0x6b, 0xaa, 0x57, 0xbc, 0xef, 0x78, 0x00, 0x39, 0xc4,
-    0xc7, 0x5e, 0x8a, 0x81, 0x8c, 0x88, 0xde, 0x00, 0x8c, 0x06, 0xbe, 0xc3, 0xc9, 0xae, 0x51, 0x60,
-    0xd3, 0x8a, 0x78, 0xc0, 0x0e, 0x25, 0xff, 0xfd, 0xdb, 0x8f, 0x09, 0xd7, 0x52, 0xac, 0x4d, 0xd5,
-    0x5c, 0xa9, 0xe3, 0xad, 0xc1, 0x80, 0x60, 0x39, 0xc3, 0x87, 0x70, 0xe1, 0x52, 0x38, 0x15, 0xc0,
-    0x70, 0xe2, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87,
-    0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c,
-    0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c, 0x38, 0x76,
-    0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23, 0x03, 0x9c,
-    0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e, 0x05, 0x23,
-    0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38, 0x87, 0x0e,
-    0x05, 0x23, 0x03, 0x9c, 0x38, 0x76, 0x0e, 0x1c, 0x23, 0x87, 0x9c, 0x05, 0x76, 0x03, 0x1c, 0x38,
-    0x87, 0x0e, 0x05, 0x23, 0x0f, 0xfe, 0xf6, 0xa7, 0xbf, 0x78, 0xfb, 0x2d, 0xfb, 0xc5, 0x00, 0x00,
-    0x00, 0x00, 0x45, 0x49, 0x44, 0x4e, 0x42, 0xae, 0x82, 0x60,
-  ],
-  disp: function()
-  {
-    // Do Nothing
-
-    throw "Does Nothing!";
-  }
-
-};
-
-try
-{
-  LOGO.disp();
-}
-catch(e)
-{
-  alert("Error: " + e + "\n");
-}
diff --git a/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties
deleted file mode 100644
index be1b7aa..0000000
--- a/jetty-spdy/spdy-http-server/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
-#org.eclipse.jetty.server.LEVEL=DEBUG
-#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
-#org.eclipse.jetty.client.LEVEL=DEBUG
-#org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy.LEVEL=DEBUG
-#org.eclipse.jetty.spdy.server.proxy.LEVEL=DEBUG
-#org.mortbay.LEVEL=DEBUG
-
diff --git a/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks b/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks
deleted file mode 100644
index 428ba54..0000000
--- a/jetty-spdy/spdy-http-server/src/test/resources/keystore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks b/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks
deleted file mode 100644
index 839cb8c..0000000
--- a/jetty-spdy/spdy-http-server/src/test/resources/truststore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml
deleted file mode 100644
index 7b54c55..0000000
--- a/jetty-spdy/spdy-npn-tests/pom.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.11-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-npn-tests</artifactId>
-    <name>Jetty :: SPDY :: NPN Tests</name>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-dependency-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>copy</id>
-                        <phase>generate-resources</phase>
-                        <goals>
-                            <goal>copy</goal>
-                        </goals>
-                        <configuration>
-                            <artifactItems>
-                                <artifactItem>
-                                    <groupId>org.mortbay.jetty.npn</groupId>
-                                    <artifactId>npn-boot</artifactId>
-                                    <version>${npn.version}</version>
-                                    <type>jar</type>
-                                    <overWrite>false</overWrite>
-                                    <outputDirectory>${project.build.directory}/npn</outputDirectory>
-                                </artifactItem>
-                            </artifactItems>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.npn</groupId>
-            <artifactId>npn-api</artifactId>
-            <version>${npn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-start</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-http-server</artifactId>
-            <version>${project.version}</version>
-            <classifier>tests</classifier>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-    
-</project>
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java
deleted file mode 100644
index d225d1f..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Rule;
-
-public class AbstractNPNTest
-{
-    @Rule
-    public final TestTracker tracker = new TestTracker();
-    protected Server server;
-    protected SPDYServerConnector connector;
-    protected SPDYClient.Factory clientFactory;
-
-    protected InetSocketAddress prepare() throws Exception
-    {
-        server = new Server();
-        connector = new SPDYServerConnector(server, newSslContextFactory(), null);
-        connector.setPort(0);
-        connector.setIdleTimeout(30000);
-        server.addConnector(connector);
-        server.start();
-
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setName(threadPool.getName() + "-client");
-        clientFactory = new SPDYClient.Factory(threadPool);
-        clientFactory.start();
-
-        NextProtoNego.debug = true;
-
-        return new InetSocketAddress("localhost", connector.getLocalPort());
-    }
-
-    protected SslContextFactory newSslContextFactory()
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-        sslContextFactory.setProtocol("TLSv1");
-        sslContextFactory.setIncludeProtocols("TLSv1");
-        return sslContextFactory;
-    }
-
-    @After
-    public void dispose() throws Exception
-    {
-        clientFactory.stop();
-        server.stop();
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java
deleted file mode 100644
index 72c1c6d..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java
+++ /dev/null
@@ -1,193 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.start.BaseHome;
-import org.eclipse.jetty.start.FileArg;
-import org.eclipse.jetty.start.Module;
-import org.eclipse.jetty.toolchain.test.FS;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.util.IO;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(Parameterized.class)
-public class NPNModuleTest
-{
-    /** This is here to prevent pointless download attempts */
-    private static final List<String> KNOWN_GOOD_NPN_URLS = new ArrayList<>();
-
-    static
-    {
-        /** The main() method in this test case can be run to validate this list independently */
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.11.v20150415/npn-boot-1.1.11.v20150415.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.2.v20130305/npn-boot-1.1.2.v20130305.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar");
-        KNOWN_GOOD_NPN_URLS.add("http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar");
-    }
-
-    @Parameters(name = "{index}: mod:{0}")
-    public static List<Object[]> data()
-    {
-        File npnBootModDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config/modules/protonego-impl");
-        List<Object[]> data = new ArrayList<>();
-        for (File file : npnBootModDir.listFiles())
-        {
-            if (Pattern.matches("npn-.*\\.mod",file.getName()))
-            {
-                data.add(new Object[] { file.getName() });
-            }
-        }
-        return data;
-    }
-
-    @Parameter(value = 0)
-    public String modBootFile;
-
-    private static BaseHome basehome;
-
-    @BeforeClass
-    public static void initBaseHome() throws IOException
-    {
-        File homeDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config");
-        File baseDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getName());
-        FS.ensureEmpty(baseDir);
-        
-        String cmdLine[] = { "jetty.home="+homeDir.getAbsolutePath(),"jetty.base="+baseDir.getAbsolutePath() };
-        basehome = new BaseHome(cmdLine);
-    }
-
-    /**
-     * Check the sanity of the npn-boot file module 
-     */
-    @Test
-    public void testModuleValues() throws IOException
-    {
-        Path modFile = basehome.getPath("modules/protonego-impl/" + modBootFile);
-        Module mod = new Module(basehome,modFile);
-        assertNotNull("module",mod);
-        
-        // Validate logical name
-        assertThat("Module name",mod.getName(),is("protonego-boot"));
-
-        List<String> expectedBootClasspath = new ArrayList<>();
-
-        for (String line : mod.getFiles())
-        {
-            FileArg farg = new FileArg(line);
-            if (farg.uri != null)
-            {
-                assertTrue("Not a known good NPN URL: " + farg.uri,KNOWN_GOOD_NPN_URLS.contains(farg.uri));
-                expectedBootClasspath.add("-Xbootclasspath/p:" + farg.location);
-            }
-        }
-
-        for (String line : mod.getJvmArgs())
-        {
-            expectedBootClasspath.remove(line);
-        }
-
-        if (expectedBootClasspath.size() > 0)
-        {
-            StringBuilder err = new StringBuilder();
-            err.append("XBootClasspath mismatch between [files] and [exec]");
-            err.append("\nThe following are inferred from your [files] definition in ");
-            err.append(modFile.toAbsolutePath().toString());
-            err.append("\nbut are not referenced in your [exec] section");
-            for (String entry : expectedBootClasspath)
-            {
-                err.append("\n").append(entry);
-            }
-            fail(err.toString());
-        }
-    }
-
-    public static void main(String[] args)
-    {
-        File outputDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getSimpleName() + "-main");
-        FS.ensureEmpty(outputDir);
-        for (String ref : KNOWN_GOOD_NPN_URLS)
-        {
-            try
-            {
-                URL url = new URL(ref);
-                System.err.printf("Attempting: %s%n",ref);
-                HttpURLConnection connection = (HttpURLConnection)url.openConnection();
-                String refname = url.toURI().getPath();
-                int idx = refname.lastIndexOf('/');
-                File outputFile = new File(outputDir,refname.substring(idx));
-                try (InputStream stream = connection.getInputStream(); FileOutputStream out = new FileOutputStream(outputFile))
-                {
-                    assertThat("Response Status Code",connection.getResponseCode(),is(200));
-                    IO.copy(stream,out);
-                    System.err.printf("Downloaded %,d bytes%n",outputFile.length());
-                }
-                catch (IOException e)
-                {
-                    e.printStackTrace(System.err);
-                }
-            }
-            catch (MalformedURLException e)
-            {
-                System.err.printf("Bad Ref: %s%n",ref);
-                e.printStackTrace(System.err);
-            }
-            catch (URISyntaxException e)
-            {
-                System.err.printf("Bad Ref Syntax: %s%n",ref);
-                e.printStackTrace(System.err);
-            }
-            catch (IOException e)
-            {
-                System.err.printf("Bad Connection: %s%n",ref);
-                e.printStackTrace(System.err);
-            }
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java
deleted file mode 100644
index 57f4600..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java
+++ /dev/null
@@ -1,207 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class NPNNegotiationTest extends AbstractNPNTest
-{
-    @Test
-    public void testServerAdvertisingHTTPSpeaksHTTP() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            NextProtoNego.put(client, new NextProtoNego.ClientProvider()
-            {
-                @Override
-                public boolean supports()
-                {
-                    return true;
-                }
-
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public String selectProtocol(List<String> strings)
-                {
-                    Assert.assertNotNull(strings);
-                    String protocol = "http/1.1";
-                    Assert.assertTrue(strings.contains(protocol));
-                    return protocol;
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-
-    @Test
-    public void testServerAdvertisingSPDYAndHTTPSpeaksHTTPWhenNegotiated() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            NextProtoNego.put(client, new NextProtoNego.ClientProvider()
-            {
-                @Override
-                public boolean supports()
-                {
-                    return true;
-                }
-
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public String selectProtocol(List<String> strings)
-                {
-                    Assert.assertNotNull(strings);
-                    String spdyProtocol = "spdy/2";
-                    Assert.assertTrue(strings.contains(spdyProtocol));
-                    String httpProtocol = "http/1.1";
-                    Assert.assertTrue(strings.contains(httpProtocol));
-                    Assert.assertTrue(strings.indexOf(spdyProtocol) < strings.indexOf(httpProtocol));
-                    return httpProtocol;
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-
-    @Test
-    public void testServerAdvertisingSPDYAndHTTPSpeaksDefaultProtocolWhenNPNMissing() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        connector.addConnectionFactory(new HttpConnectionFactory());
-
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLContext sslContext = sslContextFactory.getSslContext();
-        try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()))
-        {
-            client.setUseClientMode(true);
-            client.setSoTimeout(5000);
-
-            NextProtoNego.put(client, new NextProtoNego.ClientProvider()
-            {
-                @Override
-                public boolean supports()
-                {
-                    return false;
-                }
-
-                @Override
-                public void unsupported()
-                {
-                }
-
-                @Override
-                public String selectProtocol(List<String> strings)
-                {
-                    return null;
-                }
-            });
-
-            client.startHandshake();
-
-            // Verify that the server really speaks http/1.1
-
-            OutputStream output = client.getOutputStream();
-            output.write(("" +
-                    "GET / HTTP/1.1\r\n" +
-                    "Host: localhost:" + address.getPort() + "\r\n" +
-                    "\r\n" +
-                    "").getBytes(StandardCharsets.UTF_8));
-            output.flush();
-
-            InputStream input = client.getInputStream();
-            BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
-            String line = reader.readLine();
-            Assert.assertTrue(line.contains(" 404 "));
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java
deleted file mode 100644
index f2350ed..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.lang.reflect.Field;
-import java.net.InetSocketAddress;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SSLEngineLeakTest extends AbstractNPNTest
-{
-    @Test
-    public void testSSLEngineLeak() throws Exception
-    {
-        System.gc();
-        Thread.sleep(1000);
-
-        Field field = NextProtoNego.class.getDeclaredField("objects");
-        field.setAccessible(true);
-        @SuppressWarnings("unchecked")
-        Map<Object, NextProtoNego.Provider> objects = (Map<Object, NextProtoNego.Provider>)field.get(null);
-        int initialSize = objects.size();
-
-        avoidStackLocalVariables();
-        // Allow the close to arrive to the server and the selector to process it
-        Thread.sleep(1000);
-
-        // Perform GC to be sure that the map is cleared
-        System.gc();
-        Thread.sleep(1000);
-
-        // Check that the map is empty
-        if (objects.size() != initialSize)
-        {
-            System.err.println(objects);
-            server.dumpStdErr();
-        }
-
-        Assert.assertEquals(initialSize, objects.size());
-    }
-
-    private void avoidStackLocalVariables() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        Session session = clientFactory.newSPDYClient(SPDY.V3).connect(address, null);
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java
deleted file mode 100644
index 1bb2a14..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.util.List;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SSLSynReplyTest extends AbstractNPNTest
-{
-    @Test
-    public void testGentleCloseDuringHandshake() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
-        sslEngine.setUseClientMode(true);
-        NextProtoNego.put(sslEngine, new NextProtoNego.ClientProvider()
-        {
-            @Override
-            public boolean supports()
-            {
-                return true;
-            }
-
-            @Override
-            public void unsupported()
-            {
-            }
-
-            @Override
-            public String selectProtocol(List<String> protocols)
-            {
-                return null;
-            }
-        });
-        sslEngine.beginHandshake();
-
-        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
-        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-        encrypted.flip();
-
-        try (SocketChannel channel = SocketChannel.open(address))
-        {
-            // Send ClientHello, immediately followed by TLS Close Alert and then by FIN
-            channel.write(encrypted);
-            sslEngine.closeOutbound();
-            encrypted.clear();
-            sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-            encrypted.flip();
-            channel.write(encrypted);
-            channel.shutdownOutput();
-
-            // Read ServerHello from server
-            encrypted.clear();
-            int read = channel.read(encrypted);
-            encrypted.flip();
-            Assert.assertTrue(read > 0);
-            // Cannot decrypt, as the SSLEngine has been already closed
-
-            // Now if we read more, we should either read the TLS Close Alert, or directly -1
-            encrypted.clear();
-            read = channel.read(encrypted);
-            // Sending a TLS Close Alert during handshake results in an exception when
-            // unwrapping that the server react to by closing the connection abruptly.
-            Assert.assertTrue(read < 0);
-        }
-    }
-
-    @Test
-    public void testAbruptCloseDuringHandshake() throws Exception
-    {
-        InetSocketAddress address = prepare();
-        SslContextFactory sslContextFactory = newSslContextFactory();
-        sslContextFactory.start();
-        SSLEngine sslEngine = sslContextFactory.newSSLEngine(address);
-        sslEngine.setUseClientMode(true);
-        NextProtoNego.put(sslEngine, new NextProtoNego.ClientProvider()
-        {
-            @Override
-            public boolean supports()
-            {
-                return true;
-            }
-
-            @Override
-            public void unsupported()
-            {
-            }
-
-            @Override
-            public String selectProtocol(List<String> protocols)
-            {
-                return null;
-            }
-        });
-        sslEngine.beginHandshake();
-
-        ByteBuffer encrypted = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
-        sslEngine.wrap(BufferUtil.EMPTY_BUFFER, encrypted);
-        encrypted.flip();
-
-        try (SocketChannel channel = SocketChannel.open(address))
-        {
-            // Send ClientHello, immediately followed by FIN (no TLS Close Alert)
-            channel.write(encrypted);
-            channel.shutdownOutput();
-
-            // Read ServerHello from server
-            encrypted.clear();
-            int read = channel.read(encrypted);
-            encrypted.flip();
-            Assert.assertTrue(read > 0);
-            ByteBuffer decrypted = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
-            sslEngine.unwrap(encrypted, decrypted);
-
-            // Now if we read more, we should either read the TLS Close Alert, or directly -1
-            encrypted.clear();
-            read = channel.read(encrypted);
-            // Since we have close the connection abruptly, the server also does so
-            Assert.assertTrue(read < 0);
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java
deleted file mode 100644
index 72f6ca4..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-
-public class NPNProxySPDYToHTTPLoadTest extends ProxySPDYToHTTPLoadTest
-{
-    public NPNProxySPDYToHTTPLoadTest(short version)
-    {
-        super(version, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"));
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java
deleted file mode 100644
index e28ca0e..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-public class NPNProxySPDYToHTTPTest extends ProxySPDYToHTTPTest
-{
-    public NPNProxySPDYToHTTPTest(short version)
-    {
-        super(version);
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java
deleted file mode 100644
index 3d00c6e..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-public class NPNProxySPDYToSPDYLoadTest extends ProxySPDYToSPDYLoadTest
-{
-    public NPNProxySPDYToSPDYLoadTest(short version)
-    {
-        super(version);
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java
deleted file mode 100644
index d92ba2b..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server.proxy;
-
-public class NPNProxySPDYToSPDYTest extends ProxySPDYToSPDYTest
-{
-    public NPNProxySPDYToSPDYTest(short version)
-    {
-        super(version);
-    }
-}
diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties
deleted file mode 100644
index ead13ec..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks
deleted file mode 100644
index 428ba54..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks
deleted file mode 100644
index 839cb8c..0000000
--- a/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks
+++ /dev/null
Binary files differ
diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml
deleted file mode 100644
index bd16a86..0000000
--- a/jetty-spdy/spdy-server/pom.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <groupId>org.eclipse.jetty.spdy</groupId>
-        <artifactId>spdy-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
-    </parent>
-
-    <modelVersion>4.0.0</modelVersion>
-    <artifactId>spdy-server</artifactId>
-    <name>Jetty :: SPDY :: Server Binding</name>
-
-    <properties>
-        <bundle-symbolic-name>${project.groupId}.server</bundle-symbolic-name>
-    </properties>
-
-    <url>http://www.eclipse.org/jetty</url>
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>org.eclipse.jetty.spdy.server;version="9.1"</Export-Package>
-                                <Import-Package>org.eclipse.jetty.alpn;resolution:=optional,org.eclipse.jetty.alpn.server;resolution:=optional, org.eclipse.jetty.npn;resolution:=optional,org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                                <_nouses>true</_nouses>
-                            </instructions>
-                          </configuration>
-                       </execution>
-                  </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.spdy</groupId>
-            <artifactId>spdy-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.npn</groupId>
-            <artifactId>npn-api</artifactId>
-            <version>${npn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty.alpn</groupId>
-            <artifactId>alpn-api</artifactId>
-            <version>${alpn.api.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java
deleted file mode 100644
index 0d5e20b..0000000
--- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.List;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.NegotiatingServerConnection;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class NPNServerConnection extends NegotiatingServerConnection implements NextProtoNego.ServerProvider
-{
-    private static final Logger LOG = Log.getLogger(NPNServerConnection.class);
-
-    public NPNServerConnection(EndPoint endPoint, SSLEngine engine, Connector connector, List<String> protocols, String defaultProtocol)
-    {
-        super(connector, endPoint, engine, protocols, defaultProtocol);
-        NextProtoNego.put(engine, this);
-    }
-
-    @Override
-    public void unsupported()
-    {
-        protocolSelected(getDefaultProtocol());
-    }
-
-    @Override
-    public List<String> protocols()
-    {
-        return getProtocols();
-    }
-
-    @Override
-    public void protocolSelected(String protocol)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} protocol selected {}", this, protocol);
-        setProtocol(protocol != null ? protocol : getDefaultProtocol());
-        NextProtoNego.remove(getSSLEngine());
-    }
-
-    @Override
-    public void close()
-    {
-        NextProtoNego.remove(getSSLEngine());
-        super.close();
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java
deleted file mode 100644
index 628d542..0000000
--- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.List;
-import javax.net.ssl.SSLEngine;
-
-import org.eclipse.jetty.io.AbstractConnection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.npn.NextProtoNego;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
-import org.eclipse.jetty.util.annotation.Name;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-
-public class NPNServerConnectionFactory extends NegotiatingServerConnectionFactory
-{
-    private static final Logger LOG = Log.getLogger(NPNServerConnectionFactory.class);
-
-    public NPNServerConnectionFactory(@Name("protocols") String... protocols)
-    {
-        super("npn", protocols);
-        try
-        {
-            ClassLoader npnClassLoader = NextProtoNego.class.getClassLoader();
-            if (npnClassLoader != null)
-            {
-                LOG.warn("NPN must be in the boot classloader, not in: " + npnClassLoader);
-                throw new IllegalStateException("NPN must be in the boot classloader");
-            }
-        }
-        catch (Throwable x)
-        {
-            LOG.warn("NPN not available: " + x);
-            throw new IllegalStateException("NPN not available", x);
-        }
-    }
-
-    @Override
-    protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
-    {
-        return new NPNServerConnection(endPoint, engine, connector, protocols, defaultProtocol);
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java
deleted file mode 100644
index 6ced409..0000000
--- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java
+++ /dev/null
@@ -1,245 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.eclipse.jetty.io.Connection;
-import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.AbstractConnectionFactory;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.spdy.CompressionFactory;
-import org.eclipse.jetty.spdy.FlowControlStrategy;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.StandardSession;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.FlowControlStrategyFactory;
-import org.eclipse.jetty.spdy.client.SPDYConnection;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.annotation.ManagedAttribute;
-import org.eclipse.jetty.util.annotation.ManagedObject;
-
-@ManagedObject("SPDY Server Connection Factory")
-public class SPDYServerConnectionFactory extends AbstractConnectionFactory
-{
-    /**
-     * @deprecated use {@link #checkProtocolNegotiationAvailable()} instead.
-     */
-    @Deprecated
-    public static void checkNPNAvailable()
-    {
-        checkProtocolNegotiationAvailable();
-    }
-
-    public static void checkProtocolNegotiationAvailable()
-    {
-        if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") &&
-                !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego"))
-            throw new IllegalStateException("No ALPN nor NPN classes available");
-    }
-
-    private static boolean isAvailableInBootClassPath(String className)
-    {
-        try
-        {
-            Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className);
-            if (klass.getClassLoader() != null)
-                throw new IllegalStateException(className + " must be on JVM boot classpath");
-            return true;
-        }
-        catch (ClassNotFoundException x)
-        {
-            return false;
-        }
-    }
-
-    private final Queue<Session> sessions = new ConcurrentLinkedQueue<>();
-    private final short version;
-    private final ServerSessionFrameListener listener;
-    private int initialWindowSize;
-    private boolean dispatchIO;
-
-    public SPDYServerConnectionFactory(int version)
-    {
-        this(version, null);
-    }
-
-    public SPDYServerConnectionFactory(int version, ServerSessionFrameListener listener)
-    {
-        super("spdy/" + version);
-        this.version = (short)version;
-        this.listener = listener;
-        setInitialWindowSize(65536);
-        setDispatchIO(true);
-    }
-
-    @ManagedAttribute("SPDY version")
-    public short getVersion()
-    {
-        return version;
-    }
-
-    public ServerSessionFrameListener getServerSessionFrameListener()
-    {
-        return listener;
-    }
-
-    @Override
-    public Connection newConnection(Connector connector, EndPoint endPoint)
-    {
-        CompressionFactory compressionFactory = new StandardCompressionFactory();
-        Parser parser = new Parser(compressionFactory.newDecompressor());
-        Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor());
-
-        ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint);
-        SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener,
-                isDispatchIO(), getInputBufferSize());
-
-        FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version);
-
-        StandardSession session = new StandardSession(getVersion(), connector.getByteBufferPool(),
-                connector.getScheduler(), connection, endPoint, connection, 2, listener,
-                generator, flowControlStrategy);
-        session.setWindowSize(getInitialWindowSize());
-        parser.addListener(session);
-        connection.setSession(session);
-
-        sessionOpened(session);
-
-        return configure(connection, connector, endPoint);
-    }
-
-    protected FlowControlStrategy newFlowControlStrategy(short version)
-    {
-        return FlowControlStrategyFactory.newFlowControlStrategy(version);
-    }
-
-    protected ServerSessionFrameListener provideServerSessionFrameListener(Connector connector, EndPoint endPoint)
-    {
-        return listener;
-    }
-
-    @ManagedAttribute("Initial Window Size")
-    public int getInitialWindowSize()
-    {
-        return initialWindowSize;
-    }
-
-    public void setInitialWindowSize(int initialWindowSize)
-    {
-        this.initialWindowSize = initialWindowSize;
-    }
-
-    @ManagedAttribute("Dispatch I/O to a pooled thread")
-    public boolean isDispatchIO()
-    {
-        return dispatchIO;
-    }
-
-    public void setDispatchIO(boolean dispatchIO)
-    {
-        this.dispatchIO = dispatchIO;
-    }
-
-    protected boolean sessionOpened(Session session)
-    {
-        // Add sessions only if the connector is not stopping
-        return sessions.offer(session);
-    }
-
-    protected boolean sessionClosed(Session session)
-    {
-        // Remove sessions only if the connector is not stopping
-        // to avoid concurrent removes during iterations
-        return sessions.remove(session);
-    }
-
-    void closeSessions()
-    {
-        for (Session session : sessions)
-            session.goAway(new GoAwayInfo(), Callback.Adapter.INSTANCE);
-        sessions.clear();
-    }
-
-    @Override
-    protected void doStop() throws Exception
-    {
-        closeSessions();
-        super.doStop();
-    }
-
-    public Collection<Session> getSessions()
-    {
-        return Collections.unmodifiableCollection(sessions);
-    }
-
-    @Override
-    protected void dumpThis(Appendable out) throws IOException
-    {
-        super.dumpThis(out);
-        dump(out, "", sessions);
-    }
-
-    private class ServerSPDYConnection extends SPDYConnection implements Runnable
-    {
-        private final ServerSessionFrameListener listener;
-        private final AtomicBoolean connected = new AtomicBoolean();
-
-        private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser,
-                                     ServerSessionFrameListener listener, boolean dispatchIO, int bufferSize)
-        {
-            super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(),
-                    dispatchIO, bufferSize);
-            this.listener = listener;
-        }
-
-        @Override
-        public void onOpen()
-        {
-            super.onOpen();
-            if (connected.compareAndSet(false, true))
-                getExecutor().execute(this);
-        }
-
-        @Override
-        public void onClose()
-        {
-            super.onClose();
-            sessionClosed(getSession());
-        }
-
-        @Override
-        public void run()
-        {
-            // NPE guard to support tests
-            if (listener != null)
-                listener.onConnect(getSession());
-        }
-    }
-
-}
diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java
deleted file mode 100644
index 4faee0b..0000000
--- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.Objects;
-
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-public class SPDYServerConnector extends ServerConnector
-{
-    public SPDYServerConnector(Server server, ServerSessionFrameListener listener)
-    {
-        super(server, (SslContextFactory)null, new SPDYServerConnectionFactory(SPDY.V2, listener));
-    }
-
-    public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener)
-    {
-        this(server, sslContextFactory, listener, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"));
-    }
-
-    public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener, NegotiatingServerConnectionFactory negotiator)
-    {
-        super(server, Objects.requireNonNull(sslContextFactory),
-                negotiator,
-                new SPDYServerConnectionFactory(SPDY.V3, listener),
-                new SPDYServerConnectionFactory(SPDY.V2, listener),
-                new HttpConnectionFactory());
-        negotiator.setDefaultProtocol("http/1.1");
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java
deleted file mode 100644
index 1366f0f..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-
-public abstract class AbstractTest
-{
-    @Rule
-    public final TestWatcher testName = new TestWatcher()
-    {
-
-        @Override
-        public void starting(Description description)
-        {
-            super.starting(description);
-            System.err.printf("Running %s.%s()%n",
-                    description.getClassName(),
-                    description.getMethodName());
-        }
-    };
-
-    protected final short version = SPDY.V2;
-
-    protected Server server;
-    protected SPDYClient.Factory clientFactory;
-    protected ServerConnector connector;
-
-    protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
-    {
-        return startServer(version, listener);
-    }
-
-    protected InetSocketAddress startServer(short version, ServerSessionFrameListener listener) throws Exception
-    {
-        if (server == null)
-            server = newServer();
-        if (connector == null)
-            connector = newSPDYServerConnector(server, listener);
-        if (listener == null)
-            listener = connector.getConnectionFactory(SPDYServerConnectionFactory.class).getServerSessionFrameListener();
-
-        ConnectionFactory spdy = new SPDYServerConnectionFactory(version, listener);
-        connector.addConnectionFactory(spdy);
-        connector.setPort(0);
-        server.addConnector(connector);
-
-        if (connector.getConnectionFactory(NPNServerConnectionFactory.class)!=null)
-            connector.getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol(spdy.getProtocol());
-        else
-            connector.setDefaultProtocol(spdy.getProtocol());
-
-        server.start();
-        return new InetSocketAddress("localhost", connector.getLocalPort());
-    }
-
-    protected Server newServer()
-    {
-        QueuedThreadPool pool = new QueuedThreadPool();
-        pool.setName(pool.getName()+"-server");
-        return new Server(pool);
-    }
-
-    protected ServerConnector newSPDYServerConnector(Server server, ServerSessionFrameListener listener)
-    {
-        return new SPDYServerConnector(server, listener);
-    }
-
-    protected Session startClient(InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception
-    {
-        return startClient(version, socketAddress, listener);
-    }
-
-    protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception
-    {
-        if (clientFactory == null)
-        {
-            QueuedThreadPool threadPool = new QueuedThreadPool();
-            threadPool.setName(threadPool.getName() + "-client");
-            clientFactory = newSPDYClientFactory(threadPool);
-        }
-        clientFactory.start();
-
-        return clientFactory.newSPDYClient(version).connect(socketAddress, listener);
-    }
-
-    protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool)
-    {
-        return new SPDYClient.Factory(threadPool);
-    }
-
-    protected SslContextFactory newSslContextFactory()
-    {
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
-        sslContextFactory.setKeyStorePassword("storepwd");
-        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
-        sslContextFactory.setTrustStorePassword("storepwd");
-        sslContextFactory.setProtocol("TLSv1");
-        sslContextFactory.setIncludeProtocols("TLSv1");
-        return sslContextFactory;
-    }
-
-    @After
-    public void destroy() throws Exception
-    {
-        if (clientFactory != null)
-        {
-            clientFactory.stop();
-        }
-        if (server != null)
-        {
-            server.stop();
-            server.join();
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java
deleted file mode 100644
index 07eb552..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ClosedStreamTest.java
+++ /dev/null
@@ -1,273 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.SocketChannel;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.GoAwayFrame;
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.spdy.parser.Parser.Listener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class ClosedStreamTest extends AbstractTest
-{
-    //TODO: Right now it sends a rst as the stream is unknown to the session once it's closed.
-    //TODO: But according to the spec we probably should just ignore the data?!
-    @Test
-    public void testDataSentOnClosedStreamIsIgnored() throws Exception
-    {
-        ServerSocketChannel server = ServerSocketChannel.open();
-        server.bind(new InetSocketAddress("localhost", 0));
-
-        Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataLatch.countDown();
-            }
-        });
-
-        SocketChannel channel = server.accept();
-        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
-        channel.read(readBuffer);
-        readBuffer.flip();
-        int streamId = readBuffer.getInt(8);
-
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-
-        ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Fields()));
-        channel.write(writeBuffer);
-        Assert.assertThat(writeBuffer.hasRemaining(), is(false));
-
-        byte[] bytes = new byte[1];
-        writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
-        channel.write(writeBuffer);
-        Assert.assertThat(writeBuffer.hasRemaining(), is(false));
-
-        // Write again to simulate the faulty condition
-        writeBuffer.flip();
-        channel.write(writeBuffer);
-        Assert.assertThat(writeBuffer.hasRemaining(), is(false));
-
-        Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
-
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        server.close();
-    }
-
-    @Test
-    public void testSendDataOnHalfClosedStreamCausesExceptionOnServer() throws Exception
-    {
-        final CountDownLatch replyReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch clientReceivedDataLatch = new CountDownLatch(1);
-        final CountDownLatch exceptionWhenSendingData = new CountDownLatch(1);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                try
-                {
-                    replyReceivedLatch.await(5,TimeUnit.SECONDS);
-                }
-                catch (InterruptedException e)
-                {
-                    e.printStackTrace();
-                }
-                try
-                {
-                    stream.data(new StringDataInfo("data send after half closed",false), new Callback.Adapter());
-                }
-                catch (RuntimeException e)
-                {
-                    // we expect an exception here, but we don't want it to be logged
-                    exceptionWhenSendingData.countDown();
-                }
-
-                return null;
-            }
-        }),null);
-
-        Stream stream = clientSession.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyReceivedLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                clientReceivedDataLatch.countDown();
-            }
-        });
-        assertThat("reply has been received by client",replyReceivedLatch.await(5,TimeUnit.SECONDS),is(true));
-        assertThat("stream is half closed from server",stream.isHalfClosed(),is(true));
-        assertThat("client has not received any data sent after stream was half closed by server",
-                clientReceivedDataLatch.await(1,TimeUnit.SECONDS), is(false));
-        assertThat("sending data threw an exception",exceptionWhenSendingData.await(5,TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testV2ReceiveDataOnHalfClosedStream() throws Exception
-    {
-        runReceiveDataOnHalfClosedStream(SPDY.V2);
-    }
-
-    @Test
-    @Ignore("until v3 is properly implemented")
-    public void testV3ReceiveDataOnHalfClosedStream() throws Exception
-    {
-        runReceiveDataOnHalfClosedStream(SPDY.V3);
-    }
-
-    private void runReceiveDataOnHalfClosedStream(short version) throws Exception
-    {
-        final CountDownLatch clientResetReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch serverReplySentLatch = new CountDownLatch(1);
-        final CountDownLatch clientReplyReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch serverDataReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1);
-
-        InetSocketAddress startServer = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                serverReplySentLatch.countDown();
-                try
-                {
-                    clientReplyReceivedLatch.await(5,TimeUnit.SECONDS);
-                }
-                catch (InterruptedException e)
-                {
-                    e.printStackTrace();
-                }
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        serverDataReceivedLatch.countDown();
-                    }
-                };
-            }
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                goAwayReceivedLatch.countDown();
-            }
-        });
-
-        final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory().newCompressor());
-        int streamId = 1;
-        ByteBuffer synData = generator.control(new SynStreamFrame(version,SynInfo.FLAG_CLOSE, streamId,0,(byte)0,(short)0,new Fields()));
-
-        final SocketChannel socketChannel = SocketChannel.open(startServer);
-        socketChannel.write(synData);
-        assertThat("synData is fully written", synData.hasRemaining(), is(false));
-
-        assertThat("server: push reply is sent",serverReplySentLatch.await(5,TimeUnit.SECONDS),is(true));
-
-        Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
-        parser.addListener(new Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                if (frame instanceof SynReplyFrame)
-                {
-                    SynReplyFrame synReplyFrame = (SynReplyFrame)frame;
-                    clientReplyReceivedLatch.countDown();
-                    int streamId = synReplyFrame.getStreamId();
-                    ByteBuffer data = generator.data(streamId,0,new StringDataInfo("data",false));
-                    try
-                    {
-                        socketChannel.write(data);
-                    }
-                    catch (IOException e)
-                    {
-                        e.printStackTrace();
-                    }
-                }
-                else if (frame instanceof RstStreamFrame)
-                {
-                    clientResetReceivedLatch.countDown();
-                }
-            }
-        });
-        ByteBuffer response = ByteBuffer.allocate(28);
-        socketChannel.read(response);
-        response.flip();
-        parser.parse(response);
-
-        assertThat("server didn't receive data",serverDataReceivedLatch.await(1,TimeUnit.SECONDS),not(true));
-        assertThat("client didn't receive reset",clientResetReceivedLatch.await(1,TimeUnit.SECONDS),not(true));
-
-        ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode()));
-        socketChannel.write(buffer);
-        Assert.assertThat(buffer.hasRemaining(), is(false));
-
-        assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5,TimeUnit.SECONDS), is(true));
-
-        socketChannel.close();
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java
deleted file mode 100644
index 2953f9c..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/FlowControlTest.java
+++ /dev/null
@@ -1,493 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.nio.ByteBuffer;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Exchanger;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.SPDYException;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.FutureCallback;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class FlowControlTest extends AbstractTest
-{
-    @Test
-    public void testFlowControlWithConcurrentSettings() throws Exception
-    {
-        // Initial window is 64 KiB. We allow the client to send 1024 B
-        // then we change the window to 512 B. At this point, the client
-        // must stop sending data (although the initial window allows it)
-
-        final int size = 512;
-        final AtomicReference<DataInfo> dataInfoRef = new AtomicReference<>();
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        final CountDownLatch settingsLatch = new CountDownLatch(1);
-        Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                return new StreamFrameListener.Adapter()
-                {
-                    private final AtomicInteger dataFrames = new AtomicInteger();
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        int dataFrameCount = dataFrames.incrementAndGet();
-                        if (dataFrameCount == 1)
-                        {
-                            dataInfoRef.set(dataInfo);
-                            Settings settings = new Settings();
-                            settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, size));
-                            stream.getSession().settings(new SettingsInfo(settings), new FutureCallback());
-                        }
-                        else if (dataFrameCount > 1)
-                        {
-                            dataInfo.consume(dataInfo.length());
-                            dataLatch.countDown();
-                        }
-                    }
-                };
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                settingsLatch.countDown();
-            }
-        });
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        stream.data(new BytesDataInfo(new byte[size * 2], false));
-        settingsLatch.await(5, TimeUnit.SECONDS);
-
-        // Send the second chunk of data, must not arrive since we're flow control stalled now
-        stream.data(new BytesDataInfo(new byte[size * 2], true), new Callback.Adapter());
-        Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
-
-        // Consume the data arrived to server, this will resume flow control
-        DataInfo dataInfo = dataInfoRef.get();
-        dataInfo.consume(dataInfo.length());
-
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testServerFlowControlOneBigWrite() throws Exception
-    {
-        final int windowSize = 1536;
-        final int length = 5 * windowSize;
-        final CountDownLatch settingsLatch = new CountDownLatch(1);
-        Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                settingsLatch.countDown();
-            }
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter());
-                return null;
-            }
-        }), null);
-
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize));
-        session.settings(new SettingsInfo(settings));
-
-        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
-
-        final Exchanger<DataInfo> exchanger = new Exchanger<>();
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            private AtomicInteger dataFrames = new AtomicInteger();
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                try
-                {
-                    int dataFrames = this.dataFrames.incrementAndGet();
-                    if (dataFrames == 1)
-                    {
-                        // Do not consume nor read from the data frame.
-                        // We should then be flow-control stalled
-                        exchanger.exchange(dataInfo);
-                    }
-                    else if (dataFrames == 2)
-                    {
-                        // Read but not consume, we should be flow-control stalled
-                        dataInfo.asByteBuffer(false);
-                        exchanger.exchange(dataInfo);
-                    }
-                    else if (dataFrames == 3)
-                    {
-                        // Consume partially, we should be flow-control stalled
-                        dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2));
-                        exchanger.exchange(dataInfo);
-                    }
-                    else if (dataFrames == 4 || dataFrames == 5)
-                    {
-                        // Consume totally
-                        dataInfo.asByteBuffer(true);
-                        exchanger.exchange(dataInfo);
-                    }
-                    else
-                    {
-                        Assert.fail();
-                    }
-                }
-                catch (InterruptedException x)
-                {
-                    throw new SPDYException(x);
-                }
-            }
-        });
-
-        DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(windowSize, dataInfo.available());
-        Assert.assertEquals(0, dataInfo.consumed());
-        dataInfo.asByteBuffer(true);
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(0, dataInfo.available());
-        Assert.assertEquals(0, dataInfo.consumed());
-        dataInfo.consume(dataInfo.length());
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed());
-        dataInfo.asByteBuffer(true);
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        Assert.assertEquals(dataInfo.length(), dataInfo.consumed());
-        // Check that we are not flow control stalled
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        Assert.assertEquals(dataInfo.length(), dataInfo.consumed());
-    }
-
-    @Test
-    public void testClientFlowControlOneBigWrite() throws Exception
-    {
-        final int windowSize = 1536;
-        final Exchanger<DataInfo> exchanger = new Exchanger<>();
-        final CountDownLatch settingsLatch = new CountDownLatch(1);
-        Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                Settings settings = new Settings();
-                settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize));
-                session.settings(new SettingsInfo(settings), new FutureCallback());
-            }
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                return new StreamFrameListener.Adapter()
-                {
-                    private AtomicInteger dataFrames = new AtomicInteger();
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        try
-                        {
-                            int dataFrames = this.dataFrames.incrementAndGet();
-                            if (dataFrames == 1)
-                            {
-                                // Do not consume nor read from the data frame.
-                                // We should then be flow-control stalled
-                                exchanger.exchange(dataInfo);
-                            }
-                            else if (dataFrames == 2)
-                            {
-                                // Read but not consume, we should be flow-control stalled
-                                dataInfo.asByteBuffer(false);
-                                exchanger.exchange(dataInfo);
-                            }
-                            else if (dataFrames == 3)
-                            {
-                                // Consume partially, we should be flow-control stalled
-                                dataInfo.consumeInto(ByteBuffer.allocate(dataInfo.length() / 2));
-                                exchanger.exchange(dataInfo);
-                            }
-                            else if (dataFrames == 4 || dataFrames == 5)
-                            {
-                                // Consume totally
-                                dataInfo.asByteBuffer(true);
-                                exchanger.exchange(dataInfo);
-                            }
-                            else
-                            {
-                                Assert.fail();
-                            }
-                        }
-                        catch (InterruptedException x)
-                        {
-                            throw new SPDYException(x);
-                        }
-                    }
-                };
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                settingsLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        final int length = 5 * windowSize;
-        stream.data(new BytesDataInfo(new byte[length], true), new Callback.Adapter());
-
-        DataInfo dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(windowSize, dataInfo.available());
-        Assert.assertEquals(0, dataInfo.consumed());
-        dataInfo.asByteBuffer(true);
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(0, dataInfo.available());
-        Assert.assertEquals(0, dataInfo.consumed());
-        dataInfo.consume(dataInfo.length());
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        checkThatWeAreFlowControlStalled(exchanger);
-
-        Assert.assertEquals(dataInfo.length() / 2, dataInfo.consumed());
-        dataInfo.asByteBuffer(true);
-
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        Assert.assertEquals(dataInfo.length(), dataInfo.consumed());
-        // Check that we are not flow control stalled
-        dataInfo = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-        Assert.assertEquals(dataInfo.length(), dataInfo.consumed());
-    }
-
-    @Test
-    public void testStreamsStalledDoesNotStallOtherStreams() throws Exception
-    {
-        final int windowSize = 1024;
-        final CountDownLatch settingsLatch = new CountDownLatch(1);
-        Session session = startClient(SPDY.V3, startServer(SPDY.V3, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                settingsLatch.countDown();
-            }
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(new BytesDataInfo(new byte[windowSize * 2], true), new Callback.Adapter());
-                return null;
-            }
-        }), null);
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize));
-        session.settings(new SettingsInfo(settings));
-
-        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
-
-        final CountDownLatch latch = new CountDownLatch(3);
-        final AtomicReference<DataInfo> dataInfoRef1 = new AtomicReference<>();
-        final AtomicReference<DataInfo> dataInfoRef2 = new AtomicReference<>();
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger dataFrames = new AtomicInteger();
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                int frames = dataFrames.incrementAndGet();
-                if (frames == 1)
-                {
-                    // Do not consume it to stall flow control
-                    dataInfoRef1.set(dataInfo);
-                }
-                else
-                {
-                    dataInfo.consume(dataInfo.length());
-                    if (dataInfo.isClose())
-                        latch.countDown();
-                }
-            }
-        });
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
-        {
-            private final AtomicInteger dataFrames = new AtomicInteger();
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                int frames = dataFrames.incrementAndGet();
-                if (frames == 1)
-                {
-                    // Do not consume it to stall flow control
-                    dataInfoRef2.set(dataInfo);
-                }
-                else
-                {
-                    dataInfo.consume(dataInfo.length());
-                    if (dataInfo.isClose())
-                        latch.countDown();
-                }
-            }
-        });
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                DataInfo dataInfo1 = dataInfoRef1.getAndSet(null);
-                if (dataInfo1 != null)
-                    dataInfo1.consume(dataInfo1.length());
-                DataInfo dataInfo2 = dataInfoRef2.getAndSet(null);
-                if (dataInfo2 != null)
-                    dataInfo2.consume(dataInfo2.length());
-                dataInfo.consume(dataInfo.length());
-                if (dataInfo.isClose())
-                    latch.countDown();
-            }
-        });
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSendBigFileWithoutFlowControl() throws Exception
-    {
-        testSendBigFile(SPDY.V2);
-    }
-
-    @Test
-    public void testSendBigFileWithFlowControl() throws Exception
-    {
-        testSendBigFile(SPDY.V3);
-    }
-
-    private void testSendBigFile(short version) throws Exception
-    {
-        final int dataSize = 1024 * 1024;
-        final ByteBufferDataInfo bigByteBufferDataInfo = new ByteBufferDataInfo(ByteBuffer.allocate(dataSize),false);
-        final CountDownLatch allDataReceivedLatch = new CountDownLatch(1);
-
-        Session session = startClient(version, startServer(version, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(bigByteBufferDataInfo, new Callback.Adapter());
-                return null;
-            }
-        }),new SessionFrameListener.Adapter());
-
-        session.syn(new SynInfo(new Fields(), false),new StreamFrameListener.Adapter()
-        {
-            private int dataBytesReceived;
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataBytesReceived = dataBytesReceived + dataInfo.length();
-                dataInfo.consume(dataInfo.length());
-                if (dataBytesReceived == dataSize)
-                    allDataReceivedLatch.countDown();
-            }
-        });
-
-        assertThat("all data bytes have been received by the client", allDataReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private void checkThatWeAreFlowControlStalled(final Exchanger<DataInfo> exchanger)
-    {
-        expectException(TimeoutException.class, new Callable<DataInfo>()
-        {
-            @Override
-            public DataInfo call() throws Exception
-            {
-                return exchanger.exchange(null, 1, TimeUnit.SECONDS);
-            }
-        });
-    }
-
-    private void expectException(Class<? extends Exception> exception, Callable<DataInfo> command)
-    {
-        try
-        {
-            command.call();
-            Assert.fail();
-        }
-        catch (Exception x)
-        {
-            Assert.assertSame(exception, x.getClass());
-        }
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java
deleted file mode 100644
index a834202..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/GoAwayTest.java
+++ /dev/null
@@ -1,234 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.FutureCallback;
-import org.eclipse.jetty.util.FuturePromise;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class GoAwayTest extends AbstractTest
-{
-    @Test
-    public void testServerReceivesGoAwayOnClientGoAway() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                return null;
-            }
-
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                Assert.assertEquals(0, goAwayInfo.getLastStreamId());
-                Assert.assertSame(SessionStatus.OK, goAwayInfo.getSessionStatus());
-                latch.countDown();
-            }
-        };
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        session.goAway(new GoAwayInfo());
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testClientReceivesGoAwayOnServerGoAway() throws Exception
-    {
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
-                return null;
-            }
-        };
-        final AtomicReference<GoAwayResultInfo> ref = new AtomicReference<>();
-        final CountDownLatch latch = new CountDownLatch(1);
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                ref.set(goAwayInfo);
-                latch.countDown();
-            }
-        };
-        Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
-
-        Stream stream1 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-        GoAwayResultInfo goAwayResultInfo = ref.get();
-        Assert.assertNotNull(goAwayResultInfo);
-        Assert.assertEquals(stream1.getId(), goAwayResultInfo.getLastStreamId());
-        Assert.assertSame(SessionStatus.OK, goAwayResultInfo.getSessionStatus());
-    }
-
-    @Test
-    public void testSynStreamIgnoredAfterGoAway() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            private final AtomicInteger syns = new AtomicInteger();
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                int synCount = syns.incrementAndGet();
-                if (synCount == 1)
-                {
-                    stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                    stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
-                }
-                else
-                {
-                    latch.countDown();
-                }
-                return null;
-            }
-        };
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                session.syn(new SynInfo(new Fields(), true), null, new FuturePromise<Stream>());
-            }
-        };
-        Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
-
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        Assert.assertFalse(latch.await(1, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testDataNotProcessedAfterGoAway() throws Exception
-    {
-        final CountDownLatch closeLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            private AtomicInteger syns = new AtomicInteger();
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                int synCount = syns.incrementAndGet();
-                if (synCount == 1)
-                {
-                    return null;
-                }
-                else
-                {
-                    stream.getSession().goAway(new GoAwayInfo(), new FutureCallback());
-                    closeLatch.countDown();
-                    return new StreamFrameListener.Adapter()
-                    {
-                        @Override
-                        public void onData(Stream stream, DataInfo dataInfo)
-                        {
-                            dataLatch.countDown();
-                        }
-                    };
-                }
-            }
-        };
-        final AtomicReference<GoAwayResultInfo> goAwayRef = new AtomicReference<>();
-        final CountDownLatch goAwayLatch = new CountDownLatch(1);
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                goAwayRef.set(goAwayInfo);
-                goAwayLatch.countDown();
-            }
-        };
-        Session session = startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
-
-        // First stream is processed ok
-        final CountDownLatch reply1Latch = new CountDownLatch(1);
-        session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                reply1Latch.countDown();
-            }
-        });
-        Assert.assertTrue(reply1Latch.await(5, TimeUnit.SECONDS));
-
-        // Second stream is closed in the middle
-        Stream stream2 = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
-
-        // There is a race between the data we want to send, and the client
-        // closing the connection because the server closed it after the
-        // go_away, so we guard with a try/catch to have the test pass cleanly
-        try
-        {
-            stream2.data(new StringDataInfo("foo", true));
-            Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
-        }
-        catch (ExecutionException x)
-        {
-            // doesn't matter which exception we get, it's important that the data is not been written and the
-            // previous assertion is true
-        }
-
-        // The last good stream is the second, because it was received by the server
-        Assert.assertTrue(goAwayLatch.await(5, TimeUnit.SECONDS));
-        GoAwayResultInfo goAway = goAwayRef.get();
-        Assert.assertNotNull(goAway);
-        Assert.assertEquals(stream2.getId(), goAway.getLastStreamId());
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java
deleted file mode 100644
index 34f3c82..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/HeadersTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class HeadersTest extends AbstractTest
-{
-    @Test
-    public void testHeaders() throws Exception
-    {
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onHeaders(Stream stream, HeadersInfo headersInfo)
-                    {
-                        Assert.assertTrue(stream.isHalfClosed());
-                        stream.headers(new HeadersInfo(new Fields(), true), new Callback.Adapter());
-                        Assert.assertTrue(stream.isClosed());
-                    }
-                };
-            }
-        };
-
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Fields headers = new Fields();
-                headers.put("foo", "bar");
-                headers.put("baz", "woo");
-                stream.headers(new HeadersInfo(headers, true), new Callback.Adapter());
-                Assert.assertTrue(stream.isHalfClosed());
-            }
-
-            @Override
-            public void onHeaders(Stream stream, HeadersInfo headersInfo)
-            {
-                Assert.assertTrue(stream.isClosed());
-                latch.countDown();
-            }
-        });
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java
deleted file mode 100644
index 195bb6a..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/IdleTimeoutTest.java
+++ /dev/null
@@ -1,257 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class IdleTimeoutTest extends AbstractTest
-{
-    private final int idleTimeout = 1000;
-
-    @Test
-    public void testServerEnforcingIdleTimeout() throws Exception
-    {
-        server = newServer();
-        connector = newSPDYServerConnector(server, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                return null;
-            }
-        });
-        connector.setIdleTimeout(idleTimeout);
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testServerEnforcingIdleTimeoutWithUnrespondedStream() throws Exception
-    {
-        server = newServer();
-        connector = newSPDYServerConnector(server, null);
-        connector.setIdleTimeout(idleTimeout);
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        // The SYN is not replied, and the server should idle timeout
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testServerNotEnforcingIdleTimeoutWithPendingStream() throws Exception
-    {
-        server = newServer();
-        connector = newSPDYServerConnector(server, new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                try
-                {
-                    Thread.sleep(2 * idleTimeout);
-                    stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                    return null;
-                }
-                catch (InterruptedException x)
-                {
-                    Assert.fail();
-                    return null;
-                }
-            }
-        });
-        connector.setIdleTimeout(idleTimeout);
-
-        final CountDownLatch goAwayLatch = new CountDownLatch(1);
-        Session session = startClient(startServer(null), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                goAwayLatch.countDown();
-            }
-        });
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS));
-
-        // Just make sure onGoAway has never been called, but don't wait too much
-        Assert.assertFalse(goAwayLatch.await(idleTimeout / 2, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testClientEnforcingIdleTimeout() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                return null;
-            }
-
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setName(threadPool.getName() + "-client");
-        clientFactory = newSPDYClientFactory(threadPool);
-        clientFactory.start();
-        SPDYClient client = clientFactory.newSPDYClient(SPDY.V2);
-        client.setIdleTimeout(idleTimeout);
-        Session session = client.connect(address, null);
-
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testClientEnforcingIdleTimeoutWithUnrespondedStream() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setName(threadPool.getName() + "-client");
-        clientFactory = newSPDYClientFactory(threadPool);
-        clientFactory.start();
-        SPDYClient client = clientFactory.newSPDYClient(SPDY.V2);
-        client.setIdleTimeout(idleTimeout);
-        Session session = client.connect(address, null);
-
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void testClientNotEnforcingIdleTimeoutWithPendingStream() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                return null;
-            }
-
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        QueuedThreadPool threadPool = new QueuedThreadPool();
-        threadPool.setName(threadPool.getName() + "-client");
-        clientFactory = newSPDYClientFactory(threadPool);
-        clientFactory.start();
-        SPDYClient client = clientFactory.newSPDYClient(SPDY.V2);
-        client.setIdleTimeout(idleTimeout);
-        Session session = client.connect(address, null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                try
-                {
-                    Thread.sleep(2 * idleTimeout);
-                    replyLatch.countDown();
-                }
-                catch (InterruptedException e)
-                {
-                    Assert.fail();
-                }
-            }
-        });
-
-        Assert.assertFalse(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
-        Assert.assertTrue(replyLatch.await(3 * idleTimeout, TimeUnit.MILLISECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java
deleted file mode 100644
index 9cc8115..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MaxConcurrentStreamTest extends AbstractTest
-{
-    @Test
-    public void testMaxConcurrentStreamsSetByServer() throws Exception, ExecutionException
-    {
-        final CountDownLatch settingsReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch dataReceivedLatch = new CountDownLatch(1);
-
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                Settings settings = new Settings();
-                settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 1));
-                try
-                {
-                    session.settings(new SettingsInfo(settings));
-                }
-                catch (ExecutionException | InterruptedException | TimeoutException e)
-                {
-                    e.printStackTrace();
-                }
-            }
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                try
-                {
-                    stream.reply(new ReplyInfo(true));
-                }
-                catch (ExecutionException | InterruptedException | TimeoutException e)
-                {
-                    e.printStackTrace();
-                }
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataReceivedLatch.countDown();
-                    }
-                };
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                settingsReceivedLatch.countDown();
-            }
-        });
-
-        assertThat("Settings frame received", settingsReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-
-        SynInfo synInfo = new SynInfo(new Fields(), false);
-        Stream stream = session.syn(synInfo, null);
-
-        boolean failed = false;
-        try
-        {
-            session.syn(synInfo, null);
-        }
-        catch (ExecutionException | InterruptedException | TimeoutException e)
-        {
-            failed = true;
-        }
-
-        assertThat("Opening second stream failed", failed, is(true));
-
-        stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true));
-        assertThat("Data has been received on first stream.", dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java
deleted file mode 100644
index 1684229..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PingTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.PingInfo;
-import org.eclipse.jetty.spdy.api.PingResultInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Promise;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PingTest extends AbstractTest
-{
-    @Test
-    public void testPingPong() throws Exception
-    {
-        final AtomicReference<PingResultInfo> ref = new AtomicReference<>();
-        final CountDownLatch latch = new CountDownLatch(1);
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onPing(Session session, PingResultInfo pingInfo)
-            {
-                ref.set(pingInfo);
-                latch.countDown();
-            }
-        };
-        Session session = startClient(startServer(null), clientSessionFrameListener);
-        PingResultInfo pingResultInfo = session.ping(new PingInfo(5, TimeUnit.SECONDS));
-        Assert.assertEquals(1, pingResultInfo.getPingId() % 2);
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-        PingResultInfo pongInfo = ref.get();
-        Assert.assertNotNull(pongInfo);
-        Assert.assertEquals(pingResultInfo.getPingId(), pongInfo.getPingId());
-    }
-
-    @Test
-    public void testServerPingPong() throws Exception
-    {
-        final CountDownLatch pingReceived = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            private final CountDownLatch pingSent = new CountDownLatch(1);
-            private int pingId;
-
-            @Override
-            public void onConnect(Session session)
-            {
-                session.ping(new PingInfo(), new Promise.Adapter<PingResultInfo>()
-                {
-                    @Override
-                    public void succeeded(PingResultInfo pingInfo)
-                    {
-                        pingId = pingInfo.getPingId();
-                        pingSent.countDown();
-                    }
-                });
-            }
-
-            @Override
-            public void onPing(Session session, PingResultInfo pingInfo)
-            {
-                try
-                {
-                    // This callback may be notified before the promise above,
-                    // so make sure we wait here to know the pingId
-                    Assert.assertTrue(pingSent.await(5, TimeUnit.SECONDS));
-                    Assert.assertEquals(0, pingInfo.getPingId() % 2);
-                    Assert.assertEquals(pingId, pingInfo.getPingId());
-                    pingReceived.countDown();
-                }
-                catch (InterruptedException x)
-                {
-                    Assert.fail();
-                }
-            }
-        };
-        startClient(startServer(serverSessionFrameListener), null);
-
-        Assert.assertTrue(pingReceived.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java
deleted file mode 100644
index cedf9e1..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ProtocolViolationsTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.ServerSocketChannel;
-import java.nio.channels.SocketChannel;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.HeadersInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.SynReplyFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ProtocolViolationsTest extends AbstractTest
-{
-    @Test
-    public void testSendDataBeforeReplyIsIllegal() throws Exception
-    {
-        final CountDownLatch resetLatch = new CountDownLatch(1);
-        final CountDownLatch latch = new CountDownLatch(1);
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                try
-                {
-                    stream.data(new StringDataInfo("failure", true), new Callback.Adapter());
-                    return null;
-                }
-                catch (IllegalStateException x)
-                {
-                    latch.countDown();
-                    return null;
-                }
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus());
-                resetLatch.countDown();
-            }
-        });
-        session.syn(new SynInfo(new Fields(), true), null);
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testReceiveDataBeforeReplyIsIllegal() throws Exception
-    {
-        ServerSocketChannel server = ServerSocketChannel.open();
-        server.bind(new InetSocketAddress("localhost", 0));
-
-        Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
-        session.syn(new SynInfo(new Fields(), true), null);
-
-        SocketChannel channel = server.accept();
-        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
-        channel.read(readBuffer);
-        readBuffer.flip();
-        int streamId = readBuffer.getInt(8);
-
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-        byte[] bytes = new byte[1];
-        ByteBuffer writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
-        channel.write(writeBuffer);
-        assertThat("data is fully written", writeBuffer.hasRemaining(),is(false));
-
-        readBuffer.clear();
-        channel.read(readBuffer);
-        readBuffer.flip();
-        Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2));
-        Assert.assertEquals(streamId, readBuffer.getInt(8));
-
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        server.close();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testSendDataAfterCloseIsIllegal() throws Exception
-    {
-        Session session = startClient(startServer(null), null);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
-        stream.data(new StringDataInfo("test", true));
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testSendHeadersAfterCloseIsIllegal() throws Exception
-    {
-        Session session = startClient(startServer(null), null);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0), null);
-        stream.headers(new HeadersInfo(new Fields(), true));
-    }
-
-    @Test //TODO: throws an ISException in StandardStream.updateCloseState(). But instead we should send a rst or something to the server probably?!
-    public void testServerClosesStreamTwice() throws Exception
-    {
-        ServerSocketChannel server = ServerSocketChannel.open();
-        server.bind(new InetSocketAddress("localhost", 0));
-
-        Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                dataLatch.countDown();
-            }
-        });
-
-        SocketChannel channel = server.accept();
-        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
-        channel.read(readBuffer);
-        readBuffer.flip();
-        int streamId = readBuffer.getInt(8);
-
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-
-        ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Fields()));
-        channel.write(writeBuffer);
-        assertThat("SynReply is fully written", writeBuffer.hasRemaining(), is(false));
-
-        byte[] bytes = new byte[1];
-        writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
-        channel.write(writeBuffer);
-        assertThat("data is fully written", writeBuffer.hasRemaining(), is(false));
-
-        // Write again to simulate the faulty condition
-        writeBuffer.flip();
-        channel.write(writeBuffer);
-        assertThat("data is fully written", writeBuffer.hasRemaining(), is(false));
-
-        Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
-
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        server.close();
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java
deleted file mode 100644
index ab4e5ed..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/PushStreamTest.java
+++ /dev/null
@@ -1,591 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.Exchanger;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.PushInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.SessionStatus;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.DataFrame;
-import org.eclipse.jetty.spdy.frames.GoAwayFrame;
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.spdy.parser.Parser.Listener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PushStreamTest extends AbstractTest
-{
-    private static final Logger LOG = Log.getLogger(PushStreamTest.class);
-
-    @Test
-    public void testSynPushStream() throws Exception
-    {
-        final AtomicReference<Stream> pushStreamRef = new AtomicReference<>();
-        final CountDownLatch pushStreamLatch = new CountDownLatch(1);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.push(new PushInfo(new Fields(), true), new Promise.Adapter<Stream>());
-                return null;
-            }
-        }), null);
-
-        Stream stream = clientSession.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                assertThat("streamId is even", stream.getId() % 2, is(0));
-                assertThat("stream is unidirectional", stream.isUnidirectional(), is(true));
-                assertThat("stream is closed", stream.isClosed(), is(true));
-                assertThat("stream has associated stream", stream.getAssociatedStream(), notNullValue());
-                try
-                {
-                    stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                    fail("Cannot reply to push streams");
-                }
-                catch (IllegalStateException x)
-                {
-                    // Expected
-                }
-                pushStreamRef.set(stream);
-                pushStreamLatch.countDown();
-                return null;
-            }
-        });
-        assertThat("onSyn has been called", pushStreamLatch.await(5, TimeUnit.SECONDS), is(true));
-        Stream pushStream = pushStreamRef.get();
-        assertThat("main stream and associated stream are the same", stream, sameInstance(pushStream.getAssociatedStream()));
-    }
-
-    @Test
-    public void testSendDataOnPushStreamAfterAssociatedStreamIsClosed() throws Exception
-    {
-        final Exchanger<Stream> streamExchanger = new Exchanger<>();
-        final CountDownLatch pushStreamSynLatch = new CountDownLatch(1);
-        final CyclicBarrier replyBarrier = new CyclicBarrier(3);
-        final CyclicBarrier closeBarrier = new CyclicBarrier(3);
-        final CountDownLatch streamDataSent = new CountDownLatch(2);
-        final CountDownLatch pushStreamDataReceived = new CountDownLatch(2);
-        final CountDownLatch exceptionCountDownLatch = new CountDownLatch(1);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                try
-                {
-                    replyBarrier.await(5, TimeUnit.SECONDS);
-                    return new StreamFrameListener.Adapter()
-                    {
-                        @Override
-                        public void onData(Stream stream, DataInfo dataInfo)
-                        {
-                            try
-                            {
-                                if (dataInfo.isClose())
-                                {
-                                    stream.data(new StringDataInfo("close stream", true));
-                                    closeBarrier.await(5, TimeUnit.SECONDS);
-                                }
-                                streamDataSent.countDown();
-                                if (pushStreamDataReceived.getCount() == 2)
-                                {
-                                    Stream pushStream = stream.push(new PushInfo(new Fields(), false));
-                                    streamExchanger.exchange(pushStream, 5, TimeUnit.SECONDS);
-                                }
-                            }
-                            catch (Exception e)
-                            {
-                                exceptionCountDownLatch.countDown();
-                            }
-                        }
-                    };
-                }
-                catch (Exception e)
-                {
-                    exceptionCountDownLatch.countDown();
-                    throw new IllegalStateException(e);
-                }
-            }
-
-        }), null);
-
-        Stream stream = clientSession.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                pushStreamSynLatch.countDown();
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        pushStreamDataReceived.countDown();
-                        super.onData(stream, dataInfo);
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                try
-                {
-                    replyBarrier.await(5, TimeUnit.SECONDS);
-                }
-                catch (Exception e)
-                {
-                    exceptionCountDownLatch.countDown();
-                }
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                try
-                {
-                    closeBarrier.await(5, TimeUnit.SECONDS);
-                }
-                catch (Exception e)
-                {
-                    exceptionCountDownLatch.countDown();
-                }
-            }
-        });
-
-        replyBarrier.await(5, TimeUnit.SECONDS);
-        stream.data(new StringDataInfo("client data", false));
-        Stream pushStream = streamExchanger.exchange(null, 5, TimeUnit.SECONDS);
-        pushStream.data(new StringDataInfo("first push data frame", false));
-        // nasty, but less complex than using another cyclicBarrier for example
-        while (pushStreamDataReceived.getCount() != 1)
-            Thread.sleep(1);
-        stream.data(new StringDataInfo("client close", true));
-        closeBarrier.await(5, TimeUnit.SECONDS);
-        assertThat("stream is closed", stream.isClosed(), is(true));
-        pushStream.data(new StringDataInfo("second push data frame while associated stream has been closed already", false));
-        assertThat("2 pushStream data frames have been received.", pushStreamDataReceived.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("2 data frames have been sent", streamDataSent.await(5, TimeUnit.SECONDS), is(true));
-        assertThatNoExceptionOccurred(exceptionCountDownLatch);
-    }
-
-    @Test
-    public void testSynPushStreamOnClosedStream() throws Exception
-    {
-        final CountDownLatch pushStreamFailedLatch = new CountDownLatch(1);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                stream.push(new PushInfo(1, TimeUnit.SECONDS, new Fields(), false),
-                        new Promise.Adapter<Stream>()
-                        {
-                            @Override
-                            public void failed(Throwable x)
-                            {
-                                pushStreamFailedLatch.countDown();
-                            }
-                        });
-                return super.onSyn(stream, synInfo);
-            }
-        }), new SessionFrameListener.Adapter());
-
-        clientSession.syn(new SynInfo(new Fields(), true), null);
-        assertThat("pushStream push has failed", pushStreamFailedLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    @Test
-    public void testSendBigDataOnPushStreamWhenAssociatedStreamIsClosed() throws Exception
-    {
-        final CountDownLatch streamClosedLatch = new CountDownLatch(1);
-        final CountDownLatch allDataReceived = new CountDownLatch(1);
-        final CountDownLatch exceptionCountDownLatch = new CountDownLatch(1);
-        final Exchanger<ByteBuffer> exchanger = new Exchanger<>();
-        final int dataSizeInBytes = 1024 * 1024 * 1;
-        final byte[] transferBytes = createHugeByteArray(dataSizeInBytes);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                try
-                {
-                    Stream pushStream = stream.push(new PushInfo(new Fields(), false));
-                    stream.reply(new ReplyInfo(true));
-                    // wait until stream is closed
-                    streamClosedLatch.await(5, TimeUnit.SECONDS);
-                    pushStream.data(new BytesDataInfo(transferBytes, true), new Callback.Adapter());
-                    return null;
-                }
-                catch (Exception e)
-                {
-                    exceptionCountDownLatch.countDown();
-                    throw new IllegalStateException(e);
-                }
-            }
-        }), null);
-
-        Stream stream = clientSession.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-            {
-                return new StreamFrameListener.Adapter()
-                {
-                    ByteBuffer receivedBytes = ByteBuffer.allocate(dataSizeInBytes);
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataInfo.consumeInto(receivedBytes);
-                        if (dataInfo.isClose())
-                        {
-                            allDataReceived.countDown();
-                            try
-                            {
-                                receivedBytes.flip();
-                                exchanger.exchange(receivedBytes.slice(), 5, TimeUnit.SECONDS);
-                            }
-                            catch (Exception e)
-                            {
-                                exceptionCountDownLatch.countDown();
-                            }
-                        }
-                    }
-                };
-            }
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                streamClosedLatch.countDown();
-                super.onReply(stream, replyInfo);
-            }
-        });
-
-        ByteBuffer receivedBytes = exchanger.exchange(null, 5, TimeUnit.SECONDS);
-
-        assertThat("received byte array is the same as transferred byte array", Arrays.equals(transferBytes, receivedBytes.array()), is(true));
-        assertThat("onReply has been called to close the stream", streamClosedLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("stream is closed", stream.isClosed(), is(true));
-        assertThat("all data has been received", allDataReceived.await(20, TimeUnit.SECONDS), is(true));
-        assertThatNoExceptionOccurred(exceptionCountDownLatch);
-    }
-
-    private byte[] createHugeByteArray(int sizeInBytes)
-    {
-        byte[] bytes = new byte[sizeInBytes];
-        ThreadLocalRandom.current().nextBytes(bytes);
-        return bytes;
-    }
-
-
-    @Test
-    public void testClientResetsStreamAfterPushSynDoesPreventSendingDataFramesWithFlowControl() throws Exception
-    {
-        final boolean flowControl = true;
-        testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(flowControl);
-    }
-
-    @Test
-    public void testClientResetsStreamAfterPushSynDoesPreventSendingDataFramesWithoutFlowControl() throws Exception
-    {
-        final boolean flowControl = false;
-        testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(flowControl);
-    }
-
-    private volatile boolean read = true;
-
-    private void testNoMoreFramesAreSentOnPushStreamAfterClientResetsThePushStream(final boolean flowControl) throws Exception
-    {
-        final short version = SPDY.V3;
-        final AtomicBoolean unexpectedExceptionOccurred = new AtomicBoolean(false);
-        final CountDownLatch resetReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch allDataFramesReceivedLatch = new CountDownLatch(1);
-        final CountDownLatch goAwayReceivedLatch = new CountDownLatch(1);
-        final int dataSizeInBytes = 1024 * 256;
-        final byte[] transferBytes = createHugeByteArray(dataSizeInBytes);
-
-        InetSocketAddress serverAddress = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
-            {
-                new Thread(new Runnable()
-                {
-
-                    @Override
-                    public void run()
-                    {
-                        Stream pushStream = null;
-                        try
-                        {
-                            stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                            pushStream = stream.push(new PushInfo(new Fields(), false));
-                            resetReceivedLatch.await(5, TimeUnit.SECONDS);
-                        }
-                        catch (InterruptedException | ExecutionException | TimeoutException e)
-                        {
-                            e.printStackTrace();
-                            unexpectedExceptionOccurred.set(true);
-                        }
-                        assert pushStream != null;
-                        try
-                        {
-                            pushStream.data(new BytesDataInfo(transferBytes, true));
-                            stream.data(new StringDataInfo("close", true));
-                        }
-                        catch (InterruptedException | ExecutionException | TimeoutException e)
-                        {
-                            LOG.debug(e.getMessage());
-                        }
-                    }
-                }).start();
-                return null;
-            }
-
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                resetReceivedLatch.countDown();
-            }
-
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayInfo)
-            {
-                goAwayReceivedLatch.countDown();
-            }
-        }/*TODO, flowControl*/);
-
-        final SocketChannel channel = SocketChannel.open(serverAddress);
-        final Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-        int streamId = 1;
-        ByteBuffer writeBuffer = generator.control(new SynStreamFrame(version, (byte)0, streamId, 0, (byte)0, (short)0, new Fields()));
-        channel.write(writeBuffer);
-        assertThat("writeBuffer is fully written", writeBuffer.hasRemaining(), is(false));
-
-        final Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
-        parser.addListener(new Listener.Adapter()
-        {
-            int bytesRead = 0;
-
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                if (frame instanceof SynStreamFrame)
-                {
-                    int pushStreamId = ((SynStreamFrame)frame).getStreamId();
-                    ByteBuffer writeBuffer = generator.control(new RstStreamFrame(version, pushStreamId, StreamStatus.CANCEL_STREAM.getCode(version)));
-                    try
-                    {
-                        channel.write(writeBuffer);
-                    }
-                    catch (IOException e)
-                    {
-                        e.printStackTrace();
-                        unexpectedExceptionOccurred.set(true);
-                    }
-                }
-            }
-
-            @Override
-            public void onDataFrame(DataFrame frame, ByteBuffer data)
-            {
-                if (frame.getStreamId() == 2)
-                    bytesRead = bytesRead + frame.getLength();
-                if (bytesRead == dataSizeInBytes)
-                {
-                    allDataFramesReceivedLatch.countDown();
-                    return;
-                }
-                if (flowControl)
-                {
-                    ByteBuffer writeBuffer = generator.control(new WindowUpdateFrame(version, frame.getStreamId(), frame.getLength()));
-                    try
-                    {
-                        channel.write(writeBuffer);
-                    }
-                    catch (IOException e)
-                    {
-                        e.printStackTrace();
-                        unexpectedExceptionOccurred.set(true);
-                    }
-                }
-            }
-        });
-
-        Thread reader = new Thread(new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                ByteBuffer readBuffer = ByteBuffer.allocate(dataSizeInBytes * 2);
-                while (read)
-                {
-                    try
-                    {
-                        channel.read(readBuffer);
-                    }
-                    catch (IOException e)
-                    {
-                        e.printStackTrace();
-                        unexpectedExceptionOccurred.set(true);
-                    }
-                    readBuffer.flip();
-                    parser.parse(readBuffer);
-                    readBuffer.clear();
-                }
-
-            }
-        });
-        reader.start();
-        read = false;
-
-        assertThat("no unexpected exceptions occurred", unexpectedExceptionOccurred.get(), is(false));
-        assertThat("not all dataframes have been received as the pushstream has been reset by the client.", allDataFramesReceivedLatch.await(streamId, TimeUnit.SECONDS), is(false));
-
-
-        ByteBuffer buffer = generator.control(new GoAwayFrame(version, streamId, SessionStatus.OK.getCode()));
-        channel.write(buffer);
-        Assert.assertThat(buffer.hasRemaining(), is(false));
-
-        assertThat("GoAway frame is received by server", goAwayReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
-        channel.shutdownOutput();
-        channel.close();
-    }
-
-    @Test
-    public void testOddEvenStreamIds() throws Exception
-    {
-        final CountDownLatch pushStreamIdIsEvenLatch = new CountDownLatch(3);
-
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.push(new PushInfo(new Fields(), false), new Promise.Adapter<Stream>());
-                return null;
-            }
-        }), null);
-
-        Stream stream = clientSession.syn(new SynInfo(new Fields(), false),
-                new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch));
-        Stream stream2 = clientSession.syn(new SynInfo(new Fields(), false),
-                new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch));
-        Stream stream3 = clientSession.syn(new SynInfo(new Fields(), false),
-                new VerifyPushStreamIdIsEvenStreamFrameListener(pushStreamIdIsEvenLatch));
-        assertStreamIdIsOdd(stream);
-        assertStreamIdIsOdd(stream2);
-        assertStreamIdIsOdd(stream3);
-
-        assertThat("all pushStreams had even ids", pushStreamIdIsEvenLatch.await(5, TimeUnit.SECONDS), is(true));
-    }
-
-    private class VerifyPushStreamIdIsEvenStreamFrameListener extends StreamFrameListener.Adapter
-    {
-        final CountDownLatch pushStreamIdIsEvenLatch;
-
-        private VerifyPushStreamIdIsEvenStreamFrameListener(CountDownLatch pushStreamIdIsEvenLatch)
-        {
-            this.pushStreamIdIsEvenLatch = pushStreamIdIsEvenLatch;
-        }
-
-        @Override
-        public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
-        {
-            assertStreamIdIsEven(stream);
-            pushStreamIdIsEvenLatch.countDown();
-            return super.onPush(stream, pushInfo);
-        }
-    }
-
-    private void assertStreamIdIsEven(Stream stream)
-    {
-        assertThat("streamId is odd", stream.getId() % 2, is(0));
-    }
-
-    private void assertStreamIdIsOdd(Stream stream)
-    {
-        assertThat("streamId is odd", stream.getId() % 2, is(1));
-    }
-
-    private void assertThatNoExceptionOccurred(final CountDownLatch exceptionCountDownLatch) throws InterruptedException
-    {
-        assertThat("No exception occurred", exceptionCountDownLatch.await(1, TimeUnit.SECONDS), is(false));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java
deleted file mode 100644
index c28657c..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/ResetStreamTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.RstInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.FutureCallback;
-import org.junit.Test;
-
-public class ResetStreamTest extends AbstractTest
-{
-    @Test
-    public void testResetStreamIsRemoved() throws Exception
-    {
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()/*TODO, true*/), null);
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        session.rst(new RstInfo(5, TimeUnit.SECONDS, stream.getId(), StreamStatus.CANCEL_STREAM));
-
-        assertEquals("session expected to contain 0 streams", 0, session.getStreams().size());
-    }
-
-    @Test
-    public void testRefusedStreamIsRemoved() throws Exception
-    {
-        final AtomicReference<Session> serverSessionRef = new AtomicReference<>();
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        final CountDownLatch rstLatch = new CountDownLatch(1);
-        Session clientSession = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Session serverSession = stream.getSession();
-                serverSessionRef.set(serverSession);
-                serverSession.rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
-                synLatch.countDown();
-                return null;
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                rstLatch.countDown();
-            }
-        });
-
-        Stream stream = clientSession.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-
-        assertTrue("syncLatch didn't count down", synLatch.await(5, TimeUnit.SECONDS));
-        Session serverSession = serverSessionRef.get();
-        assertEquals("serverSession expected to contain 0 streams", 0, serverSession.getStreams().size());
-
-        assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS));
-        // Need to sleep a while to give the chance to the implementation to remove the stream
-        TimeUnit.SECONDS.sleep(1);
-        assertTrue("stream is expected to be reset", stream.isReset());
-        assertEquals("clientSession expected to contain 0 streams", 0, clientSession.getStreams().size());
-    }
-
-    @Test
-    public void testRefusedStreamIgnoresData() throws Exception
-    {
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        final CountDownLatch rstLatch = new CountDownLatch(1);
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                try
-                {
-                    // Refuse the stream, we must ignore data frames
-                    assertTrue(synLatch.await(5, TimeUnit.SECONDS));
-                    stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
-                    return new StreamFrameListener.Adapter()
-                    {
-                        @Override
-                        public void onData(Stream stream, DataInfo dataInfo)
-                        {
-                            dataLatch.countDown();
-                        }
-                    };
-                }
-                catch (InterruptedException x)
-                {
-                    x.printStackTrace();
-                    return null;
-                }
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                rstLatch.countDown();
-            }
-        });
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", true), new Callback.Adapter()
-        {
-            @Override
-            public void succeeded()
-            {
-                synLatch.countDown();
-            }
-        });
-
-        assertTrue("rstLatch didn't count down", rstLatch.await(5, TimeUnit.SECONDS));
-        assertTrue("stream is expected to be reset", stream.isReset());
-        assertFalse("dataLatch shouldn't be count down", dataLatch.await(1, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testResetAfterServerReceivedFirstDataFrameAndSecondDataFrameFails() throws Exception
-    {
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        final CountDownLatch rstLatch = new CountDownLatch(1);
-        final CountDownLatch failLatch = new CountDownLatch(1);
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                synLatch.countDown();
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        dataLatch.countDown();
-                        stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new FutureCallback());
-                    }
-                };
-            }
-        }), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onRst(Session session, RstInfo rstInfo)
-            {
-                rstLatch.countDown();
-            }
-        });
-
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0), null);
-        assertThat("push is received by server", synLatch.await(5, TimeUnit.SECONDS), is(true));
-        stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data", false), new Callback.Adapter());
-        assertThat("stream is reset", rstLatch.await(5, TimeUnit.SECONDS), is(true));
-        stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "2nd dataframe", false), new Callback.Adapter()
-        {
-            @Override
-            public void failed(Throwable x)
-            {
-                failLatch.countDown();
-            }
-        });
-
-        assertThat("2nd data call failed", failLatch.await(5, TimeUnit.SECONDS), is(true));
-        assertThat("stream is reset", stream.isReset(), is(true));
-    }
-
-    // TODO: If server already received 2nd dataframe after it rst, it should ignore it. Not easy to do.
-
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java
deleted file mode 100644
index 91f197b..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYClientFactoryTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SPDYClientFactoryTest extends AbstractTest
-{
-    @Test
-    public void testStoppingClientFactorySendsGoAway() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo)
-            {
-                latch.countDown();
-            }
-        }), null);
-
-        // Sleep a while to avoid the factory is
-        // stopped before a session can be opened
-        TimeUnit.SECONDS.sleep(1);
-
-        clientFactory.stop();
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(clientFactory.getSessions().isEmpty());
-    }
-
-    @Test
-    public void testSessionClosedIsRemovedFromClientFactory() throws Exception
-    {
-        Session session = startClient(startServer(null), null);
-
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        for (int i=0;i<10;i++)
-        {
-            // Sleep a while to allow the factory to remove the session
-            // since it is done asynchronously by the selector thread
-            TimeUnit.SECONDS.sleep(1);
-            if (clientFactory.getSessions().isEmpty())
-                return;
-        }
-
-        Assert.fail(clientFactory.getSessions().toString());
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java
deleted file mode 100644
index 46c664c..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SPDYServerConnectorTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.spdy.api.GoAwayInfo;
-import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SPDYServerConnectorTest extends AbstractTest
-{
-    @Test
-    public void testStoppingServerConnectorSendsGoAway() throws Exception
-    {
-        final CountDownLatch latch = new CountDownLatch(1);
-        startClient(startServer(null), new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onGoAway(Session session, GoAwayResultInfo goAwayResultInfo)
-            {
-                latch.countDown();
-            }
-        });
-
-        // Sleep a while to avoid the connector is
-        // stopped before a session can be opened
-        TimeUnit.SECONDS.sleep(1);
-
-        connector.stop();
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(connector.getConnectionFactory(SPDYServerConnectionFactory.class).getSessions().isEmpty());
-    }
-
-    @Test
-    public void testSessionClosedIsRemovedFromServerConnector() throws Exception
-    {
-        Session session = startClient(startServer(null), null);
-
-        session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
-
-        // Sleep a while to allow the connector to remove the session
-        // since it is done asynchronously by the selector thread
-        TimeUnit.SECONDS.sleep(1);
-
-        Assert.assertTrue(connector.getConnectionFactory(SPDYServerConnectionFactory.class).getSessions().isEmpty());
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java
deleted file mode 100644
index 5a13bb9..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SettingsTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Settings;
-import org.eclipse.jetty.spdy.api.SettingsInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.FutureCallback;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SettingsTest extends AbstractTest
-{
-    @Test
-    public void testSettingsUsage() throws Exception
-    {
-        Settings settings = new Settings();
-        int streamsValue = 100;
-        settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, Settings.Flag.PERSIST, streamsValue));
-        int windowValue = 32768;
-        settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowValue));
-        int newCode = 91;
-        Settings.ID newID = Settings.ID.from(newCode);
-        int newValue = 97;
-        settings.put(new Settings.Setting(newID, newValue));
-
-        Settings.Setting setting1 = settings.get(Settings.ID.MAX_CONCURRENT_STREAMS);
-        Assert.assertSame(Settings.ID.MAX_CONCURRENT_STREAMS, setting1.id());
-        Assert.assertSame(Settings.Flag.PERSIST, setting1.flag());
-        Assert.assertEquals(streamsValue, setting1.value());
-
-        Settings.Setting setting2 = settings.get(Settings.ID.INITIAL_WINDOW_SIZE);
-        Assert.assertSame(Settings.ID.INITIAL_WINDOW_SIZE, setting2.id());
-        Assert.assertSame(Settings.Flag.NONE, setting2.flag());
-        Assert.assertEquals(windowValue, setting2.value());
-
-        int size = settings.size();
-        Settings.Setting setting3 = settings.remove(Settings.ID.from(newCode));
-        Assert.assertEquals(size - 1, settings.size());
-        Assert.assertNotNull(setting3);
-        Assert.assertSame(newID, setting3.id());
-        Assert.assertEquals(newValue, setting3.value());
-    }
-
-    @Test
-    public void testSettings() throws Exception
-    {
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.UPLOAD_BANDWIDTH, 1024 * 1024));
-        settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_BANDWIDTH, 1024 * 1024));
-        settings.put(new Settings.Setting(Settings.ID.CURRENT_CONGESTION_WINDOW, Settings.Flag.PERSISTED, 1024));
-        final SettingsInfo clientSettingsInfo = new SettingsInfo(settings);
-        final CountDownLatch latch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo serverSettingsInfo)
-            {
-                Assert.assertEquals(clientSettingsInfo.getFlags(), serverSettingsInfo.getFlags());
-                Assert.assertEquals(clientSettingsInfo.getSettings(), serverSettingsInfo.getSettings());
-                latch.countDown();
-            }
-        };
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        session.settings(clientSettingsInfo);
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testServerSettings() throws Exception
-    {
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.UPLOAD_BANDWIDTH, 1024 * 1024));
-        settings.put(new Settings.Setting(Settings.ID.DOWNLOAD_BANDWIDTH, 1024 * 1024));
-        settings.put(new Settings.Setting(Settings.ID.CURRENT_CONGESTION_WINDOW, Settings.Flag.PERSIST, 1024));
-        final SettingsInfo serverSettingsInfo = new SettingsInfo(settings);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                session.settings(serverSettingsInfo, new FutureCallback());
-            }
-        };
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public void onSettings(Session session, SettingsInfo clientSettingsInfo)
-            {
-                Assert.assertEquals(serverSettingsInfo.getFlags(), clientSettingsInfo.getFlags());
-                Assert.assertEquals(serverSettingsInfo.getSettings(), clientSettingsInfo.getSettings());
-                latch.countDown();
-            }
-        };
-
-        startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
-
-        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSettingIDIsTheSameInBothV2AndV3() throws Exception
-    {
-        final AtomicReference<SettingsInfo> v2 = new AtomicReference<>();
-        final AtomicReference<SettingsInfo> v3 = new AtomicReference<>();
-        final CountDownLatch settingsLatch = new CountDownLatch(2);
-        InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            private final AtomicInteger count = new AtomicInteger();
-
-            @Override
-            public void onSettings(Session session, SettingsInfo settingsInfo)
-            {
-                int count = this.count.incrementAndGet();
-                if (count == 1)
-                    v2.set(settingsInfo);
-                else if (count == 2)
-                    v3.set(settingsInfo);
-                else
-                    Assert.fail();
-                settingsLatch.countDown();
-            }
-        });
-
-        Settings settings = new Settings();
-        settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, Settings.Flag.PERSIST, 0xC0_00));
-        SettingsInfo settingsInfo = new SettingsInfo(settings);
-
-        Session sessionV2 = startClient(address, null);
-        sessionV2.settings(settingsInfo);
-
-        Session sessionV3 = clientFactory.newSPDYClient(SPDY.V3).connect(address, null);
-        sessionV3.settings(settingsInfo);
-
-        Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertEquals(v2.get().getSettings(), v3.get().getSettings());
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java
deleted file mode 100644
index 6dfdb5b..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynDataReplyDataLoadTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-
-package org.eclipse.jetty.spdy.server;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.client.SPDYClient;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.eclipse.jetty.util.thread.Scheduler;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-public class SynDataReplyDataLoadTest extends AbstractTest
-{
-    private static final int TIMEOUT = 60 * 1000;
-    private static final Logger logger = Log.getLogger(SynDataReplyDataLoadTest.class);
-
-    @Test(timeout = TIMEOUT)
-    @Ignore("Test needs to be rewritten")
-    public void testSynDataReplyDataLoad() throws Exception
-    {
-        LeakTrackingByteBufferPool serverBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged());
-        LeakTrackingByteBufferPool clientBufferPool = new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged());
-
-        ServerSessionFrameListener listener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                stream.reply(new ReplyInfo(synInfo.getHeaders(), false), new Callback.Adapter());
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        ByteBuffer buffer = dataInfo.asByteBuffer(true);
-                        stream.data(new ByteBufferDataInfo(buffer, dataInfo.isClose()), new Callback.Adapter());
-                    }
-                };
-            }
-        };
-
-        short spdyVersion = SPDY.V2;
-        long idleTimeout = 2 * TIMEOUT;
-
-        server = newServer();
-        connector = new ServerConnector(server, null, null, serverBufferPool, 1,
-                Math.max(1, Runtime.getRuntime().availableProcessors() / 2),
-                new SPDYServerConnectionFactory(spdyVersion, listener));
-        connector.setIdleTimeout(idleTimeout);
-
-        QueuedThreadPool clientExecutor = new QueuedThreadPool();
-        clientExecutor.setName(clientExecutor.getName() + "-client");
-        clientFactory = new SPDYClient.Factory(clientExecutor, null, clientBufferPool, null, idleTimeout);
-        final Session session = startClient(spdyVersion, startServer(spdyVersion, listener), null);
-
-        final Thread testThread = Thread.currentThread();
-        Runnable timeout = new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                logger.warn("Interrupting test, it is taking too long");
-                logger.warn("SERVER: {}", server.dump());
-                logger.warn("CLIENT: {}", clientFactory.dump());
-                testThread.interrupt();
-            }
-        };
-
-        final int iterations = 500;
-        final int count = 50;
-
-        final Fields headers = new Fields();
-        headers.put("method", "get");
-        headers.put("url", "/");
-        headers.put("version", "http/1.1");
-        headers.put("host", "localhost:8080");
-        headers.put("content-type", "application/octet-stream");
-
-        final CountDownLatch latch = new CountDownLatch(count * iterations);
-        session.addListener(new Session.StreamListener.Adapter()
-        {
-            @Override
-            public void onStreamClosed(Stream stream)
-            {
-                latch.countDown();
-            }
-        });
-
-        ExecutorService threadPool = Executors.newFixedThreadPool(count);
-        List<Callable<Object>> tasks = new ArrayList<>();
-
-        tasks.clear();
-        for (int i = 0; i < count; ++i)
-        {
-            tasks.add(new Callable<Object>()
-            {
-                @Override
-                public Object call() throws Exception
-                {
-                    synGetDataGet(session, headers, iterations);
-                    return null;
-                }
-            });
-        }
-        Scheduler.Task syncTimeoutTask = clientFactory.getScheduler().schedule(timeout, TIMEOUT / 2, TimeUnit.MILLISECONDS);
-        {
-            long begin = System.nanoTime();
-            List<Future<Object>> futures = threadPool.invokeAll(tasks);
-            for (Future<Object> future : futures)
-                future.get(iterations, TimeUnit.SECONDS);
-            Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
-            long end = System.nanoTime();
-            System.err.printf("SYN+GET+DATA+GET completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
-        }
-        syncTimeoutTask.cancel();
-
-        tasks.clear();
-        for (int i = 0; i < count; ++i)
-        {
-            tasks.add(new Callable<Object>()
-            {
-                @Override
-                public Object call() throws Exception
-                {
-                    synCompletedData(session, headers, iterations);
-                    return null;
-                }
-            });
-        }
-        Scheduler.Task asyncTimeoutTask = clientFactory.getScheduler().schedule(timeout, TIMEOUT / 2, TimeUnit.MILLISECONDS);
-        {
-            long begin = System.nanoTime();
-            List<Future<Object>> futures = threadPool.invokeAll(tasks);
-            for (Future<Object> future : futures)
-                future.get(iterations, TimeUnit.SECONDS);
-            Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
-            long end = System.nanoTime();
-            System.err.printf("SYN+COMPLETED+DATA completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
-        }
-        asyncTimeoutTask.cancel();
-
-        threadPool.shutdown();
-
-        System.gc();
-
-        assertThat("Server BufferPool - leaked acquires", serverBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Server BufferPool - leaked releases", serverBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Server BufferPool - unreleased", serverBufferPool.getLeakedResources(), is(0L));
-        
-        assertThat("Client BufferPool - leaked acquires", clientBufferPool.getLeakedAcquires(), is(0L));
-        assertThat("Client BufferPool - leaked releases", clientBufferPool.getLeakedReleases(), is(0L));
-        assertThat("Client BufferPool - unreleased", clientBufferPool.getLeakedResources(), is(0L));
-    }
-
-    private void synCompletedData(Session session, Fields headers, int iterations) throws Exception
-    {
-        final Map<Integer, Integer> counter = new ConcurrentHashMap<>(iterations);
-        final CountDownLatch requestsLatch = new CountDownLatch(2 * iterations);
-        for (int i = 0; i < iterations; ++i)
-        {
-            final AtomicInteger count = new AtomicInteger(2);
-            final int index = i;
-            counter.put(index, index);
-            session.syn(new SynInfo(headers, false), new StreamFrameListener.Adapter()
-                    {
-                        @Override
-                        public void onReply(Stream stream, ReplyInfo replyInfo)
-                        {
-                            Assert.assertEquals(2, count.getAndDecrement());
-                            requestsLatch.countDown();
-                        }
-
-                        @Override
-                        public void onData(Stream stream, DataInfo dataInfo)
-                        {
-                            // TCP can split the data frames, so I may be receiving more than 1 data frame
-                            dataInfo.asBytes(true);
-                            if (dataInfo.isClose())
-                            {
-                                Assert.assertEquals(1, count.getAndDecrement());
-                                counter.remove(index);
-                                requestsLatch.countDown();
-                            }
-                        }
-                    }, new Promise.Adapter<Stream>()
-                    {
-                        @Override
-                        public void succeeded(Stream stream)
-                        {
-                            stream.data(new StringDataInfo("data_" + stream.getId(), true),
-                                    new Callback.Adapter());
-                        }
-                    }
-            );
-        }
-        Assert.assertTrue(requestsLatch.await(iterations, TimeUnit.SECONDS));
-        Assert.assertTrue(counter.toString(), counter.isEmpty());
-    }
-
-    private void synGetDataGet(Session session, Fields headers, int iterations) throws Exception
-    {
-        final Map<Integer, Integer> counter = new ConcurrentHashMap<>(iterations);
-        final CountDownLatch latch = new CountDownLatch(2 * iterations);
-        for (int i = 0; i < iterations; ++i)
-        {
-            final AtomicInteger count = new AtomicInteger(2);
-            final int index = i;
-            counter.put(index, index);
-            Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0),
-                    new StreamFrameListener.Adapter()
-                    {
-                        @Override
-                        public void onReply(Stream stream, ReplyInfo replyInfo)
-                        {
-                            Assert.assertEquals(2, count.getAndDecrement());
-                            latch.countDown();
-                        }
-
-                        @Override
-                        public void onData(Stream stream, DataInfo dataInfo)
-                        {
-                            // TCP can split the data frames, so I may be receiving more than 1 data frame
-                            dataInfo.asBytes(true);
-                            if (dataInfo.isClose())
-                            {
-                                Assert.assertEquals(1, count.getAndDecrement());
-                                counter.remove(index);
-                                latch.countDown();
-                            }
-                        }
-                    });
-            stream.data(new StringDataInfo(5, TimeUnit.SECONDS, "data_" + stream.getId(), true));
-        }
-        Assert.assertTrue(latch.await(iterations, TimeUnit.SECONDS));
-        Assert.assertTrue(counter.toString(), counter.isEmpty());
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java
deleted file mode 100644
index 29c2b50..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SynReplyTest.java
+++ /dev/null
@@ -1,375 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.eclipse.jetty.spdy.api.BytesDataInfo;
-import org.eclipse.jetty.spdy.api.DataInfo;
-import org.eclipse.jetty.spdy.api.ReplyInfo;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.SessionFrameListener;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StringDataInfo;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.Promise;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SynReplyTest extends AbstractTest
-{
-    @Test
-    public void testSynReply() throws Exception
-    {
-        final AtomicReference<Session> sessionRef = new AtomicReference<>();
-        final CountDownLatch sessionLatch = new CountDownLatch(1);
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                sessionRef.set(session);
-                sessionLatch.countDown();
-            }
-
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(stream.isHalfClosed());
-                stream.reply(new ReplyInfo(new Fields(), true), new Callback.Adapter());
-                synLatch.countDown();
-                return null;
-            }
-        };
-
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        Assert.assertTrue(sessionLatch.await(5, TimeUnit.SECONDS));
-        Session serverSession = sessionRef.get();
-        Assert.assertNotNull(serverSession);
-
-        final CountDownLatch streamCreatedLatch = new CountDownLatch(1);
-        final CountDownLatch streamRemovedLatch = new CountDownLatch(1);
-        session.addListener(new Session.StreamListener()
-        {
-            @Override
-            public void onStreamCreated(Stream stream)
-            {
-                streamCreatedLatch.countDown();
-            }
-
-            @Override
-            public void onStreamClosed(Stream stream)
-            {
-                streamRemovedLatch.countDown();
-            }
-        });
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), true, (byte)0),
-                new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertTrue(stream.isClosed());
-                replyLatch.countDown();
-            }
-        });
-
-        Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
-
-        Assert.assertTrue(streamCreatedLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(stream.isClosed());
-
-        Assert.assertTrue(streamRemovedLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertEquals(0, session.getStreams().size());
-    }
-
-    @Test
-    public void testSynDataReply() throws Exception
-    {
-        final byte[] dataBytes = "foo".getBytes(StandardCharsets.UTF_8);
-
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertFalse(stream.isHalfClosed());
-                Assert.assertFalse(stream.isClosed());
-                synLatch.countDown();
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-                        ByteBuffer buffer = ByteBuffer.allocate(2);
-                        while (dataInfo.available() > 0)
-                        {
-                            dataInfo.readInto(buffer);
-                            buffer.flip();
-                            bytes.write(buffer.array(), buffer.arrayOffset(), buffer.remaining());
-                            buffer.clear();
-                        }
-                        Assert.assertTrue(Arrays.equals(dataBytes, bytes.toByteArray()));
-                        Assert.assertTrue(stream.isHalfClosed());
-                        Assert.assertFalse(stream.isClosed());
-
-                        stream.reply(new ReplyInfo(true), new Callback.Adapter());
-                        Assert.assertTrue(stream.isClosed());
-                        dataLatch.countDown();
-                    }
-                };
-            }
-        };
-
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        final CountDownLatch streamRemovedLatch = new CountDownLatch(1);
-        session.addListener(new Session.StreamListener.Adapter()
-        {
-            @Override
-            public void onStreamClosed(Stream stream)
-            {
-                streamRemovedLatch.countDown();
-            }
-        });
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, new Fields(), false, (byte)0),
-                new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                replyLatch.countDown();
-            }
-        });
-        stream.data(new BytesDataInfo(dataBytes, true));
-
-        Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
-
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-
-        Assert.assertTrue(streamRemovedLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertEquals(0, session.getStreams().size());
-    }
-
-    @Test
-    public void testSynReplyDataData() throws Exception
-    {
-        final String data1 = "foo";
-        final String data2 = "bar";
-        Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(final Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(stream.isHalfClosed());
-
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(new StringDataInfo(5, TimeUnit.SECONDS, data1, false), new Callback.Adapter()
-                {
-                    @Override
-                    public void succeeded()
-                    {
-                        stream.data(new StringDataInfo(data2, true), new Adapter());
-                    }
-                });
-
-                return null;
-            }
-        }), null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch dataLatch1 = new CountDownLatch(1);
-        final CountDownLatch dataLatch2 = new CountDownLatch(1);
-        session.syn(new SynInfo(new Fields(), true), new StreamFrameListener.Adapter()
-        {
-            private AtomicInteger dataCount = new AtomicInteger();
-
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                int dataCount = this.dataCount.incrementAndGet();
-                if (dataCount == 1)
-                {
-                    String chunk1 = dataInfo.asString(StandardCharsets.UTF_8, true);
-                    Assert.assertEquals(data1, chunk1);
-                    dataLatch1.countDown();
-                }
-                else if (dataCount == 2)
-                {
-                    String chunk2 = dataInfo.asString(StandardCharsets.UTF_8, true);
-                    Assert.assertEquals(data2, chunk2);
-                    dataLatch2.countDown();
-                }
-            }
-        });
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch1.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch2.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testServerSynDataReplyData() throws Exception
-    {
-        final String serverData = "server";
-        final String clientData = "client";
-
-        final CountDownLatch replyLatch = new CountDownLatch(1);
-        final CountDownLatch clientDataLatch = new CountDownLatch(1);
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public void onConnect(Session session)
-            {
-                session.syn(new SynInfo(new Fields(), false), new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onReply(Stream stream, ReplyInfo replyInfo)
-                    {
-                        replyLatch.countDown();
-                    }
-
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        String data = dataInfo.asString(StandardCharsets.UTF_8, true);
-                        Assert.assertEquals(clientData, data);
-                        clientDataLatch.countDown();
-                    }
-                }, new Promise.Adapter<Stream>()
-                {
-                    @Override
-                    public void succeeded(Stream stream)
-                    {
-                        stream.data(new StringDataInfo(serverData, true), new Callback.Adapter());
-                    }
-                });
-            }
-        };
-
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        final CountDownLatch serverDataLatch = new CountDownLatch(1);
-        SessionFrameListener clientSessionFrameListener = new SessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertEquals(0, stream.getId() % 2);
-
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(new StringDataInfo(clientData, true), new Callback.Adapter());
-                synLatch.countDown();
-
-                return new StreamFrameListener.Adapter()
-                {
-                    @Override
-                    public void onData(Stream stream, DataInfo dataInfo)
-                    {
-                        ByteBuffer buffer = dataInfo.asByteBuffer(false);
-                        String data = StandardCharsets.UTF_8.decode(buffer).toString();
-                        Assert.assertEquals(serverData, data);
-                        serverDataLatch.countDown();
-                    }
-                };
-            }
-        };
-
-        startClient(startServer(serverSessionFrameListener), clientSessionFrameListener);
-
-        Assert.assertTrue(synLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(clientDataLatch.await(5, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testSynReplyDataSynReplyData() throws Exception
-    {
-        final String data = "foo";
-        ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                Assert.assertTrue(stream.isHalfClosed());
-
-                stream.reply(new ReplyInfo(false), new Callback.Adapter());
-                stream.data(new StringDataInfo(data, true), new Callback.Adapter());
-
-                return null;
-            }
-        };
-
-        Session session = startClient(startServer(serverSessionFrameListener), null);
-
-        final CountDownLatch replyLatch = new CountDownLatch(2);
-        final CountDownLatch dataLatch = new CountDownLatch(2);
-        StreamFrameListener clientStreamFrameListener = new StreamFrameListener.Adapter()
-        {
-            @Override
-            public void onReply(Stream stream, ReplyInfo replyInfo)
-            {
-                Assert.assertFalse(replyInfo.isClose());
-                replyLatch.countDown();
-            }
-
-            @Override
-            public void onData(Stream stream, DataInfo dataInfo)
-            {
-                String chunk = dataInfo.asString(StandardCharsets.UTF_8, true);
-                Assert.assertEquals(data, chunk);
-                dataLatch.countDown();
-            }
-        };
-        session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener);
-        session.syn(new SynInfo(new Fields(), true), clientStreamFrameListener);
-
-        Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS));
-        Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java
deleted file mode 100644
index 5d92bee..0000000
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/UnsupportedVersionTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.spdy.server;
-
-import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
-import java.nio.channels.SocketChannel;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.spdy.StandardCompressionFactory;
-import org.eclipse.jetty.spdy.api.SPDY;
-import org.eclipse.jetty.spdy.api.Session;
-import org.eclipse.jetty.spdy.api.Stream;
-import org.eclipse.jetty.spdy.api.StreamFrameListener;
-import org.eclipse.jetty.spdy.api.StreamStatus;
-import org.eclipse.jetty.spdy.api.SynInfo;
-import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
-import org.eclipse.jetty.spdy.frames.ControlFrame;
-import org.eclipse.jetty.spdy.frames.ControlFrameType;
-import org.eclipse.jetty.spdy.frames.RstStreamFrame;
-import org.eclipse.jetty.spdy.frames.SynStreamFrame;
-import org.eclipse.jetty.spdy.generator.Generator;
-import org.eclipse.jetty.spdy.parser.Parser;
-import org.eclipse.jetty.util.Fields;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class UnsupportedVersionTest extends AbstractTest
-{
-    @Test
-    public void testSynWithUnsupportedVersion() throws Exception
-    {
-        final CountDownLatch synLatch = new CountDownLatch(1);
-        InetSocketAddress address = startServer(new ServerSessionFrameListener.Adapter()
-        {
-            @Override
-            public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
-            {
-                synLatch.countDown();
-                return null;
-            }
-
-            @Override
-            public void onFailure(Session session, Throwable x)
-            {
-                // Suppress exception logging for this test
-            }
-        });
-
-        SynStreamFrame frame = new SynStreamFrame(SPDY.V2, SynInfo.FLAG_CLOSE, 1, 0, (byte)0, (short)0, new Fields());
-        Generator generator = new Generator(new MappedByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
-        ByteBuffer buffer = generator.control(frame);
-        // Replace the version byte with an unsupported version
-        buffer.putShort(0, (short)0x8001);
-
-        SocketChannel channel = SocketChannel.open(address);
-        channel.write(buffer);
-        Assert.assertFalse(buffer.hasRemaining());
-
-        Assert.assertFalse(synLatch.await(1, TimeUnit.SECONDS));
-
-        buffer = ByteBuffer.allocate(1024);
-        channel.read(buffer);
-        buffer.flip();
-
-        final CountDownLatch rstLatch = new CountDownLatch(1);
-        Parser parser = new Parser(new StandardCompressionFactory.StandardDecompressor());
-        parser.addListener(new Parser.Listener.Adapter()
-        {
-            @Override
-            public void onControlFrame(ControlFrame frame)
-            {
-                Assert.assertSame(ControlFrameType.RST_STREAM, frame.getType());
-                Assert.assertEquals(StreamStatus.UNSUPPORTED_VERSION.getCode(frame.getVersion()), ((RstStreamFrame)frame).getStatusCode());
-                rstLatch.countDown();
-            }
-        });
-        parser.parse(buffer);
-
-        Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS));
-    }
-}
diff --git a/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties
deleted file mode 100644
index ead13ec..0000000
--- a/jetty-spdy/spdy-server/src/test/resources/jetty-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-#org.eclipse.jetty.spdy.LEVEL=DEBUG
diff --git a/jetty-spring/pom.xml b/jetty-spring/pom.xml
index 07d3d48..e87cef9 100644
--- a/jetty-spring/pom.xml
+++ b/jetty-spring/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-spring</artifactId>
@@ -11,28 +11,12 @@
   <properties>
     <spring-version>3.2.8.RELEASE</spring-version>
     <dependencies>target/dependencies</dependencies>
+    <bundle-symbolic-name>${project.groupId}.spring</bundle-symbolic-name>
   </properties>
 
   <build>
     <defaultGoal>install</defaultGoal>
     <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
   <dependencies>
diff --git a/jetty-spring/src/main/config/modules/spring.mod b/jetty-spring/src/main/config/modules/spring.mod
index 444afb2..39b9b8d 100644
--- a/jetty-spring/src/main/config/modules/spring.mod
+++ b/jetty-spring/src/main/config/modules/spring.mod
@@ -1,6 +1,7 @@
 #
 # Spring
 #
+
 [name]
 spring
 
diff --git a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java
index 925b0a3..378d04e 100644
--- a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java
+++ b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessor.java
@@ -36,28 +36,27 @@
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
-import org.springframework.beans.factory.xml.XmlBeanFactory;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.UrlResource;
 
 /**
  * Spring ConfigurationProcessor
- * <p/>
+ * <p>
  * A {@link ConfigurationProcessor} that uses a spring XML file to emulate the {@link XmlConfiguration} format.
- * <p/>
+ * <p>
  * {@link XmlConfiguration} expects a primary object that is either passed in to a call to {@link #configure(Object)}
  * or that is constructed by a call to {@link #configure()}. This processor looks for a bean definition
  * with an id, name or alias of "Main" as uses that as the primary bean.
- * <p/>
+ * <p>
  * The objects mapped by {@link XmlConfiguration#getIdMap()} are set as singletons before any configuration calls
  * and if the spring configuration file contains a definition for the singleton id, the the singleton is updated
- * with a call to {@link XmlBeanFactory#configureBean(Object, String)}.
- * <p/>
+ * with a call to {@link DefaultListableBeanFactory#configureBean(Object, String)}.
+ * <p>
  * The property map obtained via {@link XmlConfiguration#getProperties()} is set as a singleton called "properties"
  * and values can be accessed by somewhat verbose
  * usage of {@link org.springframework.beans.factory.config.MethodInvokingFactoryBean}.
- * <p/>
+ * <p>
  * This processor is returned by the {@link SpringConfigurationProcessorFactory} for any XML document whos first
  * element is "beans". The factory is discovered by a {@link ServiceLoader} for {@link ConfigurationProcessorFactory}.
  */
diff --git a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessorFactory.java b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessorFactory.java
index 5cbb8d9..29bd7e2 100644
--- a/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessorFactory.java
+++ b/jetty-spring/src/main/java/org/eclipse/jetty/spring/SpringConfigurationProcessorFactory.java
@@ -24,7 +24,7 @@
 
 /**
  * Spring ConfigurationProcessor Factory
- * <p/>
+ * <p>
  * Create a {@link SpringConfigurationProcessor} for XML documents with a "beans" element.
  * The factory is discovered by a {@link java.util.ServiceLoader} for {@link ConfigurationProcessorFactory}.
  *
diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml
index 17dc1ed..a0a687d 100644
--- a/jetty-start/pom.xml
+++ b/jetty-start/pom.xml
@@ -2,13 +2,17 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-start</artifactId>
   <name>Jetty :: Start</name>
   <description>The start utility</description>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.start</bundle-symbolic-name>
+    <start-jar-file-name>start.jar</start-jar-file-name>
+  </properties>
   <build>
    <plugins>
       <plugin>
@@ -30,9 +34,6 @@
       </plugin>
     </plugins>
   </build>
-  <properties>
-    <start-jar-file-name>start.jar</start-jar-file-name>
-  </properties>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty.toolchain</groupId>
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java
new file mode 100644
index 0000000..843d6f1
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java
@@ -0,0 +1,399 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.start.builders.StartDirBuilder;
+import org.eclipse.jetty.start.builders.StartIniBuilder;
+import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer;
+import org.eclipse.jetty.start.fileinits.TestFileInitializer;
+import org.eclipse.jetty.start.fileinits.UriFileInitializer;
+import org.eclipse.jetty.start.graph.CriteriaSetPredicate;
+import org.eclipse.jetty.start.graph.UniqueCriteriaPredicate;
+import org.eclipse.jetty.start.graph.Predicate;
+import org.eclipse.jetty.start.graph.Selection;
+
+/**
+ * Build a start configuration in <code>${jetty.base}</code>, including
+ * ini files, directories, and libs. Also handles License management.
+ */
+public class BaseBuilder
+{
+    public static interface Config
+    {
+        /**
+         * Add a module to the start environment in <code>${jetty.base}</code>
+         *
+         * @param module
+         *            the module to add
+         * @return true if module was added, false if module was not added
+         *         (because that module already exists)
+         * @throws IOException if unable to add the module
+         */
+        public boolean addModule(Module module) throws IOException;
+    }
+
+    private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!";
+
+    private final BaseHome baseHome;
+    private final List<FileInitializer> fileInitializers;
+    private final StartArgs startArgs;
+
+    public BaseBuilder(BaseHome baseHome, StartArgs args)
+    {
+        this.baseHome = baseHome;
+        this.startArgs = args;
+        this.fileInitializers = new ArrayList<>();
+
+        // Establish FileInitializers
+        if (args.isTestingModeEnabled())
+        {
+            // No downloads performed
+            fileInitializers.add(new TestFileInitializer());
+        }
+        else if (args.isDownload())
+        {
+            // Downloads are allowed to be performed
+            // Setup Maven Local Repo
+            Path localRepoDir = args.getMavenLocalRepoDir();
+            if (localRepoDir != null)
+            {
+                // Use provided local repo directory
+                fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome,localRepoDir));
+            }
+            else
+            {
+                // No no local repo directory (direct downloads)
+                fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome));
+            }
+
+            // Normal URL downloads
+            fileInitializers.add(new UriFileInitializer(baseHome));
+        }
+    }
+
+    private void ackLicenses() throws IOException
+    {
+        if (startArgs.isLicenseCheckRequired())
+        {
+            if (startArgs.isApproveAllLicenses())
+            {
+                StartLog.info("All Licenses Approved via Command Line Option");
+            }
+            else
+            {
+                Licensing licensing = new Licensing();
+                for (Module module : startArgs.getAllModules().getSelected())
+                {
+                    if (!module.hasFiles(baseHome,startArgs.getProperties()))
+                    {
+                        licensing.addModule(module);
+                    }
+                }
+
+                if (licensing.hasLicenses())
+                {
+                    StartLog.debug("Requesting License Acknowledgement");
+                    if (!licensing.acknowledgeLicenses())
+                    {
+                        StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
+                        System.exit(1);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Build out the Base directory (if needed)
+     * 
+     * @return true if base directory was changed, false if left unchanged.
+     * @throws IOException if unable to build
+     */
+    public boolean build() throws IOException
+    {
+        Modules modules = startArgs.getAllModules();
+        boolean dirty = false;
+
+        String dirCriteria = "<add-to-startd>";
+        String iniCriteria = "<add-to-start-ini>";
+        Selection startDirSelection = new Selection(dirCriteria);
+        Selection startIniSelection = new Selection(iniCriteria);
+        
+        List<String> startDNames = new ArrayList<>();
+        startDNames.addAll(startArgs.getAddToStartdIni());
+        List<String> startIniNames = new ArrayList<>();
+        startIniNames.addAll(startArgs.getAddToStartIni());
+
+        int count = 0;
+        count += modules.selectNodes(startDNames,startDirSelection);
+        count += modules.selectNodes(startIniNames,startIniSelection);
+
+        // look for ambiguous declaration found in both places
+        Predicate ambiguousPredicate = new CriteriaSetPredicate(dirCriteria,iniCriteria);
+        List<Module> ambiguous = modules.getMatching(ambiguousPredicate);
+
+        if (ambiguous.size() > 0)
+        {
+            StringBuilder warn = new StringBuilder();
+            warn.append("Ambiguous module locations detected, defaulting to --add-to-start for the following module selections:");
+            warn.append(" [");
+            
+            for (int i = 0; i < ambiguous.size(); i++)
+            {
+                if (i > 0)
+                {
+                    warn.append(", ");
+                }
+                warn.append(ambiguous.get(i).getName());
+            }
+            warn.append(']');
+            StartLog.warn(warn.toString());
+        }
+
+        StartLog.debug("Adding %s new module(s)",count);
+        
+        // Acknowledge Licenses
+        ackLicenses();
+
+        // Collect specific modules to enable
+        // Should match 'criteria', with no other selections.explicit
+        Predicate startDMatcher = new UniqueCriteriaPredicate(dirCriteria);
+        Predicate startIniMatcher = new UniqueCriteriaPredicate(iniCriteria);
+
+        List<Module> startDModules = modules.getMatching(startDMatcher);
+        List<Module> startIniModules = modules.getMatching(startIniMatcher);
+
+        List<FileArg> files = new ArrayList<FileArg>();
+
+        if (!startDModules.isEmpty())
+        {
+            StartDirBuilder builder = new StartDirBuilder(this);
+            for (Module mod : startDModules)
+            {
+                if (ambiguous.contains(mod))
+                {
+                    // skip ambiguous module
+                    continue;
+                }
+                
+                if (mod.isSkipFilesValidation())
+                {
+                    StartLog.debug("Skipping [files] validation on %s",mod.getName());
+                } 
+                else 
+                {
+                    dirty |= builder.addModule(mod);
+                    for (String file : mod.getFiles())
+                    {
+                        files.add(new FileArg(mod,startArgs.getProperties().expand(file)));
+                    }
+                }
+            }
+        }
+
+        if (!startIniModules.isEmpty())
+        {
+            StartIniBuilder builder = new StartIniBuilder(this);
+            for (Module mod : startIniModules)
+            {
+                if (mod.isSkipFilesValidation())
+                {
+                    StartLog.debug("Skipping [files] validation on %s",mod.getName());
+                } 
+                else 
+                {
+                    dirty |= builder.addModule(mod);
+                    for (String file : mod.getFiles())
+                    {
+                        files.add(new FileArg(mod,startArgs.getProperties().expand(file)));
+                    }
+                }
+            }
+        }
+        
+        // Process files
+        files.addAll(startArgs.getFiles());
+        dirty |= processFileResources(files);
+
+        return dirty;
+    }
+
+    public BaseHome getBaseHome()
+    {
+        return baseHome;
+    }
+
+    public StartArgs getStartArgs()
+    {
+        return startArgs;
+    }
+
+    /**
+     * Process a specific file resource
+     * 
+     * @param arg
+     *            the fileArg to work with
+     * @param file
+     *            the resolved file reference to work with
+     * @return true if change was made as a result of the file, false if no change made.
+     * @throws IOException
+     *             if there was an issue in processing this file
+     */
+    private boolean processFileResource(FileArg arg, Path file) throws IOException
+    {
+        if (startArgs.isDownload() && (arg.uri != null))
+        {
+            // now on copy/download paths (be safe above all else)
+            if (!file.startsWith(baseHome.getBasePath()))
+            {
+                throw new IOException("For security reasons, Jetty start is unable to process maven file resource not in ${jetty.base} - " + file);
+            }
+            
+            // make the directories in ${jetty.base} that we need
+            FS.ensureDirectoryExists(file.getParent());
+            
+            URI uri = URI.create(arg.uri);
+
+            // Process via initializers
+            for (FileInitializer finit : fileInitializers)
+            {
+                if (finit.init(uri,file,arg.location))
+                {
+                    // Completed successfully
+                    return true;
+                }
+            }
+
+            return false;
+        }
+        else
+        {
+            // Process directly
+            boolean isDir = arg.location.endsWith("/");
+
+            if (FS.exists(file))
+            {
+                // Validate existence
+                if (isDir)
+                {
+                    if (!Files.isDirectory(file))
+                    {
+                        throw new IOException("Invalid: path should be a directory (but isn't): " + file);
+                    }
+                    if (!FS.canReadDirectory(file))
+                    {
+                        throw new IOException("Unable to read directory: " + file);
+                    }
+                }
+                else
+                {
+                    if (!FS.canReadFile(file))
+                    {
+                        throw new IOException("Unable to read file: " + file);
+                    }
+                }
+
+                return false;
+            }
+
+            if (isDir)
+            {
+                // Create directory
+                StartLog.log("MKDIR",baseHome.toShortForm(file));
+                return FS.ensureDirectoryExists(file);
+            }
+            else
+            {
+                // Warn on missing file (this has to be resolved manually by user)
+                String shortRef = baseHome.toShortForm(file);
+                if (startArgs.isTestingModeEnabled())
+                {
+                    StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
+                    return true;
+                }
+
+                StartLog.warn("Missing Required File: %s",baseHome.toShortForm(file));
+                startArgs.setRun(false);
+                if (arg.uri != null)
+                {
+                    StartLog.warn("  Can be downloaded From: %s",arg.uri);
+                    StartLog.warn("  Run start.jar --create-files to download");
+                }
+
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Process the {@link FileArg} for startup, assume that all licenses have
+     * been acknowledged at this stage.
+     *
+     * @param files
+     *            the list of {@link FileArg}s to process
+     * @return true if base directory modified, false if left untouched
+     */
+    private boolean processFileResources(List<FileArg> files) throws IOException
+    {
+        if ((files == null) || (files.isEmpty()))
+        {
+            return false;
+        }
+
+        boolean dirty = false;
+
+        List<String> failures = new ArrayList<String>();
+
+        for (FileArg arg : files)
+        {
+            Path file = baseHome.getBasePath(arg.location);
+            try
+            {
+                dirty |= processFileResource(arg,file);
+            }
+            catch (Throwable t)
+            {
+                StartLog.warn(t);
+                failures.add(String.format("[%s] %s - %s",t.getClass().getSimpleName(),t.getMessage(),file.toAbsolutePath().toString()));
+            }
+        }
+
+        if (!failures.isEmpty())
+        {
+            StringBuilder err = new StringBuilder();
+            err.append("Failed to process all file resources.");
+            for (String failure : failures)
+            {
+                err.append(System.lineSeparator()).append(" - ").append(failure);
+            }
+            StartLog.warn(err.toString());
+
+            throw new RuntimeException(err.toString());
+        }
+
+        return dirty;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
index eb88d43..bab5e89 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseHome.java
@@ -130,7 +130,6 @@
 
     public BaseHome(CommandLineConfigSource cmdLineSource) throws IOException
     {
-
         sources = new ConfigSources();
         sources.add(cmdLineSource);
         this.homeDir = cmdLineSource.getHomePath();
@@ -201,7 +200,7 @@
      */
     public Path getBasePath(String path)
     {
-        return baseDir.resolve(path);
+        return baseDir.resolve(path).normalize().toAbsolutePath();
     }
 
     public ConfigSources getConfigSources()
@@ -324,20 +323,19 @@
      * <dt><code>lib/**&#47;*-dev.jar</code></dt>
      * <dd>Relative pattern, recursive search <code>${jetty.home}</code> then <code>${jetty.base}</code> for files under <code>lib</code> ending in
      * <code>-dev.jar</code></dd>
-     * </dl>
      * 
      * <dt><code>etc/jetty.xml</code></dt>
      * <dd>Relative pattern, no glob, search for <code>${jetty.home}/etc/jetty.xml</code> then <code>${jetty.base}/etc/jetty.xml</code></dd>
      * 
      * <dt><code>glob:/opt/app/common/*-corp.jar</code></dt>
-     * <dd>PathMapper pattern, glob, search <code>/opt/app/common/</code> for <code>*-corp.jar</code></code></dd>
+     * <dd>PathMapper pattern, glob, search <code>/opt/app/common/</code> for <code>*-corp.jar</code></dd>
      * 
      * </dl>
      * 
      * <p>
      * Notes:
      * <ul>
-     * <li>FileSystem case sensitivity is implementation specific (eg: linux is case-sensitive, windows is case-insensitive).<br/>
+     * <li>FileSystem case sensitivity is implementation specific (eg: linux is case-sensitive, windows is case-insensitive).<br>
      * See {@link java.nio.file.FileSystem#getPathMatcher(String)} for more details</li>
      * <li>Pattern slashes are implementation neutral (use '/' always and you'll be fine)</li>
      * <li>Recursive searching is limited to 30 levels deep (not configurable)</li>
@@ -415,6 +413,8 @@
 
     /**
      * Convenience method for <code>toShortForm(file.toPath())</code>
+     * @param path the path to shorten
+     * @return the short form of the path as a String
      */
     public String toShortForm(final File path)
     {
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Classpath.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Classpath.java
index dc860b9..c95489a 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Classpath.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Classpath.java
@@ -36,6 +36,11 @@
 {
     private static class Loader extends URLClassLoader
     {
+        static
+        {
+            registerAsParallelCapable();
+        }
+
         Loader(URL[] urls, ClassLoader parent)
         {
             super(urls,parent);
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/CommandLineBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/CommandLineBuilder.java
index 7b6ea65..2d34c43 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/CommandLineBuilder.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/CommandLineBuilder.java
@@ -62,8 +62,8 @@
      * Perform an optional quoting of the argument, being intelligent with spaces and quotes as needed. If a subString is set in quotes it won't the subString
      * won't be escaped.
      * 
-     * @param arg
-     * @return
+     * @param arg the argument to quote
+     * @return the quoted and escaped argument
      */
     public static String quote(String arg)
     {
@@ -126,7 +126,6 @@
     /**
      * Similar to {@link #addArg(String)} but concats both name + value with an "=" sign, quoting were needed, and excluding the "=" portion if the value is
      * undefined or empty.
-     * <p>
      * 
      * <pre>
      *   addEqualsArg("-Dname", "value") = "-Dname=value"
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java b/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
index d715c848..10d993e 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/FS.java
@@ -67,14 +67,15 @@
         return Files.exists(ret);
     }
 
-    public static void ensureDirectoryExists(Path dir) throws IOException
+    public static boolean ensureDirectoryExists(Path dir) throws IOException
     {
         if (exists(dir))
         {
             // exists already, nothing to do
-            return;
+            return false;
         }
         Files.createDirectories(dir);
+        return true;
     }
 
     public static void ensureDirectoryWritable(Path dir) throws IOException
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/FileInitializer.java b/jetty-start/src/main/java/org/eclipse/jetty/start/FileInitializer.java
new file mode 100644
index 0000000..715b132
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/FileInitializer.java
@@ -0,0 +1,46 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Path;
+
+/**
+ * Interface for initializing a file resource.
+ */
+public interface FileInitializer
+{
+    /**
+     * Initialize a file resource
+     * 
+     * @param uri
+     *            the remote URI of the resource acting as its source
+     * @param file
+     *            the local file resource to initialize. (often in ${jetty.base} directory) 
+     * @param fileRef
+     *            the simple string reference to the output file, suitable for searching
+     *            for the file in other locations (like ${jetty.home} or ${jetty.dir})
+     * @return true if local file is initialized (resulted in a change on disk), false if this
+     *         {@link FileInitializer} did nothing.
+     * @throws IOException
+     *             if there was an attempt to initialize, but an error occurred.
+     */
+    public boolean init(URI uri, Path file, String fileRef) throws IOException;
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Licensing.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Licensing.java
new file mode 100644
index 0000000..055951f
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Licensing.java
@@ -0,0 +1,104 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Handles basic license presentation and acknowledgement.
+ */
+public class Licensing
+{
+    private static final String PROP_ACK_LICENSES = "org.eclipse.jetty.start.ack.licenses";
+    public Map<String, List<String>> licenseMap = new TreeMap<>(new NaturalSort.Strings());
+
+    public void addModule(Module module)
+    {
+        if (!module.hasLicense())
+        {
+            // skip, no license
+            return;
+        }
+        
+        if (licenseMap.containsKey(module.getName()))
+        {
+            // skip, already being tracked
+            return;
+        }
+
+        licenseMap.put(module.getName(),module.getLicense());
+    }
+
+    public boolean hasLicenses()
+    {
+        return !licenseMap.isEmpty();
+    }
+
+    public boolean acknowledgeLicenses() throws IOException
+    {
+        if (!hasLicenses())
+        {
+            return true;
+        }
+        
+        System.err.printf("%nALERT: There are enabled module(s) with licenses.%n");
+        System.err.printf("The following %d module(s):%n", licenseMap.size());
+        System.err.printf(" + contains software not provided by the Eclipse Foundation!%n");
+        System.err.printf(" + contains software not covered by the Eclipse Public License!%n");
+        System.err.printf(" + has not been audited for compliance with its license%n");
+
+        for (String key : licenseMap.keySet())
+        {
+            System.err.printf("%n Module: %s%n",key);
+            for (String line : licenseMap.get(key))
+            {
+                System.err.printf("  + %s%n",line);
+            }
+        }
+
+        boolean licenseAck = false;
+
+        String propBasedAckValue = System.getProperty(PROP_ACK_LICENSES);
+        if (propBasedAckValue != null)
+        {
+            StartLog.log("TESTING MODE","Programmatic ACK - %s=%s",PROP_ACK_LICENSES,propBasedAckValue);
+            licenseAck = Boolean.parseBoolean(propBasedAckValue);
+        }
+        else
+        {
+            if (Boolean.getBoolean("org.eclipse.jetty.start.testing"))
+            {
+                throw new RuntimeException("Test Configuration Missing - Pre-specify answer to (" + PROP_ACK_LICENSES + ") in test case");
+            }
+
+            BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
+            System.err.printf("%nProceed (y/N)? ");
+            String response = input.readLine();
+
+            licenseAck = (Utils.isNotBlank(response) && response.toLowerCase().startsWith("y"));
+        }
+
+        return licenseAck;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
index e4cfcf5..6358b40 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java
@@ -18,38 +18,31 @@
 
 package org.eclipse.jetty.start;
 
-import static org.eclipse.jetty.start.UsageException.*;
+import static org.eclipse.jetty.start.UsageException.ERR_BAD_GRAPH;
+import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN;
+import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED;
+import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN;
 
 import java.io.BufferedReader;
-import java.io.BufferedWriter;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.ConnectException;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Set;
-import java.util.regex.Pattern;
 
 import org.eclipse.jetty.start.config.CommandLineConfigSource;
+import org.eclipse.jetty.start.graph.GraphException;
+import org.eclipse.jetty.start.graph.Selection;
 
 /**
  * Main start class.
@@ -57,52 +50,22 @@
  * This class is intended to be the main class listed in the MANIFEST.MF of the start.jar archive. It allows the Jetty Application server to be started with the
  * command "java -jar start.jar".
  * <p>
- * Argument processing steps:
+ * <b>Argument processing steps:</b>
  * <ol>
- * <li>Directory Locations:
- * <ul>
- * <li>jetty.home=[directory] (the jetty.home location)</li>
- * <li>jetty.base=[directory] (the jetty.base location)</li>
- * </ul>
- * </li>
- * <li>Start Logging behavior:
- * <ul>
- * <li>--debug (debugging enabled)</li>
- * <li>--start-log-file=logs/start.log (output start logs to logs/start.log location)</li>
- * </ul>
- * </li>
+ * <li>Directory Location: jetty.home=[directory] (the jetty.home location)</li>
+ * <li>Directory Location: jetty.base=[directory] (the jetty.base location)</li>
+ * <li>Start Logging behavior: --debug (debugging enabled)</li>
+ * <li>Start Logging behavior: --start-log-file=logs/start.log (output start logs to logs/start.log location)</li>
  * <li>Module Resolution</li>
  * <li>Properties Resolution</li>
  * <li>Present Optional Informational Options</li>
  * <li>Normal Startup</li>
- * </li>
  * </ol>
  */
 public class Main
 {
-    private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!";
     private static final int EXIT_USAGE = 1;
 
-    public static String join(Collection<?> objs, String delim)
-    {
-        if (objs==null)
-        {
-            return "";
-        }
-        StringBuilder str = new StringBuilder();
-        boolean needDelim = false;
-        for (Object obj : objs)
-        {
-            if (needDelim)
-            {
-                str.append(delim);
-            }
-            str.append(obj);
-            needDelim = true;
-        }
-        return str.toString();
-    }
-
     public static void main(String[] args)
     {
         try
@@ -172,76 +135,6 @@
         }).start();
     }
 
-    private void initFile(StartArgs args, FileArg farg)
-    {
-        try
-        {
-            Path file = baseHome.getBasePath(farg.location);
-            
-            StartLog.debug("[init-file] %s module specified file %s",file.toAbsolutePath(),(FS.exists(file)?"[Exists!]":""));
-            if (FS.exists(file))
-            {
-                // file already initialized / downloaded, skip it
-                return;
-            }
-
-            if (farg.uri!=null)
-            {
-                URL url = new URL(farg.uri);
-
-                StartLog.log("DOWNLOAD", "%s to %s", url, farg.location);
-
-                FS.ensureDirectoryExists(file.getParent());
-                
-                if (args.isTestingModeEnabled())
-                {
-                    StartLog.log("TESTING MODE", "Skipping download of " + url);
-                    return;
-                }
-
-                byte[] buf = new byte[8192];
-                try (InputStream in = url.openStream(); 
-                     OutputStream out = Files.newOutputStream(file,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE))
-                {
-                    while (true)
-                    {
-                        int len = in.read(buf);
-
-                        if (len > 0)
-                        {
-                            out.write(buf,0,len);
-                        }
-                        if (len < 0)
-                        {
-                            break;
-                        }
-                    }
-                }
-            }
-            else if (farg.location.endsWith("/"))
-            {
-                StartLog.log("MKDIR",baseHome.toShortForm(file));
-                FS.ensureDirectoryExists(file);
-            }
-            else
-            {
-                String shortRef = baseHome.toShortForm(file);
-                if (args.isTestingModeEnabled())
-                {
-                    StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
-                    return;
-                }
-                StartLog.warn("MISSING: Required file %s",shortRef);
-            }
-        }
-        catch (Exception e)
-        {
-            StartLog.warn("ERROR: processing %s%n%s",farg,e);
-            StartLog.warn(e);
-            usageExit(EXIT_USAGE);
-        }
-    }
-
     private void dumpClasspathWithVersions(Classpath classpath)
     {
         StartLog.endStartLog();
@@ -344,7 +237,7 @@
         args.dumpActiveXmls(baseHome);
     }
 
-    private void listModules(StartArgs args)
+    public void listModules(StartArgs args)
     {
         StartLog.endStartLog();
         System.out.println();
@@ -354,227 +247,17 @@
 
         // Dump Enabled Modules
         System.out.println();
-        System.out.println("Jetty Active Module Tree:");
-        System.out.println("-------------------------");
+        System.out.println("Jetty Selected Module Ordering:");
+        System.out.println("-------------------------------");
         Modules modules = args.getAllModules();
-        modules.dumpEnabledTree();
-    }
-
-    /**
-     * Build out INI file.
-     * <p>
-     * This applies equally for either <code>${jetty.base}/start.ini</code> or
-     * <code>${jetty.base}/start.d/${name}.ini</code> 
-     * 
-     * @param args the arguments of what modules are enabled
-     * @param name the name of the module to based the build of the ini
-     * @param topLevel 
-     * @param appendStartIni true to append to <code>${jetty.base}/start.ini</code>, 
-     * false to create a <code>${jetty.base}/start.d/${name}.ini</code> entry instead.
-     * @throws IOException
-     */
-    private void buildIni(StartArgs args, String name, boolean topLevel, boolean appendStartIni) throws IOException
-    {        
-        // Find the start.d relative to the base directory only.
-        Path start_d = baseHome.getBasePath("start.d");
-
-        // Is this a module?
-        Modules modules = args.getAllModules();
-        Module module = modules.get(name);
-        if (module == null)
-        {
-            StartLog.warn("ERROR: No known module for %s",name);
-            return;
-        }
-        
-        boolean transitive = module.isEnabled() && (module.getSources().size() == 0);
-
-        // Find any named ini file and check it follows the convention
-        Path start_ini = baseHome.getBasePath("start.ini");
-        String short_start_ini = baseHome.toShortForm(start_ini);
-        Path startd_ini = start_d.resolve(name + ".ini");
-        String short_startd_ini = baseHome.toShortForm(startd_ini);
-        StartIni module_ini = null;
-        if (FS.exists(startd_ini))
-        {
-            module_ini = new StartIni(startd_ini);
-            if (module_ini.getLineMatches(Pattern.compile("--module=(.*, *)*" + name)).size() == 0)
-            {
-                StartLog.warn("ERROR: %s is not enabled in %s!",name,short_startd_ini);
-                return;
-            }
-        }
-
-        if (!args.isApproveAllLicenses())
-        {
-            if (!module.hasFiles(baseHome) && !module.acknowledgeLicense())
-            {
-                StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
-                System.exit(1);
-            }
-        }
-        
-        boolean buildIni=false;
-        if (module.isEnabled())
-        {
-            // is it an explicit request to create an ini file?
-            if (topLevel && !FS.exists(startd_ini) && !appendStartIni)
-            {
-                buildIni=true;
-            }
-            // else is it transitive
-            else if (transitive)
-            {
-                if (module.hasDefaultConfig())
-                {
-                    buildIni = true;
-                    StartLog.info("%-15s initialised transitively",name);
-                }
-            }
-            // else must be initialized explicitly
-            else 
-            {
-                for (String source : module.getSources())
-                {
-                    StartLog.info("%-15s initialised in %s",name,baseHome.toShortForm(source));
-                }
-            }
-        }
-        else 
-        {
-            buildIni=true;
-        }
-        
-        String source = "<transitive>";
-
-        // If we need an ini
-        if (buildIni)
-        {
-            // File BufferedWriter
-            BufferedWriter writer = null;
-            PrintWriter out = null;
-            try
-            {
-                if (appendStartIni)
-                {
-                    source = short_start_ini;
-                    StartLog.info("%-15s initialised in %s (appended)",name,source);
-                    writer = Files.newBufferedWriter(start_ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.APPEND);
-                    out = new PrintWriter(writer);
-                }
-                else
-                {
-                    // Create the directory if needed
-                    FS.ensureDirectoryExists(start_d);
-                    FS.ensureDirectoryWritable(start_d);
-                    source = short_startd_ini;
-                    StartLog.info("%-15s initialised in %s (created)",name,source);
-                    writer = Files.newBufferedWriter(startd_ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE);
-                    out = new PrintWriter(writer);
-                }
-
-                if (appendStartIni)
-                {
-                    out.println();
-                }
-                out.println("# --------------------------------------- ");
-                out.println("# Module: " + name);
-
-                out.println("--module=" + name);
-                
-                args.parse("--module=" + name,source);
-                args.parseModule(module);
-                
-                for (String line : module.getDefaultConfig())
-                {
-                    out.println(line);
-                }
-            }
-            finally
-            {
-                if (out != null)
-                {
-                    out.close();
-                }
-            }
-        }
-        
-        modules.enable(name,Collections.singletonList(source));
-        
-        // Also list other places this module is enabled
-        for (String src : module.getSources())
-        {
-            StartLog.debug("also enabled in: %s",src);
-            if (!short_start_ini.equals(src))
-            {
-                StartLog.info("%-15s enabled in     %s",name,baseHome.toShortForm(src));
-            }
-        }
-
-        // Do downloads now
-        for (String file : module.getFiles())
-        {
-            initFile(args, new FileArg(module,file));
-        }
-
-        // Process dependencies
-        module.expandProperties(args.getProperties());
-        modules.registerParentsIfMissing(module);
-        modules.buildGraph();
-        
-        // process new ini modules
-        if (topLevel)
-        {
-            List<Module> depends = new ArrayList<>();
-            for (String depend : modules.resolveParentModulesOf(name))
-            {
-                if (!name.equals(depend))
-                {
-                    Module m = modules.get(depend);
-                    m.setEnabled(true);
-                    depends.add(m);
-                }
-            }
-            Collections.sort(depends,Collections.reverseOrder(new Module.DepthComparator()));
-            
-            Set<String> done = new HashSet<>(0);
-            while (true)
-            {
-                // initialize known dependencies
-                boolean complete=true;
-                for (Module m : depends)
-                {
-                    if (!done.contains(m.getName()))
-                    {
-                        complete=false;
-                        buildIni(args,m.getName(),false,appendStartIni);
-                        done.add(m.getName());
-                    }
-                }
-                
-                if (complete)
-                {
-                    break;
-                }
-                
-                // look for any new ones resolved via expansion
-                depends.clear();
-                for (String depend : modules.resolveParentModulesOf(name))
-                {
-                    if (!name.equals(depend))
-                    {
-                        Module m = modules.get(depend);
-                        m.setEnabled(true);
-                        depends.add(m);
-                    }
-                }
-                Collections.sort(depends,Collections.reverseOrder(new Module.DepthComparator()));
-            }
-        }
+        modules.dumpSelected();
     }
 
     /**
      * Convenience for <code>processCommandLine(cmdLine.toArray(new String[cmdLine.size()]))</code>
+     * @param cmdLine the command line
+     * @return the start args parsed from the command line
+     * @throws Exception if unable to process the command line
      */
     public StartArgs processCommandLine(List<String> cmdLine) throws Exception
     {
@@ -601,30 +284,58 @@
         StartArgs args = new StartArgs();
         args.parse(baseHome.getConfigSources());
 
-        // ------------------------------------------------------------
-        // 3) Module Registration
-        Modules modules = new Modules(baseHome,args);
-        StartLog.debug("Registering all modules");
-        modules.registerAll();
-
-        // ------------------------------------------------------------
-        // 4) Active Module Resolution
-        for (String enabledModule : args.getEnabledModules())
+        try
         {
-            List<String> msources = args.getSources(enabledModule);
-            modules.enable(enabledModule,msources);
-        }
-        
-        StartLog.debug("Building Module Graph");
-        modules.buildGraph();
+            // ------------------------------------------------------------
+            // 3) Module Registration
+            Modules modules = new Modules(baseHome,args);
+            StartLog.debug("Registering all modules");
+            modules.registerAll();
 
-        args.setAllModules(modules);
-        List<Module> activeModules = modules.resolveEnabled();
-        
-        // ------------------------------------------------------------
-        // 5) Lib & XML Expansion / Resolution
-        args.expandLibs(baseHome);
-        args.expandModules(baseHome,activeModules);
+            // ------------------------------------------------------------
+            // 4) Active Module Resolution
+            for (String enabledModule : args.getEnabledModules())
+            {
+                for (String source : args.getSources(enabledModule))
+                {
+                    String shortForm = baseHome.toShortForm(source);
+                    modules.selectNode(enabledModule,new Selection(shortForm));
+                }
+            }
+
+            StartLog.debug("Building Module Graph");
+            modules.buildGraph();
+
+            args.setAllModules(modules);
+            List<Module> activeModules = modules.getSelected();
+            
+            final Version START_VERSION = new Version(StartArgs.VERSION);
+            
+            for(Module enabled: activeModules)
+            {
+                if(enabled.getVersion().isNewerThan(START_VERSION))
+                {
+                    throw new UsageException(UsageException.ERR_BAD_GRAPH, "Module [" + enabled.getName() + "] specifies jetty version [" + enabled.getVersion()
+                            + "] which is newer than this version of jetty [" + START_VERSION + "]");
+                }
+            }
+            
+            for(String name: args.getSkipFileValidationModules())
+            {
+                Module module = modules.get(name);
+                module.setSkipFilesValidation(true);
+            }
+
+            // ------------------------------------------------------------
+            // 5) Lib & XML Expansion / Resolution
+            args.expandLibs(baseHome);
+            args.expandModules(baseHome,activeModules);
+
+        }
+        catch (GraphException e)
+        {
+            throw new UsageException(ERR_BAD_GRAPH,e);
+        }
 
         // ------------------------------------------------------------
         // 6) Resolve Extra XMLs
@@ -636,7 +347,7 @@
 
         return args;
     }
-
+    
     public void start(StartArgs args) throws IOException, InterruptedException
     {
         StartLog.debug("StartArgs: %s",args);
@@ -684,7 +395,7 @@
         if (args.isDryRun())
         {
             CommandLineBuilder cmd = args.getMainArgs(baseHome,true);
-            System.out.println(cmd.toString(File.separatorChar=='/'?" \\\n":" "));
+            System.out.println(cmd.toString(StartLog.isDebugEnabled()?" \\\n":" "));
         }
 
         if (args.isStopCommand())
@@ -692,83 +403,12 @@
             doStop(args);
         }
         
-        boolean rebuildGraph = false;
-
-        // Initialize start.ini
-        for (String module : args.getAddToStartIni())
+        BaseBuilder baseBuilder = new BaseBuilder(baseHome,args);
+        if(baseBuilder.build())
         {
-            buildIni(args,module,true,true);
-            rebuildGraph = true;
-        }
-
-        // Initialize start.d
-        for (String module : args.getAddToStartdIni())
-        {
-            buildIni(args,module,true,false);
-            rebuildGraph = true;
-        }
-        
-        if (rebuildGraph)
-        {
-            args.getAllModules().clearMissing();
-            args.getAllModules().buildGraph();
-        }
-        
-        // If in --create-files, check licenses
-        if(args.isDownload())
-        {
-            if (!args.isApproveAllLicenses())
-            {
-                for (Module module : args.getAllModules().resolveEnabled())
-                {
-                    if (!module.hasFiles(baseHome) && !module.acknowledgeLicense())
-                    {
-                        StartLog.warn(EXITING_LICENSE_NOT_ACKNOWLEDGED);
-                        System.exit(1);
-                    }
-                }
-            }
-        }
-
-        // Check ini files for download possibilities
-        for (FileArg arg : args.getFiles())
-        {
-            Path file = baseHome.getBasePath(arg.location);
-            if (!FS.exists(file) && args.isDownload())
-            {
-                initFile(args, arg);
-            }
-
-            if (!FS.exists(file))
-            {
-                boolean isDir = arg.location.endsWith("/");
-                if (isDir)
-                {
-                    StartLog.log("MKDIR", baseHome.toShortForm(file));
-                    FS.ensureDirectoryExists(file);
-                    /* Startup should not fail to run on missing directories.
-                     * See Bug #427204
-                     */
-                    // args.setRun(false);
-                }
-                else
-                {
-                    String shortRef = baseHome.toShortForm(file);
-                    if (args.isTestingModeEnabled())
-                    {
-                        StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
-                        return;
-                    }
-
-                    StartLog.warn("Missing Required File: %s",baseHome.toShortForm(file));
-                    args.setRun(false);
-                    if (arg.uri != null)
-                    {
-                        StartLog.warn("  Can be downloaded From: %s",arg.uri);
-                        StartLog.warn("  Run start.jar --create-files to download");
-                    }
-                }
-            }
+            // base directory changed.
+            StartLog.info("Base directory was modified");
+            return;
         }
         
         // Informational command line, don't run jetty
@@ -842,6 +482,9 @@
 
     /**
      * Stop a running jetty instance.
+     * @param host the host
+     * @param port the port
+     * @param key the key
      */
     public void stop(String host, int port, String key)
     {
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
index d2243bf..007ecc9 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java
@@ -21,46 +21,26 @@
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.text.CollationKey;
 import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.eclipse.jetty.start.graph.Node;
+
 /**
  * Represents a Module metadata, as defined in Jetty.
  */
-public class Module
+public class Module extends Node<Module>
 {
-    public static class DepthComparator implements Comparator<Module>
-    {
-        private Collator collator = Collator.getInstance();
-
-        @Override
-        public int compare(Module o1, Module o2)
-        {
-            // order by depth first.
-            int diff = o1.depth - o2.depth;
-            if (diff != 0)
-            {
-                return diff;
-            }
-            // then by name (not really needed, but makes for predictable test cases)
-            CollationKey k1 = collator.getCollationKey(o1.fileRef);
-            CollationKey k2 = collator.getCollationKey(o2.fileRef);
-            return k1.compareTo(k2);
-        }
-    }
+    private static final String VERSION_UNSPECIFIED = "9.2";
 
     public static class NameComparator implements Comparator<Module>
     {
@@ -78,84 +58,51 @@
 
     /** The file of the module */
     private Path file;
+    
     /** The name of this Module (as a filesystem reference) */
     private String fileRef;
-    /**
-     * The logical name of this module (for property selected references), And to aid in duplicate detection.
-     */
-    private String logicalName;
-    /** The depth of the module in the tree */
-    private int depth = 0;
-    /** Set of Modules, by name, that this Module depends on */
-    private Set<String> parentNames;
-    /** Set of Modules, by name, that this Module optionally depend on */
-    private Set<String> optionalParentNames;
-    /** The Edges to parent modules */
-    private Set<Module> parentEdges;
-    /** The Edges to child modules */
-    private Set<Module> childEdges;
+    
+    /** The version of Jetty the module supports */
+    private Version version;
+
     /** List of xml configurations for this Module */
     private List<String> xmls;
+    
     /** List of ini template lines */
+    private List<String> iniTemplate;
+    private boolean hasIniTemplate = false;
+    
+    /** List of default config */
     private List<String> defaultConfig;
     private boolean hasDefaultConfig = false;
+    
     /** List of library options for this Module */
     private List<String> libs;
+    
     /** List of files for this Module */
     private List<String> files;
+    /** Skip File Validation (default: false) */
+    private boolean skipFilesValidation = false;
+    
     /** List of jvm Args */
     private List<String> jvmArgs;
+    
     /** License lines */
     private List<String> license;
 
-    /** Is this Module enabled via start.jar command line, start.ini, or start.d/*.ini ? */
-    private boolean enabled = false;
-    /** List of sources that enabled this module */
-    private final Set<String> sources = new HashSet<>();
-    private boolean licenseAck = false;
-
     public Module(BaseHome basehome, Path file) throws FileNotFoundException, IOException
     {
+        super();
         this.file = file;
 
         // Strip .mod
         this.fileRef = Pattern.compile(".mod$",Pattern.CASE_INSENSITIVE).matcher(file.getFileName().toString()).replaceFirst("");
-        this.logicalName = fileRef;
+        this.setName(fileRef);
 
         init(basehome);
         process(basehome);
     }
 
-    public void addChildEdge(Module child)
-    {
-        if (childEdges.contains(child))
-        {
-            // already present, skip
-            return;
-        }
-        this.childEdges.add(child);
-    }
-
-    public void addParentEdge(Module parent)
-    {
-        if (parentEdges.contains(parent))
-        {
-            // already present, skip
-            return;
-        }
-        this.parentEdges.add(parent);
-    }
-
-    public void addSources(List<String> sources)
-    {
-        this.sources.addAll(sources);
-    }
-
-    public void clearSources()
-    {
-        this.sources.clear();
-    }
-
     @Override
     public boolean equals(Object obj)
     {
@@ -189,23 +136,22 @@
     public void expandProperties(Props props)
     {
         // Expand Parents
-        Set<String> parents = new HashSet<>();
-        for (String parent : parentNames)
+        List<String> parents = new ArrayList<>();
+        for (String parent : getParentNames())
         {
             parents.add(props.expand(parent));
         }
-        parentNames.clear();
-        parentNames.addAll(parents);
+        setParentNames(parents);
     }
 
-    public Set<Module> getChildEdges()
+    public List<String> getDefaultConfig()
     {
-        return childEdges;
+        return defaultConfig;
     }
-
-    public int getDepth()
+    
+    public List<String> getIniTemplate()
     {
-        return depth;
+        return iniTemplate;
     }
 
     public List<String> getFiles()
@@ -213,113 +159,50 @@
         return files;
     }
 
+    public boolean isSkipFilesValidation()
+    {
+        return skipFilesValidation;
+    }
+
     public String getFilesystemRef()
     {
         return fileRef;
     }
 
-    public List<String> getDefaultConfig()
-    {
-        return defaultConfig;
-    }
-
-    public boolean hasDefaultConfig()
-    {
-        return hasDefaultConfig;
-    }
-
-    public List<String> getLibs()
-    {
-        return libs;
-    }
-
-    public String getName()
-    {
-        return logicalName;
-    }
-
-    public Set<String> getOptionalParentNames()
-    {
-        return optionalParentNames;
-    }
-
-    public Set<Module> getParentEdges()
-    {
-        return parentEdges;
-    }
-
-    public Set<String> getParentNames()
-    {
-        return parentNames;
-    }
-
-    public Set<String> getSources()
-    {
-        return Collections.unmodifiableSet(sources);
-    }
-
-    public List<String> getXmls()
-    {
-        return xmls;
-    }
-
     public List<String> getJvmArgs()
     {
         return jvmArgs;
     }
 
-    public boolean hasLicense()
+    public List<String> getLibs()
     {
-        return license != null && license.size() > 0;
-    }
-
-    public boolean acknowledgeLicense() throws IOException
-    {
-        if (!hasLicense() || licenseAck)
-        {
-            return true;
-        }
-        
-        System.err.printf("%nModule %s:%n",getName());
-        System.err.printf(" + contains software not provided by the Eclipse Foundation!%n");
-        System.err.printf(" + contains software not covered by the Eclipse Public License!%n");
-        System.err.printf(" + has not been audited for compliance with its license%n");
-        System.err.printf("%n");
-        for (String l : getLicense())
-        {
-            System.err.printf("    %s%n",l);
-        }
-
-        String propBasedAckName = "org.eclipse.jetty.start.ack.license." + getName();
-        String propBasedAckValue = System.getProperty(propBasedAckName);
-        if (propBasedAckValue != null)
-        {
-            StartLog.log("TESTING MODE", "Programmatic ACK - %s=%s",propBasedAckName,propBasedAckValue);
-            licenseAck = Boolean.parseBoolean(propBasedAckValue);
-        }
-        else
-        {
-            if (Boolean.getBoolean("org.eclipse.jetty.start.testing"))
-            {
-                throw new RuntimeException("Test Configuration Missing - Pre-specify answer to (" + propBasedAckName + ") in test case");
-            }
-
-            try (BufferedReader input = new BufferedReader(new InputStreamReader(System.in)))
-            {
-                System.err.printf("%nProceed (y/N)? ");
-                String line = input.readLine();
-
-                licenseAck = !(line == null || line.length() == 0 || !line.toLowerCase().startsWith("y"));
-            }
-        }
-
-        return licenseAck;
+        return libs;
     }
 
     public List<String> getLicense()
     {
         return license;
     }
+    
+    public List<String> getXmls()
+    {
+        return xmls;
+    }
+    
+    public Version getVersion()
+    {
+        return version;
+    }
+
+    public boolean hasDefaultConfig()
+    {
+        return hasDefaultConfig;
+    }
+    
+    public boolean hasIniTemplate()
+    {
+        return hasIniTemplate;
+    }
 
     @Override
     public int hashCode()
@@ -330,14 +213,16 @@
         return result;
     }
 
+    public boolean hasLicense()
+    {
+        return (license != null) && (license.size() > 0);
+    }
+
     private void init(BaseHome basehome)
     {
-        parentNames = new HashSet<>();
-        optionalParentNames = new HashSet<>();
-        parentEdges = new HashSet<>();
-        childEdges = new HashSet<>();
         xmls = new ArrayList<>();
         defaultConfig = new ArrayList<>();
+        iniTemplate = new ArrayList<>();
         libs = new ArrayList<>();
         files = new ArrayList<>();
         jvmArgs = new ArrayList<>();
@@ -353,19 +238,24 @@
             throw new RuntimeException("Invalid Module location (must be located under /modules/ directory): " + name);
         }
         this.fileRef = mat.group(1).replace('\\','/');
-        this.logicalName = this.fileRef;
+        setName(this.fileRef);
     }
 
-    public boolean isEnabled()
+    /**
+     * Indicates a module that is dynamic in nature
+     * 
+     * @return a module where the declared metadata name does not match the filename reference (aka a dynamic module)
+     */
+    public boolean isDynamic()
     {
-        return enabled;
+        return !getName().equals(fileRef);
     }
 
-    public boolean hasFiles(BaseHome baseHome)
+    public boolean hasFiles(BaseHome baseHome, Props props)
     {
         for (String ref : getFiles())
         {
-            FileArg farg = new FileArg(this,ref);
+            FileArg farg = new FileArg(this,props.expand(ref));
             Path refPath = baseHome.getBasePath(farg.location);
             if (!Files.exists(refPath))
             {
@@ -404,9 +294,12 @@
                     // blank lines and comments are valid for ini-template section
                     if ((line.length() == 0) || line.startsWith("#"))
                     {
+                        // Remember ini comments and whitespace (empty lines)
+                        // for the [ini-template] section
                         if ("INI-TEMPLATE".equals(sectionType))
                         {
-                            defaultConfig.add(line);
+                            iniTemplate.add(line);
+                            hasIniTemplate = true;
                         }
                     }
                     else
@@ -417,16 +310,20 @@
                                 // ignore (this would be entries before first section)
                                 break;
                             case "DEPEND":
-                                parentNames.add(line);
+                                addParentName(line);
                                 break;
                             case "FILES":
                                 files.add(line);
                                 break;
-                            case "DEFAULTS":
-                            case "INI-TEMPLATE":
+                            case "DEFAULTS": // old name introduced in 9.2.x
+                            case "INI": // new name for 9.3+
                                 defaultConfig.add(line);
                                 hasDefaultConfig = true;
                                 break;
+                            case "INI-TEMPLATE":
+                                iniTemplate.add(line);
+                                hasIniTemplate = true;
+                                break;
                             case "LIB":
                                 libs.add(line);
                                 break;
@@ -435,14 +332,21 @@
                                 license.add(line);
                                 break;
                             case "NAME":
-                                logicalName = line;
+                                setName(line);
                                 break;
                             case "OPTIONAL":
-                                optionalParentNames.add(line);
+                                addOptionalParentName(line);
                                 break;
                             case "EXEC":
                                 jvmArgs.add(line);
                                 break;
+                            case "VERSION":
+                                if (version != null)
+                                {
+                                    throw new IOException("[version] already specified");
+                                }
+                                version = new Version(line);
+                                break;
                             case "XML":
                                 xmls.add(line);
                                 break;
@@ -453,40 +357,35 @@
                 }
             }
         }
-    }
-
-    public void setDepth(int depth)
-    {
-        this.depth = depth;
+        
+        if (version == null)
+        {
+            version = new Version(VERSION_UNSPECIFIED);
+        }
     }
 
     public void setEnabled(boolean enabled)
     {
-        this.enabled = enabled;
+        throw new RuntimeException("Don't enable directly");
     }
-
-    public void setParentNames(Set<String> parents)
+    
+    public void setSkipFilesValidation(boolean skipFilesValidation)
     {
-        this.parentNames.clear();
-        this.parentEdges.clear();
-        if (parents != null)
-        {
-            this.parentNames.addAll(parents);
-        }
+        this.skipFilesValidation = skipFilesValidation;
     }
-
+    
     @Override
     public String toString()
     {
         StringBuilder str = new StringBuilder();
-        str.append("Module[").append(logicalName);
-        if (!logicalName.equals(fileRef))
+        str.append("Module[").append(getName());
+        if (isDynamic())
         {
             str.append(",file=").append(fileRef);
         }
-        if (enabled)
+        if (isSelected())
         {
-            str.append(",enabled");
+            str.append(",selected");
         }
         str.append(']');
         return str.toString();
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
index a787eb9..48f18a2 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/ModuleGraphWriter.java
@@ -28,6 +28,10 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.eclipse.jetty.start.graph.Graph;
+import org.eclipse.jetty.start.graph.Node;
+import org.eclipse.jetty.start.graph.Selection;
+
 /**
  * Generate a graphviz dot graph of the modules found
  */
@@ -103,7 +107,7 @@
             out.println("    ssize = \"20,40\"");
             out.println("  ];");
 
-            List<Module> enabled = modules.resolveEnabled();
+            List<Module> enabled = modules.getSelected();
 
             // Module Nodes
             writeModules(out,modules,enabled);
@@ -164,7 +168,7 @@
     private void writeModuleNode(PrintWriter out, Module module, boolean resolved)
     {
         String color = colorModuleBg;
-        if (module.isEnabled())
+        if (module.isSelected())
         {
             // specifically enabled by config
             color = colorEnabledBg;
@@ -179,12 +183,12 @@
         out.printf("<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"2\">%n");
         out.printf("  <TR><TD ALIGN=\"LEFT\"><B>%s</B></TD></TR>%n",module.getName());
 
-        if (module.isEnabled())
+        if (module.isSelected())
         {
             writeModuleDetailHeader(out,"ENABLED");
-            for (String source : module.getSources())
+            for (Selection selection : module.getSelections())
             {
-                writeModuleDetailLine(out,"via: " + source);
+                writeModuleDetailLine(out,"via: " + selection);
             }
         }
         else if (resolved)
@@ -212,9 +216,9 @@
             }
         }
 
-        if (!module.getDefaultConfig().isEmpty())
+        if (!module.getIniTemplate().isEmpty())
         {
-            List<String> inis = module.getDefaultConfig();
+            List<String> inis = module.getIniTemplate();
             writeModuleDetailHeader(out,"INI Template",inis.size());
         }
 
@@ -247,11 +251,11 @@
         }
     }
 
-    private void writeRelationships(PrintWriter out, Modules modules, List<Module> enabled)
+    private void writeRelationships(PrintWriter out, Graph<Module> modules, List<Module> enabled)
     {
         for (Module module : modules)
         {
-            for (Module parent : module.getParentEdges())
+            for (Node<?> parent : module.getParentEdges())
             {
                 out.printf("    \"%s\" -> \"%s\";%n",module.getName(),parent.getName());
             }
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
index 1a5cf3e..107e4f9 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java
@@ -18,409 +18,133 @@
 
 package org.eclipse.jetty.start;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-import java.util.regex.Pattern;
+
+import org.eclipse.jetty.start.graph.Graph;
+import org.eclipse.jetty.start.graph.GraphException;
+import org.eclipse.jetty.start.graph.OnlyTransitivePredicate;
+import org.eclipse.jetty.start.graph.Selection;
 
 /**
  * Access for all modules declared, as well as what is enabled.
  */
-public class Modules implements Iterable<Module>
+public class Modules extends Graph<Module>
 {
     private final BaseHome baseHome;
     private final StartArgs args;
-    
-    private Map<String, Module> modules = new HashMap<>();
-    /*
-     * modules that may appear in the resolved graph but are undefined in the module system
-     * 
-     * ex: modules/npn/npn-1.7.0_01.mod (property expansion resolves to non-existent file)
-     */
-    private Set<String> missingModules = new HashSet<String>();
 
-    private int maxDepth = -1;
-    
     public Modules(BaseHome basehome, StartArgs args)
     {
         this.baseHome = basehome;
         this.args = args;
-    }
-
-    private Set<String> asNameSet(Set<Module> moduleSet)
-    {
-        Set<String> ret = new HashSet<>();
-        for (Module module : moduleSet)
-        {
-            ret.add(module.getName());
-        }
-        return ret;
-    }
-
-    private void assertNoCycle(Module module, Stack<String> refs)
-    {
-        for (Module parent : module.getParentEdges())
-        {
-            if (refs.contains(parent.getName()))
-            {
-                // Cycle detected.
-                StringBuilder err = new StringBuilder();
-                err.append("A cyclic reference in the modules has been detected: ");
-                for (int i = 0; i < refs.size(); i++)
-                {
-                    if (i > 0)
-                    {
-                        err.append(" -> ");
-                    }
-                    err.append(refs.get(i));
-                }
-                err.append(" -> ").append(parent.getName());
-                throw new IllegalStateException(err.toString());
-            }
-
-            refs.push(parent.getName());
-            assertNoCycle(parent,refs);
-            refs.pop();
-        }
-    }
-
-    private void bfsCalculateDepth(final Module module, final int depthNow)
-    {
-        int depth = depthNow + 1;
-
-        // Set depth on every child first
-        for (Module child : module.getChildEdges())
-        {
-            child.setDepth(Math.max(depth,child.getDepth()));
-            this.maxDepth = Math.max(this.maxDepth,child.getDepth());
-        }
-
-        // Dive down
-        for (Module child : module.getChildEdges())
-        {
-            bfsCalculateDepth(child,depth);
-        }
-    }
-
-    /**
-     * Using the provided dependencies, build the module graph
-     */
-    public void buildGraph() throws FileNotFoundException, IOException
-    {
-        normalizeDependencies();
+        this.setSelectionTerm("enable");
+        this.setNodeTerm("module");
         
-        // Connect edges
-        for (Module module : modules.values())
+        String java_version = System.getProperty("java.version");
+        if (java_version!=null)
         {
-            for (String parentName : module.getParentNames())
-            {
-                Module parent = get(parentName);
-
-                if (parent == null)
-                {
-                    if (Props.hasPropertyKey(parentName))
-                    {
-                        StartLog.debug("Module property not expandable (yet) [%s]",parentName);
-                    }
-                    else
-                    {
-                        StartLog.warn("Module not found [%s]",parentName);
-                    }
-                }
-                else
-                {
-                    module.addParentEdge(parent);
-                    parent.addChildEdge(module);
-                }
-            }
-
-            for (String optionalParentName : module.getOptionalParentNames())
-            {
-                Module optional = get(optionalParentName);
-                if (optional == null)
-                {
-                    StartLog.debug("Optional module not found [%s]",optionalParentName);
-                }
-                else if (optional.isEnabled())
-                {
-                    module.addParentEdge(optional);
-                    optional.addChildEdge(module);
-                }
-            }
-        }
-
-        // Verify there is no cyclic references
-        Stack<String> refs = new Stack<>();
-        for (Module module : modules.values())
-        {
-            refs.push(module.getName());
-            assertNoCycle(module,refs);
-            refs.pop();
-        }
-
-        // Calculate depth of all modules for sorting later
-        for (Module module : modules.values())
-        {
-            if (module.getParentEdges().isEmpty())
-            {
-                bfsCalculateDepth(module,0);
-            }
-        }
-    }
-
-    public void clearMissing()
-    {
-        missingModules.clear();
-    }
-    
-    public Integer count()
-    {
-        return modules.size();
+            args.setProperty("java.version",java_version,"<internal>",false);
+        }        
     }
 
     public void dump()
     {
         List<Module> ordered = new ArrayList<>();
-        ordered.addAll(modules.values());
+        ordered.addAll(getNodes());
         Collections.sort(ordered,new Module.NameComparator());
 
-        List<Module> active = resolveEnabled();
+        List<Module> active = getSelected();
 
         for (Module module : ordered)
         {
             boolean activated = active.contains(module);
-            boolean enabled = module.isEnabled();
-            boolean transitive = activated && !enabled;
+            boolean selected = module.isSelected();
+            boolean transitive = selected && module.matches(OnlyTransitivePredicate.INSTANCE);
 
-            char status = '-';
-            if (enabled)
+            String status = "[ ]";
+            if (transitive)
             {
-                status = '*';
+                status = "[t]";
             }
-            else if (transitive)
+            else if (selected)
             {
-                status = '+';
+                status = "[x]";
             }
 
             System.out.printf("%n %s Module: %s%n",status,module.getName());
             if (!module.getName().equals(module.getFilesystemRef()))
             {
-                System.out.printf("      Ref: %s%n",module.getFilesystemRef());
+                System.out.printf("        Ref: %s%n",module.getFilesystemRef());
             }
             for (String parent : module.getParentNames())
             {
-                System.out.printf("   Depend: %s%n",parent);
+                System.out.printf("     Depend: %s%n",parent);
             }
             for (String lib : module.getLibs())
             {
-                System.out.printf("      LIB: %s%n",lib);
+                System.out.printf("        LIB: %s%n",lib);
             }
             for (String xml : module.getXmls())
             {
-                System.out.printf("      XML: %s%n",xml);
+                System.out.printf("        XML: %s%n",xml);
             }
             if (StartLog.isDebugEnabled())
             {
-                System.out.printf("    depth: %d%n",module.getDepth());
+                System.out.printf("      depth: %d%n",module.getDepth());
             }
             if (activated)
             {
-                for (String source : module.getSources())
+                for (Selection selection : module.getSelections())
                 {
-                    System.out.printf("  Enabled: <via> %s%n",source);
-                }
-                if (transitive)
-                {
-                    System.out.printf("  Enabled: <via transitive reference>%n");
+                    System.out.printf("    Enabled: <via> %s%n",selection);
                 }
             }
             else
             {
-                System.out.printf("  Enabled: <not enabled in this configuration>%n");
+                System.out.printf("    Enabled: <not enabled in this configuration>%n");
             }
         }
     }
 
-    public void dumpEnabledTree()
-    {
-        List<Module> ordered = new ArrayList<>();
-        ordered.addAll(modules.values());
-        Collections.sort(ordered,new Module.DepthComparator());
-
-        List<Module> active = resolveEnabled();
-
-        for (Module module : ordered)
-        {
-            if (active.contains(module))
-            {
-                // Show module name
-                String indent = toIndent(module.getDepth());
-                System.out.printf("%s + Module: %s [%s]%n",indent,module.getName(),module.isEnabled()?"enabled":"transitive");
-            }
-        }
-    }
-
-    public void enable(String name) throws IOException
-    {
-        List<String> empty = Collections.emptyList();
-        enable(name,empty);
-    }
-    
-    public void enable(String name, List<String> sources) throws IOException
-    {
-        if (name.contains("*"))
-        {
-            // A regex!
-            Pattern pat = Pattern.compile(name);
-            List<Module> matching = new ArrayList<>();
-            do
-            {
-                matching.clear();
-                
-                // find matching entries that are not enabled
-                for (Map.Entry<String, Module> entry : modules.entrySet())
-                {
-                    if (pat.matcher(entry.getKey()).matches())
-                    {
-                        if (!entry.getValue().isEnabled())
-                        {
-                            matching.add(entry.getValue());
-                        }
-                    }
-                }
-                
-                // enable them
-                for (Module module : matching)
-                {
-                    enableModule(module,sources);
-                }
-            }
-            while (!matching.isEmpty());
-        }
-        else
-        {
-            Module module = modules.get(name);
-            if (module == null)
-            {
-                System.err.printf("WARNING: Cannot enable requested module [%s]: not a valid module name.%n",name);
-                return;
-            }
-            enableModule(module,sources);
-        }
-    }
-
-    private void enableModule(Module module, List<String> sources) throws IOException
-    {
-        String via = "<transitive>";
-
-        // Always add the sources
-        if (sources != null)
-        {
-            module.addSources(sources);
-            via = Main.join(sources, ", ");
-        }
-        
-        // If already enabled, nothing else to do
-        if (module.isEnabled())
-        {
-            StartLog.debug("Enabled module: %s (via %s)",module.getName(),via);
-            return;
-        }
-        
-        StartLog.debug("Enabling module: %s (via %s)",module.getName(),via);
-        module.setEnabled(true);
-        args.parseModule(module);
-        module.expandProperties(args.getProperties());
-        
-        // enable any parents that haven't been enabled (yet)
-        Set<String> parentNames = new HashSet<>();
-        parentNames.addAll(module.getParentNames());
-        for(String name: parentNames)
-        {
-            StartLog.debug("Enable parent '%s' of module: %s",name,module.getName());
-            Module parent = modules.get(name);
-            if (parent == null)
-            {
-                // parent module doesn't exist, yet
-                Path file = baseHome.getPath("modules/" + name + ".mod");
-                if (FS.canReadFile(file))
-                {
-                    parent = registerModule(file);
-                    parent.expandProperties(args.getProperties());
-                    updateParentReferencesTo(parent);
-                }
-                else
-                {
-                    if (!Props.hasPropertyKey(name))
-                    {
-                        StartLog.debug("Missing module definition: [ Mod: %s | File: %s ]",name,file);
-                        missingModules.add(name);
-                    }
-                }
-            }
-            if (parent != null)
-            {
-                enableModule(parent,null);
-            }
-        }
-    }
-    
-    private void findChildren(Module module, Set<Module> ret)
-    {
-        ret.add(module);
-        for (Module child : module.getChildEdges())
-        {
-            ret.add(child);
-        }
-    }
-
-    private void findParents(Module module, Map<String, Module> ret)
-    {
-        ret.put(module.getName(),module);
-        for (Module parent : module.getParentEdges())
-        {
-            ret.put(parent.getName(),parent);
-            findParents(parent,ret);
-        }
-    }
-
-    public Module get(String name)
-    {
-        return modules.get(name);
-    }
-
-    public int getMaxDepth()
-    {
-        return maxDepth;
-    }
-
-    public Set<Module> getModulesAtDepth(int depth)
-    {
-        Set<Module> ret = new HashSet<>();
-        for (Module module : modules.values())
-        {
-            if (module.getDepth() == depth)
-            {
-                ret.add(module);
-            }
-        }
-        return ret;
-    }
-
     @Override
-    public Iterator<Module> iterator()
+    public Module resolveNode(String name)
     {
-        return modules.values().iterator();
+        String expandedName = args.getProperties().expand(name);
+
+        if (Props.hasPropertyKey(expandedName))
+        {
+            StartLog.debug("Not yet able to expand property in: %s",name);
+            return null;
+        }
+
+        Path file = baseHome.getPath("modules/" + expandedName + ".mod");
+        if (FS.canReadFile(file))
+        {
+            Module parent = registerModule(file);
+            parent.expandProperties(args.getProperties());
+            updateParentReferencesTo(parent);
+            return parent;
+        }
+        else
+        {
+            if (!Props.hasPropertyKey(name))
+            {
+                StartLog.debug("Missing module definition: [ Mod: %s | File: %s ]",name,file);
+            }
+            return null;
+        }
+    }
+    
+    @Override
+    public void onNodeSelected(Module module)
+    {
+        StartLog.debug("on node selected: [%s] (%s.mod)",module.getName(),module.getFilesystemRef());
+        args.parseModule(module);
+        module.expandProperties(args.getProperties());
     }
 
     public List<String> normalizeLibs(List<Module> active)
@@ -455,30 +179,6 @@
         return xmls;
     }
 
-    public Module register(Module module)
-    {
-        modules.put(module.getName(),module);
-        return module;
-    }
-
-    public void registerParentsIfMissing(Module module) throws IOException
-    {
-        Set<String> parents = new HashSet<>(module.getParentNames());
-        for (String name : parents)
-        {
-            if (!modules.containsKey(name))
-            {
-                Path file = baseHome.getPath("modules/" + name + ".mod");
-                if (FS.canReadFile(file))
-                {
-                    Module parent = registerModule(file);
-                    updateParentReferencesTo(parent);
-                    registerParentsIfMissing(parent);
-                }
-            }
-        }
-    }
-    
     public void registerAll() throws IOException
     {
         for (Path path : baseHome.getPaths("modules/*.mod"))
@@ -486,140 +186,29 @@
             registerModule(path);
         }
     }
-    
-    // load missing post-expanded dependent modules
-    private void normalizeDependencies() throws FileNotFoundException, IOException
-    {
-        Set<String> expandedModules = new HashSet<>();
-        boolean done = false;
-        while (!done)
-        {
-            done = true;
-            Set<String> missingParents = new HashSet<>();
 
-            for (Module m : modules.values())
-            {
-                for (String parent : m.getParentNames())
-                {
-                    String expanded = args.getProperties().expand(parent);
-                    if (modules.containsKey(expanded) || missingModules.contains(parent) || expandedModules.contains(parent))
-                    {
-                        continue; // found. skip it.
-                    }
-                    done = false;
-                    StartLog.debug("Missing parent module %s == %s for %s",parent,expanded,m);
-                    missingParents.add(parent);
-                }
-            }
-
-            for (String missingParent : missingParents)
-            {
-                String expanded = args.getProperties().expand(missingParent);
-                Path file = baseHome.getPath("modules/" + expanded + ".mod");
-                if (FS.canReadFile(file))
-                {
-                    Module module = registerModule(file);
-                    updateParentReferencesTo(module);
-                    if (!expanded.equals(missingParent))
-                    {
-                        expandedModules.add(missingParent);
-                    }
-                }
-                else
-                {
-                    if (Props.hasPropertyKey(expanded))
-                    {
-                        StartLog.debug("Module property not expandable (yet) [%s]",expanded);
-                        expandedModules.add(missingParent);
-                    }
-                    else
-                    {
-                        StartLog.debug("Missing module definition: %s expanded to %s",missingParent,expanded);
-                        missingModules.add(missingParent);
-                    }
-                }
-            }
-        }
-    }
-
-    private Module registerModule(Path file) throws FileNotFoundException, IOException
+    private Module registerModule(Path file)
     {
         if (!FS.canReadFile(file))
         {
-            throw new IOException("Cannot read file: " + file);
+            throw new GraphException("Cannot read file: " + file);
         }
-        StartLog.debug("Registering Module: %s",baseHome.toShortForm(file));
-        Module module = new Module(baseHome,file);
-        return register(module);
-    }
-
-    public Set<String> resolveChildModulesOf(String moduleName)
-    {
-        Set<Module> ret = new HashSet<>();
-        Module module = get(moduleName);
-        findChildren(module,ret);
-        return asNameSet(ret);
+        String shortName = baseHome.toShortForm(file);
+        try
+        {
+            StartLog.debug("Registering Module: %s",shortName);
+            Module module = new Module(baseHome,file);
+            return register(module);
+        }
+        catch (Throwable t)
+        {
+            throw new GraphException("Unable to register module: " + shortName,t);
+        }
     }
 
     /**
-     * Resolve the execution order of the enabled modules, and all dependant modules, based on depth first transitive reduction.
-     * 
-     * @return the list of active modules (plus dependant modules), in execution order.
-     */
-    public List<Module> resolveEnabled()
-    {
-        Map<String, Module> active = new HashMap<String, Module>();
-
-        for (Module module : modules.values())
-        {
-            if (module.isEnabled())
-            {
-                findParents(module,active);
-            }
-        }
-
-        /*
-         * check against the missing modules
-         * 
-         * Ex: npn should match anything under npn/
-         */
-        for (String missing : missingModules)
-        {
-            for (String activeModule : active.keySet())
-            {
-                if (missing.startsWith(activeModule))
-                {
-                    StartLog.warn("** Unable to continue, required dependency missing. [%s]",missing);
-                    StartLog.warn("** As configured, Jetty is unable to start due to a missing enabled module dependency.");
-                    StartLog.warn("** This may be due to a transitive dependency akin to spdy on npn, which resolves based on the JDK in use.");
-                    throw new UsageException(UsageException.ERR_BAD_ARG, "Missing referenced dependency: " + missing);
-                }
-            }
-        }
-
-        List<Module> ordered = new ArrayList<>();
-        ordered.addAll(active.values());
-        Collections.sort(ordered,new Module.DepthComparator());
-        return ordered;
-    }
-
-    public Set<String> resolveParentModulesOf(String moduleName)
-    {
-        Map<String, Module> ret = new HashMap<>();
-        Module module = get(moduleName);
-        findParents(module,ret);
-        return ret.keySet();
-    }
-
-    private String toIndent(int depth)
-    {
-        char indent[] = new char[depth * 2];
-        Arrays.fill(indent,' ');
-        return new String(indent);
-    }
-
-    /**
-     * Modules can have a different logical name than to their filesystem reference. This updates existing references to the filesystem form to use the logical
+     * Modules can have a different logical name than to their filesystem reference. This updates existing references to
+     * the filesystem form to use the logical
      * name form.
      * 
      * @param module
@@ -633,9 +222,9 @@
             return;
         }
 
-        for (Module m : modules.values())
+        for (Module m : getNodes())
         {
-            Set<String> resolvedParents = new HashSet<>();
+            List<String> resolvedParents = new ArrayList<>();
             for (String parent : m.getParentNames())
             {
                 if (parent.equals(module.getFilesystemRef()))
@@ -658,10 +247,10 @@
     {
         StringBuilder str = new StringBuilder();
         str.append("Modules[");
-        str.append("count=").append(modules.size());
+        str.append("count=").append(count());
         str.append(",<");
         boolean delim = false;
-        for (String name : modules.keySet())
+        for (String name : getNodeNames())
         {
             if (delim)
             {
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
index c3dc4f4..add7fbf 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Props.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.start;
 
-import static org.eclipse.jetty.start.UsageException.*;
+import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -42,6 +42,8 @@
  */
 public final class Props implements Iterable<Prop>
 {
+    private static final Pattern __propertyPattern = Pattern.compile("(?<=[^$]|^)\\$\\{([^}]*)\\}");
+    
     public static class Prop
     {
         public String key;
@@ -129,6 +131,7 @@
      * If arg is not a property, ignore it.
      * @param arg the argument to parse for a potential property
      * @param source the source for this argument (to track origin of property from)
+     * @return true if the property was added, false if the property wasn't added
      */
     public boolean addPossibleProperty(String arg, String source)
     {
@@ -199,8 +202,7 @@
             return str;
         }
 
-        Pattern pat = Pattern.compile("(?<=[^$]|^)(\\$\\{[^}]*\\})");
-        Matcher mat = pat.matcher(str);
+        Matcher mat = __propertyPattern.matcher(str);
         StringBuilder expanded = new StringBuilder();
         int offset = 0;
         String property;
@@ -208,7 +210,7 @@
 
         while (mat.find(offset))
         {
-            property = cleanReference(mat.group(1));
+            property = mat.group(1);
 
             // Loop detection
             if (seenStack.contains(property))
@@ -228,13 +230,13 @@
             seenStack.push(property);
 
             // find property name
-            expanded.append(str.subSequence(offset,mat.start(1)));
+            expanded.append(str.subSequence(offset,mat.start()));
             // get property value
             value = getString(property);
             if (value == null)
             {
                 StartLog.trace("Unable to expand: %s",property);
-                expanded.append(mat.group(1));
+                expanded.append(mat.group());
             }
             else
             {
@@ -243,7 +245,7 @@
                 expanded.append(value);
             }
             // update offset
-            offset = mat.end(1);
+            offset = mat.end();
         }
 
         // leftover
@@ -318,7 +320,7 @@
 
     public static boolean hasPropertyKey(String name)
     {
-        return Pattern.compile("(?<=[^$]|^)(\\$\\{[^}]*\\})").matcher(name).find();
+        return __propertyPattern.matcher(name).find();
     }
 
     @Override
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/README.TXT b/jetty-start/src/main/java/org/eclipse/jetty/start/README.TXT
deleted file mode 100644
index fc569bc..0000000
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/README.TXT
+++ /dev/null
@@ -1,48 +0,0 @@
-Jetty start
------------
-
-The run directory is either the top-level of a distribution
-or jetty-distribution/target/distribution directory when built from
-source.
-
-Jetty start.jar provides a cross platform replacement for startup scripts.
-It makes use of executable JAR that builds the classpath and then executes
-jetty.
-
-To run with the demo:
-
-  java -jar start.jar --enable=demo
-  java -jar start.jar
-
-To run with the default modules:
-
-  java -jar start.jar
-
-The default options may be specified in the start.ini file, or if
-that is not present, they are defined in the start.config file that
-is within the start.jar.
-
-To run with specific configuration file(s)
-
-  java -jar start.jar etc/jetty.xml
-
-To see the available options
-
-  java -jar start.jar --help
-
-To run with JSP support (if available)
-
-  java -jar start.jar --module=jsp
-
-To run with JMX support
-
-  java -jar start.jar --module=jmx
-
-To run with JSP & JMX support
-
-    java -jar start.jar --module=jsp,jmx
-
-Note that JSP requires the jasper jars to be within $JETTY/lib/jsp  These 
-are currently not distributed with the eclipse release and must be
-obtained from a jetty-hightide release from codehaus.
-
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
index 66f9f72..e9398ea 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
@@ -18,12 +18,14 @@
 
 package org.eclipse.jetty.start;
 
-import static org.eclipse.jetty.start.UsageException.*;
-
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -31,6 +33,7 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
+import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
 
@@ -39,6 +42,8 @@
 import org.eclipse.jetty.start.config.ConfigSources;
 import org.eclipse.jetty.start.config.DirConfigSource;
 
+import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
+
 /**
  * The Arguments required to start Jetty.
  */
@@ -48,40 +53,87 @@
 
     static
     {
+        // Use command line versions
         String ver = System.getProperty("jetty.version",null);
+        String tag = System.getProperty("jetty.tag.version","master");
 
+        // Use META-INF/MANIFEST.MF versions
         if (ver == null)
         {
             Package pkg = StartArgs.class.getPackage();
             if ((pkg != null) && "Eclipse.org - Jetty".equals(pkg.getImplementationVendor()) && (pkg.getImplementationVersion() != null))
             {
                 ver = pkg.getImplementationVersion();
+                if (tag == null)
+                {
+                    tag = "jetty-" + ver;
+                }
             }
         }
 
+        // Use jetty-version.properties values
         if (ver == null)
         {
-            ver = "TEST";
+            URL url = Thread.currentThread().getContextClassLoader().getResource("jetty-version.properties");
+            if (url != null)
+            {
+                try (InputStream in = url.openStream())
+                {
+                    Properties props = new Properties();
+                    props.load(in);
+                    ver = props.getProperty("jetty.version");
+                }
+                catch (IOException ignore)
+                {
+                    StartLog.debug(ignore);
+                }
+            }
+        }
+
+        // Default values
+        if (ver == null)
+        {
+            ver = "0.0";
+            if (tag == null)
+            {
+                tag = "master";
+            }
+        }
+
+        // Set Tag Defaults
+        if (tag == null || tag.contains("-SNAPSHOT"))
+        {
+            tag = "master";
         }
 
         VERSION = ver;
         System.setProperty("jetty.version",VERSION);
+        System.setProperty("jetty.tag.version",tag);
     }
 
     private static final String SERVER_MAIN = "org.eclipse.jetty.xml.XmlConfiguration";
 
     /** List of enabled modules */
     private Set<String> modules = new HashSet<>();
+
+    /** List of modules to skip [files] section validation */
+    private Set<String> skipFileValidationModules = new HashSet<>();
+
     /** Map of enabled modules to the source of where that activation occurred */
     private Map<String, List<String>> sources = new HashMap<>();
+
     /** Map of properties to where that property was declared */
     private Map<String, String> propertySource = new HashMap<>();
+
     /** List of all active [files] sections from enabled modules */
     private List<FileArg> files = new ArrayList<>();
+
     /** List of all active [lib] sections from enabled modules */
     private Classpath classpath;
+
     /** List of all active [xml] sections from enabled modules */
     private List<Path> xmls = new ArrayList<>();
+
     /** JVM arguments, found via commmand line and in all active [exec] sections from enabled modules */
     private List<String> jvmArgs = new ArrayList<>();
 
@@ -90,7 +142,7 @@
 
     /** List of all property references found directly on command line or start.ini */
     private List<String> propertyFileRefs = new ArrayList<>();
-    
+
     /** List of all property files */
     private List<Path> propertyFiles = new ArrayList<>();
 
@@ -112,7 +164,12 @@
     private Modules allModules;
     /** Should the server be run? */
     private boolean run = true;
+
+    /** Download related args */
     private boolean download = false;
+    private boolean licenseCheckRequired = false;
+    private boolean testingMode = false;
+
     private boolean help = false;
     private boolean stopCommand = false;
     private boolean listModules = false;
@@ -122,8 +179,8 @@
     private boolean dryRun = false;
 
     private boolean exec = false;
+    private String exec_properties;
     private boolean approveAllLicenses = false;
-    private boolean testingMode = false;
 
     public StartArgs()
     {
@@ -132,7 +189,13 @@
 
     private void addFile(Module module, String uriLocation)
     {
-        FileArg arg = new FileArg(module, uriLocation);
+        if (module.isSkipFilesValidation())
+        {
+            StartLog.debug("Not validating %s [files] for %s",module,uriLocation);
+            return;
+        }
+
+        FileArg arg = new FileArg(module,properties.expand(uriLocation));
         if (!files.contains(arg))
         {
             files.add(arg);
@@ -157,7 +220,7 @@
             xmls.add(xmlfile);
         }
     }
-    
+
     private void addUniquePropertyFile(String propertyFileRef, Path propertyFile) throws IOException
     {
         if (!FS.canReadFile(propertyFile))
@@ -211,9 +274,10 @@
         System.out.println("Jetty Environment:");
         System.out.println("-----------------");
         dumpProperty("jetty.version");
+        dumpProperty("jetty.tag.version");
         dumpProperty("jetty.home");
         dumpProperty("jetty.base");
-        
+
         // Jetty Configuration Environment
         System.out.println();
         System.out.println("Config Search Order:");
@@ -231,7 +295,7 @@
             }
             System.out.println();
         }
-        
+
         // Jetty Se
         System.out.println();
     }
@@ -344,8 +408,9 @@
     }
 
     /**
-     * Ensure that the System Properties are set (if defined as a System property, or start.config property, or start.ini property)
-     * 
+     * Ensure that the System Properties are set (if defined as a System property, or start.config property, or
+     * start.ini property)
+     *
      * @param key
      *            the key to be sure of
      */
@@ -371,9 +436,11 @@
 
     /**
      * Expand any command line added <code>--lib</code> lib references.
-     * 
+     *
      * @param baseHome
+     *            the base home in use
      * @throws IOException
+     *             if unable to expand the libraries
      */
     public void expandLibs(BaseHome baseHome) throws IOException
     {
@@ -383,10 +450,10 @@
             StartLog.debug("rawlibref = " + rawlibref);
             String libref = properties.expand(rawlibref);
             StartLog.debug("expanded = " + libref);
-            
+
             // perform path escaping (needed by windows)
             libref = libref.replaceAll("\\\\([^\\\\])","\\\\\\\\$1");
-            
+
             for (Path libpath : baseHome.getPaths(libref))
             {
                 classpath.addComponent(libpath.toFile());
@@ -396,10 +463,13 @@
 
     /**
      * Build up the Classpath and XML file references based on enabled Module list.
-     * 
+     *
      * @param baseHome
+     *            the base home in use
      * @param activeModules
+     *            the active (selected) modules
      * @throws IOException
+     *             if unable to expand the modules
      */
     public void expandModules(BaseHome baseHome, List<Module> activeModules) throws IOException
     {
@@ -429,6 +499,7 @@
             for (String xmlRef : module.getXmls())
             {
                 // Straight Reference
+                xmlRef = properties.expand(xmlRef);
                 Path xmlfile = baseHome.getPath(xmlRef);
                 addUniqueXmlFile(xmlRef,xmlfile);
             }
@@ -512,27 +583,34 @@
         ensureSystemPropertySet("STOP.WAIT");
 
         // pass properties as args or as a file
-        if (dryRun || isExec())
+        if (dryRun && exec_properties==null)
         {
             for (Prop p : properties)
-                cmd.addRawArg(CommandLineBuilder.quote(p.key)+"="+CommandLineBuilder.quote(p.value));
+                cmd.addRawArg(CommandLineBuilder.quote(p.key) + "=" + CommandLineBuilder.quote(p.value));
         }
         else if (properties.size() > 0)
         {
-            File prop_file = File.createTempFile("start",".properties");
-            prop_file.deleteOnExit();
-            try (FileOutputStream out = new FileOutputStream(prop_file))
+            Path prop_path;
+            if (exec_properties==null)
+            {
+                prop_path=Files.createTempFile("start_", ".properties");
+                prop_path.toFile().deleteOnExit();
+            }
+            else
+                prop_path=new File(exec_properties).toPath();
+                
+            try (OutputStream out = Files.newOutputStream(prop_path))
             {
                 properties.store(out,"start.jar properties");
             }
-            cmd.addRawArg(prop_file.getAbsolutePath());
+            cmd.addRawArg(prop_path.toAbsolutePath().toString());
         }
 
         for (Path xml : xmls)
         {
             cmd.addRawArg(xml.toAbsolutePath().toString());
         }
-        
+
         for (Path propertyFile : propertyFiles)
         {
             cmd.addRawArg(propertyFile.toAbsolutePath().toString());
@@ -547,6 +625,46 @@
         return System.getProperty("main.class",mainclass);
     }
 
+    public Path getMavenLocalRepoDir()
+    {
+        // Try property first
+        String localRepo = getProperties().getString("maven.local.repo");
+
+        if (Utils.isBlank(localRepo))
+        {
+            // Try jetty specific env variable
+            localRepo = System.getenv("JETTY_MAVEN_LOCAL_REPO");
+        }
+
+        if (Utils.isBlank(localRepo))
+        {
+            // Try generic env variable
+            localRepo = System.getenv("MAVEN_LOCAL_REPO");
+        }
+
+        // TODO: load & use $HOME/.m2/settings.xml ?
+        // TODO: possibly use Eclipse Aether to manage it ?
+        // TODO: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=449511
+
+        // Still blank? then its not specified
+        if (Utils.isBlank(localRepo))
+        {
+            return null;
+        }
+
+        Path localRepoDir = new File(localRepo).toPath();
+        localRepoDir = localRepoDir.normalize().toAbsolutePath();
+        if (Files.exists(localRepoDir) && Files.isDirectory(localRepoDir))
+        {
+            return localRepoDir;
+        }
+
+        StartLog.warn("Not a valid maven local repository directory: %s",localRepoDir);
+
+        // Not a valid repository directory, skip it
+        return null;
+    }
+
     public String getModuleGraphFilename()
     {
         return moduleGraphFilename;
@@ -557,6 +675,11 @@
         return properties;
     }
 
+    public Set<String> getSkipFileValidationModules()
+    {
+        return skipFileValidationModules;
+    }
+
     public List<String> getSources(String module)
     {
         return sources.get(module);
@@ -606,7 +729,12 @@
     {
         return exec;
     }
-    
+
+    public boolean isLicenseCheckRequired()
+    {
+        return licenseCheckRequired;
+    }
+
     public boolean isNormalMainClass()
     {
         return SERVER_MAIN.equals(getMainClassname());
@@ -641,7 +769,7 @@
     {
         return stopCommand;
     }
-    
+
     public boolean isTestingModeEnabled()
     {
         return testingMode;
@@ -672,10 +800,13 @@
 
     /**
      * Parse a single line of argument.
-     * 
-     * @param rawarg the raw argument to parse
-     * @param source the origin of this line of argument
-     * @param replaceProps true if properties in this parse replace previous ones, false to not replace.
+     *
+     * @param rawarg
+     *            the raw argument to parse
+     * @param source
+     *            the origin of this line of argument
+     * @param replaceProps
+     *            true if properties in this parse replace previous ones, false to not replace.
      */
     private void parse(final String rawarg, String source, boolean replaceProps)
     {
@@ -683,7 +814,7 @@
         {
             return;
         }
-        
+
         StartLog.debug("parse(\"%s\", \"%s\", %b)",rawarg,source,replaceProps);
 
         final String arg = rawarg.trim();
@@ -710,7 +841,7 @@
             // valid, but handled in StartLog instead
             return;
         }
-        
+
         if ("--testing-mode".equals(arg))
         {
             System.setProperty("org.eclipse.jetty.start.testing","true");
@@ -743,6 +874,7 @@
         {
             run = false;
             download = true;
+            licenseCheckRequired = true;
             return;
         }
 
@@ -773,6 +905,15 @@
             exec = true;
             return;
         }
+        
+        // Assign a fixed name to the property file for exec
+        if (arg.startsWith("--exec-properties="))
+        {
+            exec_properties=Props.getValue(arg);
+            if (!exec_properties.endsWith(".properties"))
+                throw new UsageException(ERR_BAD_ARG,"--exec-properties filename must have .properties suffix: %s",exec_properties);
+            return;
+        }
 
         // Enable forked execution of Jetty server
         if ("--approve-all-licenses".equals(arg))
@@ -812,6 +953,7 @@
             addToStartdIni.addAll(moduleNames);
             run = false;
             download = true;
+            licenseCheckRequired = true;
             return;
         }
 
@@ -822,6 +964,7 @@
             addToStartIni.addAll(moduleNames);
             run = false;
             download = true;
+            licenseCheckRequired = true;
             return;
         }
 
@@ -833,6 +976,17 @@
             return;
         }
 
+        // Skip [files] validation on a module
+        if (arg.startsWith("--skip-file-validation="))
+        {
+            List<String> moduleNames = Props.getValues(arg);
+            for (String moduleName : moduleNames)
+            {
+                skipFileValidationModules.add(moduleName);
+            }
+            return;
+        }
+
         // Create graphviz output of module graph
         if (arg.startsWith("--write-module-graph="))
         {
@@ -914,7 +1068,7 @@
             }
             return;
         }
-        
+
         if (FS.isPropertyFile(arg))
         {
             // only add non-duplicates
@@ -922,7 +1076,7 @@
             {
                 propertyFileRefs.add(arg);
             }
-                return;
+            return;
         }
 
         // Anything else is unrecognized
@@ -946,9 +1100,9 @@
 
     public void parseModule(Module module)
     {
-        if(module.hasDefaultConfig()) 
+        if (module.hasDefaultConfig())
         {
-            for(String line: module.getDefaultConfig())
+            for (String line : module.getDefaultConfig())
             {
                 parse(line,module.getFilesystemRef(),false);
             }
@@ -969,7 +1123,7 @@
             addUniqueXmlFile(xmlRef,xmlfile);
         }
     }
-    
+
     public void resolvePropertyFiles(BaseHome baseHome) throws IOException
     {
         // Find and Expand property files
@@ -990,7 +1144,7 @@
         this.allModules = allModules;
     }
 
-    private void setProperty(String key, String value, String source, boolean replaceProp)
+    public void setProperty(String key, String value, String source, boolean replaceProp)
     {
         // Special / Prevent override from start.ini's
         if (key.equals("jetty.home"))
@@ -1006,18 +1160,18 @@
             return;
         }
 
-        // Normal
-        if (replaceProp)
+        if (replaceProp || (!properties.containsKey(key)))
         {
-            // always override
             properties.setProperty(key,value,source);
-        }
-        else
-        {
-            // only set if unset
-            if (!properties.containsKey(key))
+            if(key.equals("java.version"))
             {
-                properties.setProperty(key,value,source);
+                Version ver = new Version(value);
+
+                properties.setProperty("java.version",ver.toShortString(),source);
+                properties.setProperty("java.version.major",Integer.toString(ver.getLegacyMajor()),source);
+                properties.setProperty("java.version.minor",Integer.toString(ver.getMajor()),source);
+                properties.setProperty("java.version.revision",Integer.toString(ver.getRevision()),source);
+                properties.setProperty("java.version.update",Integer.toString(ver.getUpdate()),source);
             }
         }
     }
@@ -1042,5 +1196,4 @@
         builder.append("]");
         return builder.toString();
     }
-
 }
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
index ea1f94a..ab4c014 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartIni.java
@@ -64,7 +64,14 @@
     @Override
     public void init()
     {
-        basedir = getFile().getParent().toAbsolutePath();
+        try
+        {
+            basedir = getFile().getParent().toRealPath();
+        }
+        catch (IOException e)
+        {
+            basedir = getFile().getParent().normalize().toAbsolutePath();
+        }
     }
 
     public Path getBaseDir()
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java b/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java
index 55ae806..3d67ab1 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java
@@ -27,8 +27,9 @@
     public static final int ERR_LOGGING = -1;
     public static final int ERR_INVOKE_MAIN = -2;
     public static final int ERR_NOT_STOPPED = -4;
-    public static final int ERR_UNKNOWN = -5;
-    public static final int ERR_BAD_ARG = -6;
+    public static final int ERR_BAD_ARG = -5;
+    public static final int ERR_BAD_GRAPH = -6;
+    public static final int ERR_UNKNOWN = -9;
     private int exitCode;
 
     public UsageException(int exitCode, String format, Object... objs)
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Utils.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Utils.java
new file mode 100644
index 0000000..099aa88
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Utils.java
@@ -0,0 +1,122 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import java.util.Collection;
+
+public final class Utils
+{
+    public static String join(Object[] arr, String delim)
+    {
+        if (arr == null)
+        {
+            return "";
+        }
+
+        return join(arr,0,arr.length,delim);
+    }
+
+    public static String join(Object[] arr, int start, int end, String delim)
+    {
+        if (arr == null)
+        {
+            return "";
+        }
+        StringBuilder str = new StringBuilder();
+        for (int i = start; i < end; i++)
+        {
+            if (i > start)
+            {
+                str.append(delim);
+            }
+            str.append(arr[i]);
+        }
+        return str.toString();
+    }
+
+    public static String join(Collection<?> objs, String delim)
+    {
+        if (objs == null)
+        {
+            return "";
+        }
+        StringBuilder str = new StringBuilder();
+        boolean needDelim = false;
+        for (Object obj : objs)
+        {
+            if (needDelim)
+            {
+                str.append(delim);
+            }
+            str.append(obj);
+            needDelim = true;
+        }
+        return str.toString();
+    }
+
+    /**
+     * Is String null, empty, or consisting of only whitespace.
+     * 
+     * @param value
+     *            the value to test
+     * @return true if null, empty, or consisting of only whitespace
+     */
+    public static boolean isBlank(String value)
+    {
+        if (value == null)
+        {
+            return true;
+        }
+        int len = value.length();
+        for (int i = 0; i < len; i++)
+        {
+            int c = value.codePointAt(i);
+            if (!Character.isWhitespace(c))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Is String valid and has something other than whitespace
+     * 
+     * @param value
+     *            the value to test
+     * @return true if String has something other than whitespace
+     */
+    public static boolean isNotBlank(String value)
+    {
+        if (value == null)
+        {
+            return false;
+        }
+        int len = value.length();
+        for (int i = 0; i < len; i++)
+        {
+            int c = value.codePointAt(i);
+            if (!Character.isWhitespace(c))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Version.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Version.java
index a5be92d..c9fceee 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/Version.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Version.java
@@ -19,112 +19,223 @@
 package org.eclipse.jetty.start;
 
 /**
- * Utility class for parsing and comparing version strings. JDK 1.1 compatible.
- * 
+ * Utility class for parsing and comparing version strings.
+ * <p>
+ * http://www.oracle.com/technetwork/java/javase/namechange-140185.html
  */
-
-public class Version
+public class Version implements Comparable<Version>
 {
+    /**
+     * The major version for java is always "1" (per
+     * <a href="http://www.oracle.com/technetwork/java/javase/namechange-140185.html">legacy versioning history</a>)
+     */
+    private int legacyMajor = 0;
+    /**
+     * The true major version is the second value ("1.5" == "Java 5", "1.8" = "Java 8", etc..)
+     */
+    private int major = -1;
+    /**
+     * The revision of the version.
+     * <p>
+     * This value is always "0" (also per <a
+     * href="http://www.oracle.com/technetwork/java/javase/namechange-140185.html">legacy versioning history</a>)
+     */
+    private int revision = -1;
+    /**
+     * The update (where bug fixes are placed)
+     */
+    private int update = -1;
+    /**
+     * Extra versioning information present on the version string, but not relevant for version comparison reason.
+     * (eg: with "1.8.0_45-internal", the suffix would be "-internal")
+     */
+    private String suffix = "";
 
-    int _version = 0;
-    int _revision = 0;
-    int _subrevision = 0;
-    String _suffix = "";
-
-    public Version()
+    private static enum ParseState
     {
+        LEGACY,
+        MAJOR,
+        REVISION,
+        UPDATE;
     }
 
-    public Version(String version_string)
+    public Version(String versionString)
     {
-        parse(version_string);
+        parse(versionString);
     }
 
-    // java.lang.Comparable is Java 1.2! Cannot use it
+    @Override
     /**
      * Compares with other version. Does not take extension into account, as there is no reliable way to order them.
      * 
+     * @param other the other version to compare this to 
      * @return -1 if this is older version that other, 0 if its same version, 1 if it's newer version than other
      */
-    public int compare(Version other)
+    public int compareTo(Version other)
     {
         if (other == null)
         {
             throw new NullPointerException("other version is null");
         }
-        if (this._version < other._version)
+        if (this.legacyMajor < other.legacyMajor)
         {
             return -1;
         }
-        if (this._version > other._version)
+        if (this.legacyMajor > other.legacyMajor)
         {
             return 1;
         }
-        if (this._revision < other._revision)
+        if (this.major < other.major)
         {
             return -1;
         }
-        if (this._revision > other._revision)
+        if (this.major > other.major)
         {
             return 1;
         }
-        if (this._subrevision < other._subrevision)
+        if (this.revision < other.revision)
         {
             return -1;
         }
-        if (this._subrevision > other._subrevision)
+        if (this.revision > other.revision)
+        {
+            return 1;
+        }
+        if (this.update < other.update)
+        {
+            return -1;
+        }
+        if (this.update > other.update)
         {
             return 1;
         }
         return 0;
     }
 
-    /**
-     * Check whether this verion is in range of versions specified
-     */
-    public boolean isInRange(Version low, Version high)
+    public int getLegacyMajor()
     {
-        return ((compare(low) >= 0) && (compare(high) <= 0));
+        return legacyMajor;
+    }
+
+    public int getMajor()
+    {
+        return major;
+    }
+
+    public int getRevision()
+    {
+        return revision;
+    }
+
+    public int getUpdate()
+    {
+        return update;
+    }
+
+    public String getSuffix()
+    {
+        return suffix;
+    }
+
+    public boolean isNewerThan(Version other)
+    {
+        return compareTo(other) == 1;
+    }
+
+    public boolean isNewerThanOrEqualTo(Version other)
+    {
+        int comp = compareTo(other);
+        return (comp == 0) || (comp == 1);
+    }
+
+    public boolean isOlderThan(Version other)
+    {
+        return compareTo(other) == -1;
+    }
+
+    public boolean isOlderThanOrEqualTo(Version other)
+    {
+        int comp = compareTo(other);
+        return (comp == 0) || (comp == -1);
     }
 
     /**
-     * parses version string in the form version[.revision[.subrevision[extension]]] into this instance.
+     * Check whether this version is in range of versions specified
+     * 
+     * @param low
+     *            the low part of the range
+     * @param high
+     *            the high part of the range
+     * @return true if this version is within the provided range
      */
-    public void parse(String version_string)
+    public boolean isInRange(Version low, Version high)
     {
-        _version = 0;
-        _revision = 0;
-        _subrevision = 0;
-        _suffix = "";
-        int pos = 0;
-        int startpos = 0;
-        int endpos = version_string.length();
-        while ((pos < endpos) && Character.isDigit(version_string.charAt(pos)))
+        return ((compareTo(low) >= 0) && (compareTo(high) <= 0));
+    }
+
+    /**
+     * parses version string in the form legacy[.major[.revision[_update[-suffix]]]] into this instance.
+     * 
+     * @param versionStr
+     *            the version string
+     */
+    private void parse(String versionStr)
+    {
+        legacyMajor = 0;
+        major = -1;
+        revision = -1;
+        update = -1;
+        suffix = "";
+
+        ParseState state = ParseState.LEGACY;
+        int offset = 0;
+        int len = versionStr.length();
+        int val = 0;
+        while (offset < len)
         {
-            pos++;
-        }
-        _version = Integer.parseInt(version_string.substring(startpos,pos));
-        if ((pos < endpos) && (version_string.charAt(pos) == '.'))
-        {
-            startpos = ++pos;
-            while ((pos < endpos) && Character.isDigit(version_string.charAt(pos)))
+            char c = versionStr.charAt(offset);
+            boolean isSeparator = !Character.isLetterOrDigit(c);
+            if (isSeparator)
             {
-                pos++;
+                val = 0;
             }
-            _revision = Integer.parseInt(version_string.substring(startpos,pos));
-        }
-        if ((pos < endpos) && (version_string.charAt(pos) == '.'))
-        {
-            startpos = ++pos;
-            while ((pos < endpos) && Character.isDigit(version_string.charAt(pos)))
+            else if (Character.isDigit(c))
             {
-                pos++;
+                val = (val * 10) + (c - '0');
             }
-            _subrevision = Integer.parseInt(version_string.substring(startpos,pos));
-        }
-        if (pos < endpos)
-        {
-            _suffix = version_string.substring(pos);
+            else if (Character.isLetter(c))
+            {
+                suffix = versionStr.substring(offset);
+                return;
+            }
+
+            switch (state)
+            {
+                case LEGACY:
+                    if (isSeparator)
+                        state = ParseState.MAJOR;
+                    else
+                        legacyMajor = val;
+                    break;
+                case MAJOR:
+                    if (isSeparator)
+                        state = ParseState.REVISION;
+                    else
+                        major = val;
+                    break;
+                case REVISION:
+                    if (isSeparator)
+                        state = ParseState.UPDATE;
+                    else
+                        revision = val;
+                    break;
+                case UPDATE:
+                    if (!isSeparator)
+                        update = val;
+                    break;
+            }
+
+            offset++;
         }
     }
 
@@ -135,12 +246,46 @@
     public String toString()
     {
         StringBuffer sb = new StringBuffer(10);
-        sb.append(_version);
-        sb.append('.');
-        sb.append(_revision);
-        sb.append('.');
-        sb.append(_subrevision);
-        sb.append(_suffix);
+        sb.append(legacyMajor);
+        if (major >= 0)
+        {
+            sb.append('.').append(major);
+            if (revision >= 0)
+            {
+                sb.append('.').append(revision);
+                if (update >= 0)
+                {
+                    sb.append('_').append(update);
+                }
+            }
+        }
+        if (Utils.isNotBlank(suffix))
+        {
+            sb.append('-').append(suffix);
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * Return short string form (without suffix)
+     * @return string the short version string form
+     */
+    public String toShortString()
+    {
+        StringBuffer sb = new StringBuffer(10);
+        sb.append(legacyMajor);
+        if (major >= 0)
+        {
+            sb.append('.').append(major);
+            if (revision >= 0)
+            {
+                sb.append('.').append(revision);
+                if (update >= 0)
+                {
+                    sb.append('_').append(update);
+                }
+            }
+        }
         return sb.toString();
     }
 }
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java
new file mode 100644
index 0000000..76ff6b2
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java
@@ -0,0 +1,106 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.builders;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import org.eclipse.jetty.start.BaseBuilder;
+import org.eclipse.jetty.start.BaseHome;
+import org.eclipse.jetty.start.FS;
+import org.eclipse.jetty.start.Module;
+import org.eclipse.jetty.start.StartLog;
+import org.eclipse.jetty.start.graph.OnlyTransitivePredicate;
+
+/**
+ * Management of the <code>${jetty.base}/start.d/</code> based configuration.
+ * <p>
+ * Implementation of the <code>--add-to-startd=[name]</code> command line behavior
+ */
+public class StartDirBuilder implements BaseBuilder.Config
+{
+    private final BaseHome baseHome;
+    private final Path startDir;
+
+    public StartDirBuilder(BaseBuilder baseBuilder) throws IOException
+    {
+        this.baseHome = baseBuilder.getBaseHome();
+        this.startDir = baseHome.getBasePath("start.d");
+        FS.ensureDirectoryExists(startDir);
+    }
+
+    @Override
+    public boolean addModule(Module module) throws IOException
+    {
+        if (module.isDynamic())
+        {
+            if (module.hasIniTemplate())
+            {
+                // warn
+                StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName());
+            }
+            return false;
+        }
+
+        String mode = "";
+        boolean isTransitive = module.matches(OnlyTransitivePredicate.INSTANCE);
+        if (isTransitive)
+        {
+            mode = "(transitively) ";
+        }
+
+        if (module.hasIniTemplate() || !isTransitive)
+        {
+            // Create start.d/{name}.ini
+            Path ini = startDir.resolve(module.getName() + ".ini");
+            StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(ini));
+
+            try (BufferedWriter writer = Files.newBufferedWriter(ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING))
+            {
+                writeModuleSection(writer,module);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    protected void writeModuleSection(BufferedWriter writer, Module module)
+    {
+        PrintWriter out = new PrintWriter(writer);
+
+        out.println("# --------------------------------------- ");
+        out.println("# Module: " + module.getName());
+        out.println("--module=" + module.getName());
+        out.println();
+
+        for (String line : module.getIniTemplate())
+        {
+            out.println(line);
+        }
+
+        out.println();
+        out.flush();
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java
new file mode 100644
index 0000000..af1227e
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java
@@ -0,0 +1,148 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.builders;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jetty.start.BaseBuilder;
+import org.eclipse.jetty.start.BaseHome;
+import org.eclipse.jetty.start.Module;
+import org.eclipse.jetty.start.Props;
+import org.eclipse.jetty.start.StartLog;
+import org.eclipse.jetty.start.graph.OnlyTransitivePredicate;
+
+/**
+ * Management of the <code>${jetty.base}/start.ini</code> based configuration.
+ * <p>
+ * Implementation of the <code>--add-to-start=[name]</code> command line behavior
+ */
+public class StartIniBuilder implements BaseBuilder.Config
+{
+    private final BaseHome baseHome;
+    private final Path startIni;
+
+    /* List of modules already present in start.ini */
+    private Set<String> modulesPresent = new HashSet<>();
+
+    /* List of properties (keys only) already present in start.ini */
+    private Set<String> propsPresent = new HashSet<>();
+
+    public StartIniBuilder(BaseBuilder baseBuilder) throws IOException
+    {
+        this.baseHome = baseBuilder.getBaseHome();
+        this.startIni = baseHome.getBasePath("start.ini");
+
+        if (Files.exists(startIni))
+        {
+            parseIni();
+        }
+    }
+
+    private void parseIni() throws IOException
+    {
+        try (BufferedReader reader = Files.newBufferedReader(startIni,StandardCharsets.UTF_8))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                line = line.trim();
+                if (line.startsWith("--module="))
+                {
+                    List<String> moduleNames = Props.getValues(line);
+                    this.modulesPresent.addAll(moduleNames);
+                }
+                else if (!line.startsWith("-") && line.contains("="))
+                {
+                    String key = line.substring(0,line.indexOf('='));
+                    this.propsPresent.add(key);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean addModule(Module module) throws IOException
+    {
+        if (modulesPresent.contains(module.getName()))
+        {
+            StartLog.info("%-15s already initialised in %s",module.getName(),baseHome.toShortForm(startIni));
+            // skip, already present
+            return false;
+        }
+
+        if (module.isDynamic())
+        {
+            if (module.hasIniTemplate())
+            {
+                // warn
+                StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName());
+            }
+            return false;
+        }
+
+        String mode = "";
+        boolean isTransitive = module.matches(OnlyTransitivePredicate.INSTANCE);
+        if (isTransitive)
+        {
+            mode = "(transitively) ";
+        }
+
+        if (module.hasIniTemplate() || !isTransitive)
+        {
+            StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(startIni));
+
+            // Append to start.ini
+            try (BufferedWriter writer = Files.newBufferedWriter(startIni,StandardCharsets.UTF_8,StandardOpenOption.APPEND,StandardOpenOption.CREATE))
+            {
+                writeModuleSection(writer,module);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    protected void writeModuleSection(BufferedWriter writer, Module module)
+    {
+        PrintWriter out = new PrintWriter(writer);
+
+        out.println("# --------------------------------------- ");
+        out.println("# Module: " + module.getName());
+        out.println("--module=" + module.getName());
+        out.println();
+
+        for (String line : module.getIniTemplate())
+        {
+            out.println(line);
+        }
+
+        out.println();
+        out.flush();
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
index 4948e98..4643da6 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
@@ -32,6 +32,7 @@
 import org.eclipse.jetty.start.Props.Prop;
 import org.eclipse.jetty.start.RawArgs;
 import org.eclipse.jetty.start.UsageException;
+import org.eclipse.jetty.start.Utils;
 
 /**
  * Configuration Source representing the Command Line arguments.
@@ -69,14 +70,14 @@
     {
         // If a jetty property is defined, use it
         Prop prop = this.props.getProp(BaseHome.JETTY_BASE,false);
-        if (prop != null && !isEmpty(prop.value))
+        if (prop != null && !Utils.isBlank(prop.value))
         {
             return FS.toPath(prop.value);
         }
 
         // If a system property is defined, use it
         String val = System.getProperty(BaseHome.JETTY_BASE);
-        if (!isEmpty(val))
+        if (!Utils.isBlank(val))
         {
             return FS.toPath(val);
         }
@@ -91,14 +92,14 @@
     {
         // If a jetty property is defined, use it
         Prop prop = this.props.getProp(BaseHome.JETTY_HOME,false);
-        if (prop != null && !isEmpty(prop.value))
+        if (prop != null && !Utils.isBlank(prop.value))
         {
             return FS.toPath(prop.value);
         }
 
         // If a system property is defined, use it
         String val = System.getProperty(BaseHome.JETTY_HOME);
-        if (!isEmpty(val))
+        if (!Utils.isBlank(val))
         {
             return FS.toPath(val);
         }
@@ -130,24 +131,6 @@
         return home;
     }
 
-    private boolean isEmpty(String value)
-    {
-        if (value == null)
-        {
-            return true;
-        }
-        int len = value.length();
-        for (int i = 0; i < len; i++)
-        {
-            int c = value.codePointAt(i);
-            if (!Character.isWhitespace(c))
-            {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     public boolean equals(Object obj)
     {
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java
index d65bdd0..dca5cc2 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/ConfigSources.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.start.config;
 
-import static org.eclipse.jetty.start.UsageException.*;
+import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
 
 import java.io.IOException;
 import java.nio.file.Path;
@@ -31,13 +31,12 @@
 
 import org.eclipse.jetty.start.FS;
 import org.eclipse.jetty.start.Props;
-import org.eclipse.jetty.start.RawArgs;
 import org.eclipse.jetty.start.Props.Prop;
+import org.eclipse.jetty.start.RawArgs;
 import org.eclipse.jetty.start.UsageException;
 
 /**
  * Weighted List of ConfigSources.
- * <p>
  */
 public class ConfigSources implements Iterable<ConfigSource>
 {
@@ -74,7 +73,7 @@
             {
                 String ref = getValue(arg.getLine());
                 String dirName = props.expand(ref);
-                Path dir = FS.toPath(dirName);
+                Path dir = FS.toPath(dirName).normalize().toAbsolutePath();
                 DirConfigSource dirsource = new DirConfigSource(ref,dir,sourceWeight.incrementAndGet(),true);
                 add(dirsource);
             }
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java
index 607bf1f..b350851 100644
--- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/DirConfigSource.java
@@ -18,11 +18,12 @@
 
 package org.eclipse.jetty.start.config;
 
-import static org.eclipse.jetty.start.UsageException.*;
+import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
 
 import java.io.IOException;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.PathMatcher;
 import java.util.ArrayList;
@@ -33,11 +34,11 @@
 import org.eclipse.jetty.start.NaturalSort;
 import org.eclipse.jetty.start.PathMatchers;
 import org.eclipse.jetty.start.Props;
-import org.eclipse.jetty.start.RawArgs;
-import org.eclipse.jetty.start.UsageException;
 import org.eclipse.jetty.start.Props.Prop;
+import org.eclipse.jetty.start.RawArgs;
 import org.eclipse.jetty.start.StartIni;
 import org.eclipse.jetty.start.StartLog;
+import org.eclipse.jetty.start.UsageException;
 
 /**
  * A Directory based {@link ConfigSource}.
@@ -100,12 +101,21 @@
 
         if (canHaveArgs)
         {
-            Path iniFile = dir.resolve("start.ini");
-            if (FS.canReadFile(iniFile))
+            Path iniFile = dir.resolve("start.ini").normalize().toAbsolutePath();
+            
+            try
             {
-                StartIni ini = new StartIni(iniFile);
-                args.addAll(ini.getLines(),iniFile);
-                parseAllArgs(ini.getLines(),iniFile.toString());
+                iniFile = iniFile.toRealPath();
+                if (FS.canReadFile(iniFile))
+                {
+                    StartIni ini = new StartIni(iniFile);
+                    args.addAll(ini.getLines(),iniFile);
+                    parseAllArgs(ini.getLines(),iniFile.toString());
+                }
+            }
+            catch (NoSuchFileException ignore)
+            {
+                // ignore
             }
 
             Path startDdir = dir.resolve("start.d");
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java
new file mode 100644
index 0000000..1aca5bc
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java
@@ -0,0 +1,194 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.start.fileinits;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jetty.start.BaseHome;
+import org.eclipse.jetty.start.FS;
+import org.eclipse.jetty.start.FileInitializer;
+import org.eclipse.jetty.start.StartLog;
+import org.eclipse.jetty.start.Utils;
+
+/**
+ * Attempt to download a <code>maven://</code> URI, by first attempting to find
+ * the resource in the maven repository system (starting with local, then
+ * central)
+ * <p>
+ * Valid URI Formats:
+ * <dl>
+ * <dt><code>maven://&lt;groupId&gt;/&lt;artifactId&gt;/&lt;version&gt;</code></dt>
+ * <dd>minimum requirement (type defaults to <code>jar</code>, with no
+ * classifier)</dd>
+ * <dt><code>maven://&lt;groupId&gt;/&lt;artifactId&gt;/&lt;version&gt;/&lt;type&gt;</code></dt>
+ * <dd>optional type requirement</dd>
+ * <dt>
+ * <code>maven://&lt;groupId&gt;/&lt;artifactId&gt;/&lt;version&gt;/&lt;type&gt;/&lt;classifier&gt;</code>
+ * </dt>
+ * <dd>optional type and classifier requirement</dd>
+ * </dl>
+ */
+public class MavenLocalRepoFileInitializer extends UriFileInitializer implements FileInitializer
+{
+    public static class Coordinates
+    {
+        public String groupId;
+        public String artifactId;
+        public String version;
+        public String type;
+        public String classifier;
+
+        public String toPath()
+        {
+            StringBuilder pathlike = new StringBuilder();
+            pathlike.append(groupId.replace('.','/'));
+            pathlike.append('/').append(artifactId);
+            pathlike.append('/').append(version);
+            pathlike.append('/').append(artifactId);
+            pathlike.append('-').append(version);
+            if (classifier != null)
+            {
+                pathlike.append('-').append(classifier);
+            }
+            pathlike.append('.').append(type);
+            return pathlike.toString();
+        }
+
+        public URI toCentralURI()
+        {
+            return URI.create("http://central.maven.org/maven2/" + toPath());
+        }
+    }
+
+    private Path localRepositoryDir;
+
+    public MavenLocalRepoFileInitializer(BaseHome baseHome)
+    {
+        this(baseHome,null);
+    }
+
+    public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir)
+    {
+        super(baseHome);
+        this.localRepositoryDir = localRepoDir;
+    }
+
+    @Override
+    public boolean init(URI uri, Path file, String fileRef) throws IOException
+    {
+        Coordinates coords = getCoordinates(uri);
+        if (coords == null)
+        {
+            // Skip, not a maven:// URI
+            return false;
+        }
+
+        if (isFilePresent(file, baseHome.getPath(fileRef)))
+        {
+            // All done
+            return true;
+        }
+
+        // If using local repository
+        if (this.localRepositoryDir != null)
+        {
+            // Grab copy from local repository (download if needed to local
+            // repository)
+            Path localRepoFile = getLocalRepoFile(coords);
+            StartLog.log("COPY","%s to %s",localRepoFile,baseHome.toShortForm(file));
+            Files.copy(localRepoFile,file);
+        }
+        else
+        {
+            // normal non-local repo version
+            download(coords.toCentralURI(),file);
+        }
+        return true;
+    }
+
+    private Path getLocalRepoFile(Coordinates coords) throws IOException
+    {
+        Path localFile = localRepositoryDir.resolve(coords.toPath());
+        if (FS.canReadFile(localFile))
+        {
+            return localFile;
+        }
+
+        // Download, if needed
+        download(coords.toCentralURI(),localFile);
+        return localFile;
+    }
+
+    public Coordinates getCoordinates(URI uri)
+    {
+        if (!"maven".equalsIgnoreCase(uri.getScheme()))
+        {
+            return null;
+        }
+
+        String ssp = uri.getSchemeSpecificPart();
+
+        if (ssp.startsWith("//"))
+        {
+            ssp = ssp.substring(2);
+        }
+
+        String parts[] = ssp.split("/");
+
+        if (StartLog.isDebugEnabled())
+        {
+            StartLog.debug("ssp = %s",ssp);
+            StartLog.debug("parts = %d",parts.length);
+            for (int i = 0; i < parts.length; i++)
+            {
+                StartLog.debug("  part[%2d]: [%s]",i,parts[i]);
+            }
+        }
+
+        if (parts.length < 3)
+        {
+            throw new RuntimeException("Not a valid maven:// uri - " + uri);
+        }
+
+        Coordinates coords = new Coordinates();
+        coords.groupId = parts[0];
+        coords.artifactId = parts[1];
+        coords.version = parts[2];
+        coords.type = "jar";
+        coords.classifier = null;
+
+        if (parts.length >= 4)
+        {
+            if (Utils.isNotBlank(parts[3]))
+            {
+                coords.type = parts[3];
+            }
+
+            if ((parts.length == 5) && (Utils.isNotBlank(parts[4])))
+            {
+                coords.classifier = parts[4];
+            }
+        }
+
+        return coords;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/TestFileInitializer.java b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/TestFileInitializer.java
new file mode 100644
index 0000000..9dfaf69
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/TestFileInitializer.java
@@ -0,0 +1,44 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.fileinits;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Path;
+
+import org.eclipse.jetty.start.FS;
+import org.eclipse.jetty.start.FileInitializer;
+import org.eclipse.jetty.start.StartLog;
+
+/**
+ * In a start testing scenario, it is often not important to actually download
+ * or initialize a file, this implementation is merely a no-op for the
+ * {@link FileInitializer}
+ */
+public class TestFileInitializer implements FileInitializer
+{
+    @Override
+    public boolean init(URI uri, Path file, String fileRef) throws IOException
+    {
+        FS.ensureDirectoryExists(file.getParent());
+
+        StartLog.log("TESTING MODE","Skipping download of " + uri);
+        return true;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/UriFileInitializer.java b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/UriFileInitializer.java
new file mode 100644
index 0000000..db7048e
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/UriFileInitializer.java
@@ -0,0 +1,149 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.fileinits;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import org.eclipse.jetty.start.BaseHome;
+import org.eclipse.jetty.start.FS;
+import org.eclipse.jetty.start.FileInitializer;
+import org.eclipse.jetty.start.StartLog;
+
+public class UriFileInitializer implements FileInitializer
+{
+    private final static String[] SUPPORTED_SCHEMES = { "http", "https" };
+    protected final BaseHome baseHome;
+    
+    public UriFileInitializer(BaseHome baseHome)
+    {
+        this.baseHome = baseHome;
+    }
+    
+    @Override
+    public boolean init(URI uri, Path file, String fileRef) throws IOException
+    {
+        if (!isSupportedScheme(uri))
+        {
+            // Not a supported scheme.
+            return false;
+        }
+
+        if(isFilePresent(file, baseHome.getPath(fileRef)))
+        {
+            // All done
+            return true;
+        }
+
+        download(uri,file);
+
+        return true;
+    }
+
+    protected void download(URI uri, Path file) throws IOException
+    {
+        StartLog.log("DOWNLOAD","%s to %s",uri,baseHome.toShortForm(file));
+
+        FS.ensureDirectoryExists(file.getParent());
+        
+        HttpURLConnection http = (HttpURLConnection)uri.toURL().openConnection();
+        http.setInstanceFollowRedirects(true);
+        http.setAllowUserInteraction(false);
+        
+        int status = http.getResponseCode();
+        
+        if(status != HttpURLConnection.HTTP_OK)
+        {
+            throw new IOException("URL GET Failure [" + status + "/" + http.getResponseMessage() + "] on " + uri);
+        }
+
+        byte[] buf = new byte[8192];
+        try (InputStream in = http.getInputStream(); OutputStream out = Files.newOutputStream(file,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE))
+        {
+            while (true)
+            {
+                int len = in.read(buf);
+
+                if (len > 0)
+                {
+                    out.write(buf,0,len);
+                }
+                if (len < 0)
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Test if any of the Paths exist (as files)
+     * 
+     * @param paths
+     *            the list of paths to check
+     * @return true if the path exist (as a file), false if it doesn't exist
+     * @throws IOException
+     *             if the path points to a non-file, or is not readable.
+     */
+    protected boolean isFilePresent(Path... paths) throws IOException
+    {
+        for (Path file : paths)
+        {
+            if (Files.exists(file))
+            {
+                if (Files.isDirectory(file))
+                {
+                    throw new IOException("Directory in the way: " + file.toAbsolutePath());
+                }
+
+                if (!Files.isReadable(file))
+                {
+                    throw new IOException("File not readable: " + file.toAbsolutePath());
+                }
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean isSupportedScheme(URI uri)
+    {
+        String scheme = uri.getScheme();
+        if (scheme == null)
+        {
+            return false;
+        }
+        for (String supported : SUPPORTED_SCHEMES)
+        {
+            if (supported.equalsIgnoreCase(scheme))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AllPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AllPredicate.java
new file mode 100644
index 0000000..ef00986
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AllPredicate.java
@@ -0,0 +1,31 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.start.graph;
+
+/**
+ * Match on everything.
+ */
+public class AllPredicate implements Predicate
+{
+    @Override
+    public boolean match(Node<?> node)
+    {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AndPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AndPredicate.java
new file mode 100644
index 0000000..2014cfa
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AndPredicate.java
@@ -0,0 +1,46 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * Match on multiple predicates.
+ */
+public class AndPredicate implements Predicate
+{
+    private final Predicate predicates[];
+
+    public AndPredicate(Predicate... predicates)
+    {
+        this.predicates = predicates;
+    }
+
+    @Override
+    public boolean match(Node<?> node)
+    {
+        for (Predicate predicate : this.predicates)
+        {
+            if (!predicate.match(node))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AnySelectionPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AnySelectionPredicate.java
new file mode 100644
index 0000000..b8856d0
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/AnySelectionPredicate.java
@@ -0,0 +1,28 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+public class AnySelectionPredicate implements Predicate
+{
+    @Override
+    public boolean match(Node<?> input)
+    {
+        return !input.getSelections().isEmpty();
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaPredicate.java
new file mode 100644
index 0000000..3d6aaee
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaPredicate.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * Predicate against a specific {@link Selection#getCriteria()}
+ */
+public class CriteriaPredicate implements Predicate
+{
+    private final String criteria;
+
+    public CriteriaPredicate(String criteria)
+    {
+        this.criteria = criteria;
+    }
+
+    @Override
+    public boolean match(Node<?> node)
+    {
+        for (Selection selection : node.getSelections())
+        {
+            if (criteria.equalsIgnoreCase(selection.getCriteria()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaSetPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaSetPredicate.java
new file mode 100644
index 0000000..7268f82
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/CriteriaSetPredicate.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Should match against the provided set of {@link Selection#getCriteria()} values.
+ * <p>
+ * Incomplete set is considered to be no-match.
+ */
+public class CriteriaSetPredicate implements Predicate
+{
+    private final Set<String> criteriaSet;
+
+    public CriteriaSetPredicate(String... criterias)
+    {
+        this.criteriaSet = new HashSet<>();
+
+        for (String name : criterias)
+        {
+            this.criteriaSet.add(name);
+        }
+    }
+
+    @Override
+    public boolean match(Node<?> node)
+    {
+        Set<Selection> selections = node.getSelections();
+        if (selections == null)
+        {
+            // empty sources list
+            return false;
+        }
+
+        Set<String> actualCriterias = node.getSelectedCriteriaSet();
+
+        if (actualCriterias.size() != criteriaSet.size())
+        {
+            // non-equal sized set
+            return false;
+        }
+
+        for (String actualCriteria : actualCriterias)
+        {
+            if (!this.criteriaSet.contains(actualCriteria))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Graph.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Graph.java
new file mode 100644
index 0000000..a1341a9
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Graph.java
@@ -0,0 +1,503 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import org.eclipse.jetty.start.Props;
+import org.eclipse.jetty.start.StartLog;
+import org.eclipse.jetty.start.Utils;
+
+/**
+ * Basic Graph
+ * @param <T> the node type
+ */
+public abstract class Graph<T extends Node<T>> implements Iterable<T>
+{
+    private String selectionTerm = "select";
+    private String nodeTerm = "node";
+    private Map<String, T> nodes = new LinkedHashMap<>();
+    private int maxDepth = -1;
+
+    protected Set<String> asNameSet(Set<T> nodeSet)
+    {
+        Set<String> ret = new HashSet<>();
+        for (T node : nodeSet)
+        {
+            ret.add(node.getName());
+        }
+        return ret;
+    }
+
+    private void assertNoCycle(T node, Stack<String> refs)
+    {
+        for (T parent : node.getParentEdges())
+        {
+            if (refs.contains(parent.getName()))
+            {
+                // Cycle detected.
+                StringBuilder err = new StringBuilder();
+                err.append("A cyclic reference in the ");
+                err.append(this.getClass().getSimpleName());
+                err.append(" has been detected: ");
+                for (int i = 0; i < refs.size(); i++)
+                {
+                    if (i > 0)
+                    {
+                        err.append(" -> ");
+                    }
+                    err.append(refs.get(i));
+                }
+                err.append(" -> ").append(parent.getName());
+                throw new IllegalStateException(err.toString());
+            }
+
+            refs.push(parent.getName());
+            assertNoCycle(parent,refs);
+            refs.pop();
+        }
+    }
+
+    private void bfsCalculateDepth(final T node, final int depthNow)
+    {
+        int depth = depthNow + 1;
+
+        // Set depth on every child first
+        for (T child : node.getChildEdges())
+        {
+            child.setDepth(Math.max(depth,child.getDepth()));
+            this.maxDepth = Math.max(this.maxDepth,child.getDepth());
+        }
+
+        // Dive down
+        for (T child : node.getChildEdges())
+        {
+            bfsCalculateDepth(child,depth);
+        }
+    }
+
+    public void buildGraph() throws FileNotFoundException, IOException
+    {
+        // Connect edges
+        // Make a copy of nodes.values() as the list could be modified
+        List<T> nodeList = new ArrayList<>(nodes.values());
+        for (T node : nodeList)
+        {
+            for (String parentName : node.getParentNames())
+            {
+                T parent = get(parentName);
+
+                if (parent == null)
+                {
+                    parent = resolveNode(parentName);
+                }
+
+                if (parent == null)
+                {
+                    if (Props.hasPropertyKey(parentName))
+                    {
+                        StartLog.debug("Module property not expandable (yet) [%s]",parentName);
+                    }
+                    else
+                    {
+                        StartLog.warn("Module not found [%s]",parentName);
+                    }
+                }
+                else
+                {
+                    node.addParentEdge(parent);
+                    parent.addChildEdge(node);
+                }
+            }
+
+            for (String optionalParentName : node.getOptionalParentNames())
+            {
+                T optional = get(optionalParentName);
+                if (optional == null)
+                {
+                    StartLog.debug("Optional module not found [%s]",optionalParentName);
+                }
+                else if (optional.isSelected())
+                {
+                    node.addParentEdge(optional);
+                    optional.addChildEdge(node);
+                }
+            }
+        }
+
+        // Verify there is no cyclic references
+        Stack<String> refs = new Stack<>();
+        for (T module : nodes.values())
+        {
+            refs.push(module.getName());
+            assertNoCycle(module,refs);
+            refs.pop();
+        }
+
+        // Calculate depth of all modules for sorting later
+        for (T module : nodes.values())
+        {
+            if (module.getParentEdges().isEmpty())
+            {
+                bfsCalculateDepth(module,0);
+            }
+        }
+    }
+
+    public boolean containsNode(String name)
+    {
+        return nodes.containsKey(name);
+    }
+
+    public int count()
+    {
+        return nodes.size();
+    }
+
+    public void dumpSelectedTree()
+    {
+        List<T> ordered = new ArrayList<>();
+        ordered.addAll(nodes.values());
+        Collections.sort(ordered,new NodeDepthComparator());
+
+        List<T> active = getSelected();
+
+        for (T module : ordered)
+        {
+            if (active.contains(module))
+            {
+                // Show module name
+                String indent = toIndent(module.getDepth());
+                boolean transitive = module.matches(OnlyTransitivePredicate.INSTANCE);
+                System.out.printf("%s + %s: %s [%s]%n",indent,toCap(nodeTerm),module.getName(),transitive?"transitive":"selected");
+            }
+        }
+    }
+
+    public void dumpSelected()
+    {
+        List<T> ordered = new ArrayList<>();
+        ordered.addAll(nodes.values());
+        Collections.sort(ordered,new NodeDepthComparator());
+
+        List<T> active = getSelected();
+
+        for (T module : ordered)
+        {
+            if (active.contains(module))
+            {
+                // Show module name
+                boolean transitive = module.matches(OnlyTransitivePredicate.INSTANCE);
+                System.out.printf("  %3d) %-15s ",module.getDepth() + 1,module.getName());
+                if (transitive)
+                {
+                    System.out.println("<transitive> ");
+                }
+                else
+                {
+                    List<String> criterias = new ArrayList<>();
+                    for (Selection selection : module.getSelections())
+                    {
+                        if (selection.isExplicit())
+                        {
+                            criterias.add(selection.getCriteria());
+                        }
+                    }
+                    Collections.sort(criterias);
+                    System.out.println(Utils.join(criterias,", "));
+                }
+            }
+        }
+    }
+
+    protected void findChildren(T module, Set<T> ret)
+    {
+        ret.add(module);
+        for (T child : module.getChildEdges())
+        {
+            ret.add(child);
+        }
+    }
+
+    protected void findParents(T module, Map<String, T> ret)
+    {
+        ret.put(module.getName(),module);
+        for (T parent : module.getParentEdges())
+        {
+            ret.put(parent.getName(),parent);
+            findParents(parent,ret);
+        }
+    }
+
+    public T get(String name)
+    {
+        return nodes.get(name);
+    }
+
+    /**
+     * Get the list of Selected nodes.
+     * @return the list of selected nodes
+     */
+    public List<T> getSelected()
+    {
+        return getMatching(new AnySelectionPredicate());
+    }
+
+    /**
+     * Get the Nodes from the tree that match the provided predicate.
+     *
+     * @param predicate
+     *            the way to match nodes
+     * @return the list of matching nodes in execution order.
+     */
+    public List<T> getMatching(Predicate predicate)
+    {
+        List<T> selected = new ArrayList<T>();
+
+        for (T node : nodes.values())
+        {
+            if (predicate.match(node))
+            {
+                selected.add(node);
+            }
+        }
+
+        Collections.sort(selected,new NodeDepthComparator());
+        return selected;
+    }
+
+    public int getMaxDepth()
+    {
+        return maxDepth;
+    }
+
+    public Set<T> getModulesAtDepth(int depth)
+    {
+        Set<T> ret = new HashSet<>();
+        for (T node : nodes.values())
+        {
+            if (node.getDepth() == depth)
+            {
+                ret.add(node);
+            }
+        }
+        return ret;
+    }
+
+    public Collection<String> getNodeNames()
+    {
+        return nodes.keySet();
+    }
+
+    public Collection<T> getNodes()
+    {
+        return nodes.values();
+    }
+
+    public String getNodeTerm()
+    {
+        return nodeTerm;
+    }
+
+    public String getSelectionTerm()
+    {
+        return selectionTerm;
+    }
+
+    @Override
+    public Iterator<T> iterator()
+    {
+        return nodes.values().iterator();
+    }
+
+    public abstract void onNodeSelected(T node);
+
+    public T register(T node)
+    {
+        StartLog.debug("Registering Node: [%s] %s",node.getName(),node);
+        nodes.put(node.getName(),node);
+        return node;
+    }
+
+    public Set<String> resolveChildNodesOf(String nodeName)
+    {
+        Set<T> ret = new HashSet<>();
+        T module = get(nodeName);
+        findChildren(module,ret);
+        return asNameSet(ret);
+    }
+
+    /**
+     * Resolve a node just in time.
+     * <p>
+     * Useful for nodes that are virtual/transient in nature (such as the jsp/jstl/alpn modules)
+     * @param name the name of the node to resolve
+     * @return the node
+     */
+    public abstract T resolveNode(String name);
+
+    public Set<String> resolveParentModulesOf(String nodeName)
+    {
+        Map<String, T> ret = new HashMap<>();
+        T node = get(nodeName);
+        findParents(node,ret);
+        return ret.keySet();
+    }
+
+    public int selectNode(Predicate nodePredicate, Selection selection)
+    {
+        int count = 0;
+        List<T> matches = getMatching(nodePredicate);
+        if (matches.isEmpty())
+        {
+            StringBuilder err = new StringBuilder();
+            err.append("WARNING: Cannot ").append(selectionTerm);
+            err.append(" requested ").append(nodeTerm);
+            err.append("s.  ").append(nodePredicate);
+            err.append(" returned no matches.");
+            StartLog.warn(err.toString());
+            return count;
+        }
+
+        // select them
+        for (T node : matches)
+        {
+            count += selectNode(node,selection);
+        }
+
+        return count;
+    }
+
+    public int selectNode(String name, Selection selection)
+    {
+        int count = 0;
+        T node = get(name);
+        if (node == null)
+        {
+            StringBuilder err = new StringBuilder();
+            err.append("Cannot ").append(selectionTerm);
+            err.append(" requested ").append(nodeTerm);
+            err.append(" [").append(name).append("]: not a valid ");
+            err.append(nodeTerm).append(" name.");
+            StartLog.warn(err.toString());
+            return count;
+        }
+
+        count += selectNode(node,selection);
+
+        return count;
+    }
+
+    private int selectNode(T node, Selection selection)
+    {
+        int count = 0;
+
+        if (node.getSelections().contains(selection))
+        {
+            // Already enabled with this selection.
+            return count;
+        }
+
+        StartLog.debug("%s %s: %s (via %s)",toCap(selectionTerm),nodeTerm,node.getName(),selection);
+
+        boolean newlySelected = node.getSelections().isEmpty();
+
+        // Add self
+        node.addSelection(selection);
+        if (newlySelected)
+        {
+            onNodeSelected(node);
+        }
+        count++;
+
+        // Walk transitive
+        Selection transitive = selection.asTransitive();
+        List<String> parentNames = new ArrayList<>();
+        parentNames.addAll(node.getParentNames());
+
+        count += selectNodes(parentNames,transitive);
+
+        return count;
+    }
+
+    public int selectNodes(Collection<String> names, Selection selection)
+    {
+        StartLog.debug("%s [%s] (via %s)",toCap(selectionTerm),Utils.join(names,", "),selection);
+
+        int count = 0;
+
+        for (String name : names)
+        {
+            T node = get(name);
+            // Node doesn't exist yet (try to resolve it it just-in-time)
+            if (node == null)
+            {
+                StartLog.debug("resolving node [%s]",name);
+                node = resolveNode(name);
+            }
+            // Node still doesn't exist? this is now an invalid graph.
+            if (node == null)
+            {
+                throw new GraphException("Missing referenced dependency: " + name);
+            }
+
+            count += selectNode(node.getName(),selection);
+        }
+
+        return count;
+    }
+
+    public void setNodeTerm(String nodeTerm)
+    {
+        this.nodeTerm = nodeTerm;
+    }
+
+    public void setSelectionTerm(String selectionTerm)
+    {
+        this.selectionTerm = selectionTerm;
+    }
+
+    private String toCap(String str)
+    {
+        StringBuilder cap = new StringBuilder();
+        cap.append(Character.toUpperCase(str.charAt(0)));
+        cap.append(str.substring(1));
+        return cap.toString();
+    }
+
+    private String toIndent(int depth)
+    {
+        char indent[] = new char[depth * 2];
+        Arrays.fill(indent,' ');
+        return new String(indent);
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/GraphException.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/GraphException.java
new file mode 100644
index 0000000..de1c920
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/GraphException.java
@@ -0,0 +1,36 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * A non-recoverable graph exception
+ */
+@SuppressWarnings("serial")
+public class GraphException extends RuntimeException
+{
+    public GraphException(String message, Throwable cause)
+    {
+        super(message,cause);
+    }
+
+    public GraphException(String message)
+    {
+        super(message);
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NamePredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NamePredicate.java
new file mode 100644
index 0000000..0eb741d
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NamePredicate.java
@@ -0,0 +1,35 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+public class NamePredicate implements Predicate
+{
+    private final String name;
+    
+    public NamePredicate(String name)
+    {
+        this.name = name;
+    }
+    
+    @Override
+    public boolean match(Node<?> input)
+    {
+        return input.getName().equalsIgnoreCase(this.name);
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Node.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Node.java
new file mode 100644
index 0000000..f1835d3
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Node.java
@@ -0,0 +1,179 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Basic Graph Node
+ * @param <T> the node type
+ */
+public abstract class Node<T>
+{
+    /** The logical name of this Node */
+    private String logicalName;
+    /** The depth of the Node in the tree */
+    private int depth = 0;
+    /** The set of selections for how this node was selected */
+    private Set<Selection> selections = new LinkedHashSet<>();
+    /** Set of Nodes, by name, that this Node depends on */
+    private List<String> parentNames = new ArrayList<>();
+    /** Set of Nodes, by name, that this Node optionally depend on */
+    private List<String> optionalParentNames = new ArrayList<>();
+
+    /** The Edges to parent Nodes */
+    private Set<T> parentEdges = new LinkedHashSet<>();
+    /** The Edges to child Nodes */
+    private Set<T> childEdges = new LinkedHashSet<>();
+
+    public void addChildEdge(T child)
+    {
+        if (childEdges.contains(child))
+        {
+            // already present, skip
+            return;
+        }
+        this.childEdges.add(child);
+    }
+
+    public void addOptionalParentName(String name)
+    {
+        if (this.optionalParentNames.contains(name))
+        {
+            // skip, name already exists
+            return;
+        }
+        this.optionalParentNames.add(name);
+    }
+
+    public void addParentEdge(T parent)
+    {
+        if (parentEdges.contains(parent))
+        {
+            // already present, skip
+            return;
+        }
+        this.parentEdges.add(parent);
+    }
+
+    public void addParentName(String name)
+    {
+        if (this.parentNames.contains(name))
+        {
+            // skip, name already exists
+            return;
+        }
+        this.parentNames.add(name);
+    }
+
+    public void addSelection(Selection selection)
+    {
+        this.selections.add(selection);
+    }
+
+    public Set<T> getChildEdges()
+    {
+        return childEdges;
+    }
+
+    public int getDepth()
+    {
+        return depth;
+    }
+
+    @Deprecated
+    public String getLogicalName()
+    {
+        return logicalName;
+    }
+
+    public String getName()
+    {
+        return logicalName;
+    }
+
+    public List<String> getOptionalParentNames()
+    {
+        return optionalParentNames;
+    }
+
+    public Set<T> getParentEdges()
+    {
+        return parentEdges;
+    }
+
+    public List<String> getParentNames()
+    {
+        return parentNames;
+    }
+
+    public Set<Selection> getSelections()
+    {
+        return selections;
+    }
+
+    public Set<String> getSelectedCriteriaSet()
+    {
+        Set<String> criteriaSet = new HashSet<>();
+        for (Selection selection : selections)
+        {
+            criteriaSet.add(selection.getCriteria());
+        }
+        return criteriaSet;
+    }
+
+    public boolean isSelected()
+    {
+        return !selections.isEmpty();
+    }
+
+    public boolean matches(Predicate predicate)
+    {
+        return predicate.match(this);
+    }
+
+    public void setDepth(int depth)
+    {
+        this.depth = depth;
+    }
+
+    public void setName(String name)
+    {
+        this.logicalName = name;
+    }
+
+    public void setParentNames(List<String> parents)
+    {
+        this.parentNames.clear();
+        this.parentEdges.clear();
+        if (parents != null)
+        {
+            this.parentNames.addAll(parents);
+        }
+    }
+
+    public void setSelections(Set<Selection> selection)
+    {
+        this.selections = selection;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NodeDepthComparator.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NodeDepthComparator.java
new file mode 100644
index 0000000..8b2b373
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/NodeDepthComparator.java
@@ -0,0 +1,43 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+import java.text.CollationKey;
+import java.text.Collator;
+import java.util.Comparator;
+
+public class NodeDepthComparator implements Comparator<Node<?>>
+{
+    private Collator collator = Collator.getInstance();
+
+    @Override
+    public int compare(Node<?> o1, Node<?> o2)
+    {
+        // order by depth first.
+        int diff = o1.getDepth() - o2.getDepth();
+        if (diff != 0)
+        {
+            return diff;
+        }
+        // then by name (not really needed, but makes for predictable test cases)
+        CollationKey k1 = collator.getCollationKey(o1.getName());
+        CollationKey k2 = collator.getCollationKey(o2.getName());
+        return k1.compareTo(k2);
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/OnlyTransitivePredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/OnlyTransitivePredicate.java
new file mode 100644
index 0000000..df0ecdf
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/OnlyTransitivePredicate.java
@@ -0,0 +1,41 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * Predicate for a node that has no explicitly set selections.
+ * (They are all transitive)
+ */
+public class OnlyTransitivePredicate implements Predicate
+{
+    public static final Predicate INSTANCE = new OnlyTransitivePredicate();
+    
+    @Override
+    public boolean match(Node<?> input)
+    {
+        for (Selection selection : input.getSelections())
+        {
+            if (selection.isExplicit())
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Predicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Predicate.java
new file mode 100644
index 0000000..0f974cd
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Predicate.java
@@ -0,0 +1,27 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * Matcher of Nodes
+ */
+public interface Predicate
+{
+    public boolean match(Node<?> input);
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/RegexNamePredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/RegexNamePredicate.java
new file mode 100644
index 0000000..a6c2fde
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/RegexNamePredicate.java
@@ -0,0 +1,40 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+import java.util.regex.Pattern;
+
+/**
+ * Match a node based on name
+ */
+public class RegexNamePredicate implements Predicate
+{
+    private final Pattern pat;
+
+    public RegexNamePredicate(String regex)
+    {
+        this.pat = Pattern.compile(regex);
+    }
+
+    @Override
+    public boolean match(Node<?> node)
+    {
+        return pat.matcher(node.getName()).matches();
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Selection.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Selection.java
new file mode 100644
index 0000000..d7de381
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/Selection.java
@@ -0,0 +1,129 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.start.graph;
+
+/**
+ * Represents a selection criteria.
+ * <p>
+ * Each <code>Selection</code> can be used [0..n] times in the graph. The <code>Selection</code> must contain a unique
+ * 'criteria' description that how selection was determined.
+ */
+public class Selection
+{
+    private final boolean explicit;
+    private final String criteria;
+
+    public Selection(String criteria)
+    {
+        this(criteria,true);
+    }
+
+    /**
+     * The Selection criteria
+     * 
+     * @param criteria
+     *            the selection criteria
+     * @param explicit
+     *            true if explicitly selected, false if transitively selected.
+     */
+    public Selection(String criteria, boolean explicit)
+    {
+        this.criteria = criteria;
+        this.explicit = explicit;
+    }
+
+    public Selection asTransitive()
+    {
+        if (this.explicit)
+        {
+            return new Selection(criteria,false);
+        }
+        return this;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        Selection other = (Selection)obj;
+        if (explicit != other.explicit)
+        {
+            return false;
+        }
+        if (criteria == null)
+        {
+            if (other.criteria != null)
+            {
+                return false;
+            }
+        }
+        else if (!criteria.equals(other.criteria))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get the criteria for this selection
+     * @return the criteria
+     */
+    public String getCriteria()
+    {
+        return criteria;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + (explicit ? 1231 : 1237);
+        result = (prime * result) + ((criteria == null) ? 0 : criteria.hashCode());
+        return result;
+    }
+
+    public boolean isExplicit()
+    {
+        return explicit;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder str = new StringBuilder();
+        if (!explicit)
+        {
+            str.append("<transitive from> ");
+        }
+        str.append(criteria);
+        return str.toString();
+    }
+}
diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/graph/UniqueCriteriaPredicate.java b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/UniqueCriteriaPredicate.java
new file mode 100644
index 0000000..075bd21
--- /dev/null
+++ b/jetty-start/src/main/java/org/eclipse/jetty/start/graph/UniqueCriteriaPredicate.java
@@ -0,0 +1,63 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.graph;
+
+/**
+ * Match against a specific {@link Selection#getCriteria()}, where
+ * there are no other {@link Selection#isExplicit()} specified.
+ */
+public class UniqueCriteriaPredicate implements Predicate
+{
+    private final String criteria;
+
+    public UniqueCriteriaPredicate(String criteria)
+    {
+        this.criteria = criteria;
+    }
+
+    @Override
+    public boolean match(Node<?> node)
+    {
+        if (node.getSelections().isEmpty())
+        {
+            // Empty selection list (no uniqueness to it)
+            return false;
+        }
+        
+        // Assume no match
+        boolean ret = false;
+        
+        for (Selection selection : node.getSelections())
+        {
+            if (criteria.equalsIgnoreCase(selection.getCriteria()))
+            {
+                // Found a match
+                ret = true;
+                continue; // this criteria is always valid.
+            }
+            else if (selection.isExplicit())
+            {
+                // Automatic failure
+                return false;
+            }
+        }
+
+        return ret;
+    }
+}
\ No newline at end of file
diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/base-home-warning.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/base-home-warning.txt
deleted file mode 100644
index a34bfdb..0000000
--- a/jetty-start/src/main/resources/org/eclipse/jetty/start/base-home-warning.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-============================================================================
-WARNING: Jetty is starting using LEGACY behavior. 
-
-A proper {jetty.base} should be configured with no changes being made to the {jetty.home} directory.
-
-Please see http://www.eclipse.org/jetty/documentation/current/startup.html
-
-A demo-base directory has been provided as an example of this setup.
-
-  $ cd demo-base
-  $ java -jar ../start.jar
-
-This warning may be disabled by setting the system property
-
-  -Dorg.eclipse.jetty.start.home.warning=false
-============================================================================
diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt
index eacb16b..413160b 100644
--- a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt
+++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt
@@ -34,7 +34,12 @@
                    a sub process. This can be used when start.ini
                    contains -X or -D arguments, but creates an extra
                    JVM instance.
-
+                   
+  --exec-properties=<filename>
+                   Assign a fixed name to the file used to transfer 
+                   properties to the sub process. This allows the 
+                   generated properties file to be saved and reused.
+                   Without this option, a temporary file is used.
 
 Debug and Start Logging:
 ------------------------
@@ -67,7 +72,7 @@
                    Temporarily enable a module from the command line.
                    Note: this can also be used in the ${jetty.base}/start.ini
                    or ${jetty.base}/start.d/*.ini files.
-
+                   
   --add-to-start=<modulename>(,<modulename>)*
                    Enable a module by appending lines to the
                    ${jetty.base}/start.ini file.
@@ -94,10 +99,25 @@
                    See http://graphviz.org/ for details on how to post-process
                    this file into the output best suited for your needs.
                    
-  --create-files   Create any missing files that are required by initialised 
+  --create-files   Create any missing files that are required by initialized 
                    modules.  This may download a file from the network if the 
                    module provides a URL.
 
+  --skip-file-validation=<modulename>(,<modulename)*
+                   Disable the [files] section validation of content
+                   in the ${jetty.base} directory for a specific
+                   module.  Useful for modules that have downloadable
+                   content that is being overridden with alternatives
+                   in the ${jetty.base} directory.
+                   CAUTION: 
+                     This advanced option is for administrators that
+                     fully understand the configuration of their
+                     ${jetty.base} and are willing to forego some of the
+                     safety checks built into the jetty-start mechanism.
+                     
+  --approve-all-licenses
+                   Approve all license questions. Useful for enabling 
+                   modules from a script that does not require user interaction.
 
 Startup / Shutdown Command Line:
 --------------------------------
@@ -118,7 +138,7 @@
 
     STOP.KEY=[alphanumeric]
       The passphrase defined to stop the server.
-      Requried along with STOP.PORT if you want to use the --stop option above.
+      Required along with STOP.PORT if you want to use the --stop option above.
 
     STOP.WAIT=[number]
       The time (in seconds) to wait for confirmation that the running
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
index 37b947f..876ed4e 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/BaseHomeTest.java
@@ -18,7 +18,10 @@
 

 package org.eclipse.jetty.start;

 

-import static org.hamcrest.Matchers.*;

+import static org.hamcrest.Matchers.containsInAnyOrder;

+import static org.hamcrest.Matchers.containsString;

+import static org.hamcrest.Matchers.notNullValue;

+import static org.hamcrest.Matchers.startsWith;

 

 import java.io.File;

 import java.io.IOException;

@@ -57,7 +60,7 @@
                 System.out.printf(" %s%n",path);

             }

         }

-        Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

+        Assert.assertThat(message + ": " + Utils.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

     }

     

     public static void assertPathList(BaseHome hb, String message, List<String> expected, List<Path> paths)

@@ -81,7 +84,7 @@
                 System.out.printf(" %s%n",path);

             }

         }

-        Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

+        Assert.assertThat(message + ": " + Utils.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

     }

 

     public static void assertFileList(BaseHome hb, String message, List<String> expected, List<File> files)

@@ -91,7 +94,7 @@
         {

             actual.add(hb.toShortForm(file));

         }

-        Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

+        Assert.assertThat(message + ": " + Utils.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));

     }

 

     @Test

diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
index c674497..fa824d3 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ConfigurationAssert.java
@@ -18,7 +18,8 @@
 

 package org.eclipse.jetty.start;

 

-import static org.hamcrest.Matchers.*;

+import static org.hamcrest.Matchers.greaterThan;

+import static org.hamcrest.Matchers.greaterThanOrEqualTo;

 

 import java.io.File;

 import java.io.FileNotFoundException;

@@ -47,11 +48,12 @@
      *            the StartArgs that has been processed via {@link Main#processCommandLine(String[])}

      * @param filename

      *            the filename of the assertion values

-     * @throws IOException

+     * @throws FileNotFoundException if unable to find the configuration

+     * @throws IOException if unable to process the configuration

      */

     public static void assertConfiguration(BaseHome baseHome, StartArgs args, String filename) throws FileNotFoundException, IOException

     {

-        Path testResourcesDir = MavenTestingUtils.getTestResourcesDir().toPath().toAbsolutePath();

+        Path testResourcesDir = MavenTestingUtils.getTestResourcesDir().toPath().toRealPath();

         File file = MavenTestingUtils.getTestResourceFile(filename);

         TextFile textFile = new TextFile(file.toPath());

 

@@ -101,7 +103,8 @@
         {

             String name = prop.key;

             if ("jetty.home".equals(name) || "jetty.base".equals(name) ||

-                "user.dir".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP))

+                "user.dir".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP) ||

+                name.startsWith("java."))

             {

                 // strip these out from assertion, to make assertions easier.

                 continue;

diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/DistTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/DistTest.java
new file mode 100644
index 0000000..5f1c18c
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/DistTest.java
@@ -0,0 +1,211 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import static org.eclipse.jetty.start.StartMatchers.fileExists;
+import static org.eclipse.jetty.start.StartMatchers.notPathExists;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test various things with a semi-valid src/test/resources/dist-home/
+ */
+public class DistTest
+{
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
+    @Rule
+    public SystemExitAsException exitrule = new SystemExitAsException();
+
+    private void execMain(List<String> cmds) throws Exception
+    {
+        int len = cmds.size();
+        String args[] = cmds.toArray(new String[len]);
+
+        Main main = new Main();
+        StartArgs startArgs = main.processCommandLine(args);
+        main.start(startArgs);
+    }
+
+    public List<String> getBaseCommandLine(Path basePath)
+    {
+        List<String> cmds = new ArrayList<String>();
+        cmds.add("-Djava.io.tmpdir=" + MavenTestingUtils.getTargetDir().getAbsolutePath());
+        cmds.add("-Djetty.home=" + MavenTestingUtils.getTestResourceDir("dist-home").getAbsolutePath());
+        cmds.add("-Djetty.base=" + basePath.normalize().toAbsolutePath().toString());
+        cmds.add("--testing-mode");
+
+        return cmds;
+    }
+
+    @Test
+    public void testLikeDistro_SetupHome() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("--add-to-start=deploy,websocket,ext,resources,jsp,jstl,http");
+
+        execMain(cmds);
+    }
+    
+    @Test
+    public void testAddJstl() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-start=jstl");
+        execMain(cmds);
+        
+        Path startIni = basePath.resolve("start.ini");
+        assertThat("start.ini", startIni, fileExists());
+
+        List<String> startIniLines = new TextFile(startIni).getLines();
+        // Modules that should be present
+        assertThat("start.ini", startIniLines, hasItem("--module=jstl"));
+        assertThat("start.ini", startIniLines, hasItem("--module=server"));
+        
+        // Test for modules that should not be present.
+        // Namely modules that are transitive and without ini-template.
+        assertThat("start.ini", startIniLines, not(hasItem("--module=servlet")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=apache-jsp")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=apache-jstl")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=jndi")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=security")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=webapp")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=plus")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=annotations")));
+        assertThat("start.ini", startIniLines, not(hasItem("--module=jsp")));
+        
+    }
+    
+    /**
+     * Test for https://bugs.eclipse.org/452329
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testReAddServerModule() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-startd=http");
+        execMain(cmds);
+        
+        Path httpIni = basePath.resolve("start.d/http.ini");
+        Path serverIni = basePath.resolve("start.d/server.ini");
+        
+        assertThat("start.d/http.ini", httpIni, fileExists());
+        assertThat("start.d/server.ini", serverIni, fileExists());
+        
+        // Delete server.ini
+        Files.deleteIfExists(serverIni);
+        
+        // Attempt to re-add via 'server' module reference
+        cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-startd=server");
+        execMain(cmds);
+        
+        assertThat("start.d/server.ini", serverIni, fileExists());
+    }
+    
+    /**
+     * Test for https://bugs.eclipse.org/452329
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testReAddServerViaHttpModule() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-startd=http");
+        execMain(cmds);
+        
+        Path httpIni = basePath.resolve("start.d/http.ini");
+        Path serverIni = basePath.resolve("start.d/server.ini");
+        
+        assertThat("start.d/http.ini", httpIni, fileExists());
+        assertThat("start.d/server.ini", serverIni, fileExists());
+        
+        // Delete server.ini
+        Files.deleteIfExists(serverIni);
+        
+        // Attempt to re-add via 'http' module reference
+        cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-startd=http");
+        execMain(cmds);
+        
+        assertThat("start.d/server.ini", serverIni, fileExists());
+    }
+    
+    /**
+     * Test for https://bugs.eclipse.org/452329
+     * @throws Exception on test failure
+     */
+    @Test
+    public void testReAddHttpThenDeployViaStartD() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-start=http");
+        execMain(cmds);
+        
+        Path startIni = basePath.resolve("start.ini");
+        assertThat("start.ini", startIni, fileExists());
+
+        // Now add 'deploy' module.
+        cmds = getBaseCommandLine(basePath);
+        cmds.add("--add-to-startd=deploy");
+        execMain(cmds);
+        
+        // The following files should not exist (as its already defined in /start.ini)
+        Path serverIni = basePath.resolve("start.d/server.ini");
+        assertThat("start.d/server.ini", serverIni, notPathExists());
+    }
+    
+    @Test
+    @Ignore("See https://bugs.eclipse.org/451973")
+    public void testLikeDistro_SetupDemoBase() throws Exception
+    {
+        Path basePath = testdir.getEmptyDir().toPath();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("--add-to-start=continuation,deploy,websocket,ext,resources,client,annotations,jndi,servlets");
+        cmds.add("--add-to-startd=jsp,jstl,http,https");
+
+        execMain(cmds);
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java
index eaf97e2..3274b38 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/FSTest.java
@@ -50,6 +50,7 @@
     
     /**
      * Utility method used by other test cases
+     * @param expected the expected String paths to be converted (in place)
      */
     public static void toOsSeparators(List<String> expected)
     {
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/FileArgTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/FileArgTest.java
index ae2e7c9..0449892 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/FileArgTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/FileArgTest.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/IncludeJettyDirTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/IncludeJettyDirTest.java
index 0f2d3d3..4c80404 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/IncludeJettyDirTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/IncludeJettyDirTest.java
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
@@ -34,6 +32,10 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
 public class IncludeJettyDirTest
 {
     private static class MainResult
@@ -89,13 +91,13 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         // Simple command line - no reference to include-jetty-dirs
         MainResult result = runMain(base,home);
@@ -105,7 +107,7 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
+        result.assertProperty("jetty.http.host","127.0.0.1");
     }
 
     @Test
@@ -114,18 +116,18 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         // Simple command line reference to include-jetty-dir
         MainResult result = runMain(base,home,
@@ -138,8 +140,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -148,18 +150,18 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         // Simple command line reference to include-jetty-dir via property (also on command line)
         MainResult result = runMain(base,home,
@@ -174,8 +176,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -184,7 +186,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create opt
         File opt = testdir.getFile("opt");
@@ -193,13 +195,13 @@
         // Create common
         File common = new File(opt,"common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         String dirRef = "${my.opt}" + File.separator + "common";
 
@@ -216,8 +218,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -226,7 +228,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create opt
         File opt = testdir.getFile("opt");
@@ -235,13 +237,13 @@
         // Create common
         File common = new File(opt,"common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         String dirRef = "${my.opt}" + File.separator + "${my.dir}";
 
@@ -260,8 +262,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -270,18 +272,18 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         MainResult result = runMain(base,home);
@@ -292,8 +294,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -302,12 +304,12 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create corp
         File corp = testdir.getFile("corp");
@@ -317,7 +319,7 @@
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath(), //
                 "--include-jetty-dir=" + corp.getAbsolutePath());
 
@@ -330,8 +332,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -340,25 +342,25 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
-        TestEnv.makeFile(corp,"start.ini","jetty.port=9090");
+        TestEnv.makeFile(corp,"start.ini","jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         MainResult result = runMain(base,home);
@@ -370,8 +372,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -380,13 +382,13 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
@@ -394,13 +396,13 @@
         TestEnv.makeFile(common,"start.ini", //
                 "my.corp=" + corp.getAbsolutePath(), //
                 "--include-jetty-dir=${my.corp}", //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "my.common=" + common.getAbsolutePath(), //
                 "--include-jetty-dir=${my.common}");
 
@@ -413,8 +415,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","8080"); // from 'common'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -423,33 +425,33 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create devops
         File devops = testdir.getFile("devops");
         FS.ensureEmpty(devops);
         TestEnv.makeFile(devops,"start.ini", //
                 "--module=logging", //
-                "jetty.port=2222");
+                "jetty.http.port=2222");
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         MainResult result = runMain(base,home,
@@ -464,8 +466,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","2222"); // from 'devops'
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","2222"); // from 'devops'
     }
 
     @Test
@@ -474,31 +476,31 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         MainResult result = runMain(base,home,
         // command line property should override all others
-                "jetty.port=7070");
+                "jetty.http.port=7070");
 
         List<String> expectedSearchOrder = new ArrayList<>();
         expectedSearchOrder.add("${jetty.base}");
@@ -507,8 +509,8 @@
         expectedSearchOrder.add("${jetty.home}");
         result.assertSearchOrder(expectedSearchOrder);
 
-        result.assertProperty("jetty.host","127.0.0.1");
-        result.assertProperty("jetty.port","7070"); // from command line
+        result.assertProperty("jetty.http.host","127.0.0.1");
+        result.assertProperty("jetty.http.port","7070"); // from command line
     }
 
     @Test
@@ -517,7 +519,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
@@ -528,14 +530,14 @@
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini",
         // standard property
-                "jetty.port=9090",
+                "jetty.http.port=9090",
                 // INTENTIONAL BAD Reference (duplicate)
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         // Populate common
         TestEnv.makeFile(common,"start.ini",
         // standard property
-                "jetty.port=8080",
+                "jetty.http.port=8080",
                 // reference to corp
                 "--include-jetty-dir=" + corp.getAbsolutePath());
 
@@ -543,7 +545,7 @@
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         try
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/JarVersionTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/JarVersionTest.java
index fcff954..e39475c 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/JarVersionTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/JarVersionTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
 
 import java.io.File;
 
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/LicenseTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/LicenseTest.java
deleted file mode 100644
index 47732a1..0000000
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/LicenseTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.start;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.toolchain.test.OS;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.junit.Rule;
-import org.junit.Test;
-
-/**
- * Test various license handling.
- */
-public class LicenseTest
-{
-    @Rule
-    public TestingDir testdir = new TestingDir();
-
-    @Rule
-    public SystemExitAsException exitrule = new SystemExitAsException();
-
-    private String assertFileExists(File basePath, String name) throws IOException
-    {
-        File file = new File(basePath, OS.separators(name));
-        FS.exists(file.toPath());
-        return IO.readToString(file);
-    }
-
-    private void execMain(List<String> cmds) throws Exception
-    {
-        int len = cmds.size();
-        String args[] = cmds.toArray(new String[len]);
-
-        System.err.printf("%n## Exec: %s%n", Main.join(cmds,", "));
-        Main main = new Main();
-        StartArgs startArgs = main.processCommandLine(args);
-        main.start(startArgs);
-    }
-
-    public List<String> getBaseCommandLine(File basePath)
-    {
-        List<String> cmds = new ArrayList<String>();
-        cmds.add("-Djava.io.tmpdir=" + MavenTestingUtils.getTargetDir().getAbsolutePath());
-        cmds.add("-Djetty.home=" + MavenTestingUtils.getTestResourceDir("dist-home").getAbsolutePath());
-        cmds.add("-Djetty.base=" + basePath.getAbsolutePath());
-        cmds.add("--testing-mode");
-
-        return cmds;
-    }
-
-    @Test
-    public void testAdd_NoLicensed() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("--add-to-start=http,deploy");
-
-        execMain(cmds);
-    }
-
-    @Test
-    public void testAdd_CDI_Licensed() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("-Dorg.eclipse.jetty.start.ack.license.cdi=true");
-        cmds.add("--add-to-start=cdi");
-
-        execMain(cmds);
-    }
-    
-    @Test
-    public void testAdd_SPDY_Licensed() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("-Dorg.eclipse.jetty.start.ack.license.protonego-impl=true");
-        cmds.add("--add-to-start=spdy");
-
-        execMain(cmds);
-        
-        String contents = assertFileExists(basePath, "start.ini");
-        assertThat("Contents",contents,containsString("--module=spdy"+System.lineSeparator()));
-    }
-    
-    @Test
-    public void testAdd_HttpSpdy_Then_Deploy() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("-Dorg.eclipse.jetty.start.ack.license.protonego-impl=true");
-        cmds.add("--add-to-start=http,spdy");
-
-        execMain(cmds);
-        
-        String contents = assertFileExists(basePath, "start.ini");
-        assertThat("Contents",contents,containsString("--module=http"+System.lineSeparator()));
-        assertThat("Contents",contents,containsString("--module=spdy"+System.lineSeparator()));
-        
-        // now request deploy (no license check should occur)
-        List<String> cmds2 = getBaseCommandLine(basePath);
-        cmds2.add("--add-to-start=deploy");
-        execMain(cmds2);
-
-        contents = assertFileExists(basePath, "start.ini");
-        assertThat("Contents",contents,containsString("--module=deploy"+System.lineSeparator()));
-        assertThat("Contents",contents,containsString("--module=spdy"+System.lineSeparator()));
-    }
-    
-    @Test
-    public void testCreate_SPDY_Licensed() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("-Dorg.eclipse.jetty.start.ack.license.protonego-impl=true");
-        
-        StringReader startIni = new StringReader("--module=spdy\n");
-        try (FileWriter writer = new FileWriter(new File(basePath,"start.ini")))
-        {
-            IO.copy(startIni,writer);
-        }
-
-        execMain(cmds);
-    }
-
-    @Test
-    public void testCreate_CDI_Licensed() throws Exception
-    {
-        File basePath = testdir.getEmptyDir();
-
-        List<String> cmds = getBaseCommandLine(basePath);
-
-        cmds.add("-Dorg.eclipse.jetty.start.ack.license.cdi=true");
-        cmds.add("--create-files");
-
-        StringReader startIni = new StringReader("--module=cdi\n");
-        try (FileWriter writer = new FileWriter(new File(basePath,"start.ini")))
-        {
-            IO.copy(startIni,writer);
-        }
-
-        execMain(cmds);
-    }
-}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/LicensingTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/LicensingTest.java
new file mode 100644
index 0000000..5cd7d6a
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/LicensingTest.java
@@ -0,0 +1,181 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.IO;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.OS;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test various license handling.
+ */
+public class LicensingTest
+{
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
+    @Rule
+    public SystemExitAsException exitrule = new SystemExitAsException();
+
+    private String assertFileExists(File basePath, String name) throws IOException
+    {
+        File file = new File(basePath, OS.separators(name));
+        FS.exists(file.toPath());
+        return IO.readToString(file);
+    }
+
+    private void execMain(List<String> cmds) throws Exception
+    {
+        int len = cmds.size();
+        String args[] = cmds.toArray(new String[len]);
+
+        System.err.printf("%n## Exec: %s%n", Utils.join(cmds,", "));
+        Main main = new Main();
+        StartArgs startArgs = main.processCommandLine(args);
+        main.start(startArgs);
+    }
+
+    public List<String> getBaseCommandLine(File basePath)
+    {
+        List<String> cmds = new ArrayList<String>();
+        cmds.add("-Djava.io.tmpdir=" + MavenTestingUtils.getTargetDir().getAbsolutePath());
+        cmds.add("-Djetty.home=" + MavenTestingUtils.getTestResourceDir("dist-home").getAbsolutePath());
+        cmds.add("-Djetty.base=" + basePath.getAbsolutePath());
+        cmds.add("--testing-mode");
+
+        return cmds;
+    }
+
+    @Test
+    public void testAdd_NoLicensed() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("--add-to-start=http,deploy");
+
+        execMain(cmds);
+    }
+
+    @Test
+    public void testAdd_CDI_Licensed() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("-Dorg.eclipse.jetty.start.ack.licenses=true");
+        cmds.add("--add-to-start=cdi");
+
+        execMain(cmds);
+    }
+    
+    @Test
+    public void testAdd_HTTP2_Licensed() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("-Dorg.eclipse.jetty.start.ack.licenses=true");
+        cmds.add("--add-to-start=http2");
+
+        execMain(cmds);
+        
+        String contents = assertFileExists(basePath, "start.ini");
+        assertThat("Contents",contents,containsString("--module=http2"+System.lineSeparator()));
+    }
+    
+    @Test
+    public void testAdd_Http_Http2_Then_Deploy() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("-Dorg.eclipse.jetty.start.ack.license.protonego-impl=true");
+        cmds.add("--add-to-start=http,http2");
+
+        execMain(cmds);
+        
+        String contents = assertFileExists(basePath, "start.ini");
+        assertThat("Contents",contents,containsString("--module=http"+System.lineSeparator()));
+        assertThat("Contents",contents,containsString("--module=http2"+System.lineSeparator()));
+        
+        // now request deploy (no license check should occur)
+        List<String> cmds2 = getBaseCommandLine(basePath);
+        cmds2.add("--add-to-start=deploy");
+        execMain(cmds2);
+
+        contents = assertFileExists(basePath, "start.ini");
+        assertThat("Contents",contents,containsString("--module=deploy"+System.lineSeparator()));
+    }
+    
+    @Test
+    public void testCreate_HTTP2_Licensed() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("-Dorg.eclipse.jetty.start.ack.licenses=true");
+        cmds.add("--dry-run");
+        
+        StringReader startIni = new StringReader("--module=http2\n");
+        try (FileWriter writer = new FileWriter(new File(basePath,"start.ini")))
+        {
+            IO.copy(startIni,writer);
+        }
+
+        execMain(cmds);
+    }
+
+    @Test
+    public void testCreate_CDI_Licensed() throws Exception
+    {
+        File basePath = testdir.getEmptyDir();
+
+        List<String> cmds = getBaseCommandLine(basePath);
+
+        cmds.add("-Dorg.eclipse.jetty.start.ack.licenses=true");
+        cmds.add("--create-files");
+
+        StringReader startIni = new StringReader("--module=cdi\n");
+        try (FileWriter writer = new FileWriter(new File(basePath,"start.ini")))
+        {
+            IO.copy(startIni,writer);
+        }
+
+        execMain(cmds);
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
index 14e714e..fdb0558 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
@@ -50,10 +50,10 @@
     public void testBasicProcessing() throws Exception
     {
         List<String> cmdLineArgs = new ArrayList<>();
-        File testJettyHome = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
+        Path testJettyHome = MavenTestingUtils.getTestResourceDir("dist-home").toPath().toRealPath();
         cmdLineArgs.add("user.dir=" + testJettyHome);
         cmdLineArgs.add("jetty.home=" + testJettyHome);
-        cmdLineArgs.add("jetty.port=9090");
+        // cmdLineArgs.add("jetty.http.port=9090");
 
         Main main = new Main();
         StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
@@ -83,13 +83,13 @@
     }
 
     @Test
-    @Ignore("Just a bit noisy for general testing")
+    @Ignore("Too noisy for general testing")
     public void testListConfig() throws Exception
     {
         List<String> cmdLineArgs = new ArrayList<>();
-        File testJettyHome = MavenTestingUtils.getTestResourceDir("usecases/home");
+        File testJettyHome = MavenTestingUtils.getTestResourceDir("dist-home");
+        cmdLineArgs.add("user.dir=" + testJettyHome);
         cmdLineArgs.add("jetty.home=" + testJettyHome);
-        cmdLineArgs.add("jetty.port=9090");
         cmdLineArgs.add("--list-config");
         // cmdLineArgs.add("--debug");
 
@@ -111,9 +111,9 @@
     {
         List<String> cmdLineArgs = new ArrayList<>();
 
-        File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
-        cmdLineArgs.add("jetty.home=" + homePath);
-        cmdLineArgs.add("user.dir=" + homePath);
+        Path homePath = MavenTestingUtils.getTestResourceDir("dist-home").toPath().toRealPath();
+        cmdLineArgs.add("jetty.home=" + homePath.toString());
+        cmdLineArgs.add("user.dir=" + homePath.toString());
 
         // JVM args
         cmdLineArgs.add("--exec");
@@ -121,11 +121,8 @@
         cmdLineArgs.add("-Xmx1024m");
 
         // Arbitrary Libs
-        Path extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar").toPath().normalize();
-        Path extraDir = MavenTestingUtils.getTestResourceDir("extra-resources").toPath().normalize();
-        
-        extraJar = extraJar.toAbsolutePath();
-        extraDir = extraDir.toAbsolutePath();
+        Path extraJar = MavenTestingUtils.getTestResourceFile("extra-libs/example.jar").toPath().toRealPath();
+        Path extraDir = MavenTestingUtils.getTestResourceDir("extra-resources").toPath().toRealPath();
         
         assertThat("Extra Jar exists: " + extraJar,Files.exists(extraJar),is(true));
         assertThat("Extra Dir exists: " + extraDir,Files.exists(extraDir),is(true));
@@ -148,36 +145,35 @@
         StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
         BaseHome baseHome = main.getBaseHome();
 
-        assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
-        assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+        assertThat("jetty.home",baseHome.getHome(),is(homePath.toString()));
+        assertThat("jetty.base",baseHome.getBase(),is(homePath.toString()));
 
         ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-jvm.txt");
     }
     
     @Test
-    public void testWithSpdy() throws Exception
+    public void testWithHttp2() throws Exception
     {
         List<String> cmdLineArgs = new ArrayList<>();
 
-        File homePath = MavenTestingUtils.getTestResourceDir("usecases/home").getAbsoluteFile();
+        Path homePath = MavenTestingUtils.getTestResourceDir("dist-home").toPath().toRealPath();
         cmdLineArgs.add("jetty.home=" + homePath);
         cmdLineArgs.add("user.dir=" + homePath);
-        cmdLineArgs.add("java.version=1.7.0_60");
+        cmdLineArgs.add("java.version=1.8.0_31");
 
         // Modules
-        cmdLineArgs.add("--module=server");
         cmdLineArgs.add("--module=deploy");
-        cmdLineArgs.add("--module=spdy");
+        cmdLineArgs.add("--module=http2");
 
         Main main = new Main();
 
         StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
         BaseHome baseHome = main.getBaseHome();
 
-        assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
-        assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+        assertThat("jetty.home",baseHome.getHome(),is(homePath.toString()));
+        assertThat("jetty.base",baseHome.getBase(),is(homePath.toString()));
 
-        ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spdy.txt");
+        ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-http2.txt");
     }
 
     @Test
@@ -185,7 +181,7 @@
     {
         List<String> cmdLineArgs = new ArrayList<>();
 
-        File homePath = MavenTestingUtils.getTestResourceDir("jetty home with spaces").getAbsoluteFile();
+        Path homePath = MavenTestingUtils.getTestResourceDir("jetty home with spaces").toPath().toRealPath();
         cmdLineArgs.add("user.dir=" + homePath);
         cmdLineArgs.add("jetty.home=" + homePath);
 
@@ -193,8 +189,8 @@
         StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
         BaseHome baseHome = main.getBaseHome();
 
-        assertThat("jetty.home",baseHome.getHome(),is(homePath.getAbsolutePath()));
-        assertThat("jetty.base",baseHome.getBase(),is(homePath.getAbsolutePath()));
+        assertThat("jetty.home",baseHome.getHome(),is(homePath.toString()));
+        assertThat("jetty.base",baseHome.getBase(),is(homePath.toString()));
 
         ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home-with-spaces.txt");
     }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
index 72a5e6a..a441dea 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleGraphWriterTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.io.File;
 import java.io.IOException;
@@ -43,7 +43,7 @@
     public void testGenerate_NothingEnabled() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
         File baseDir = testdir.getEmptyDir();
         String cmdLine[] = new String[] {"jetty.version=TEST"};
         
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java
index f79ca54..d4b336f 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModuleTest.java
@@ -18,7 +18,9 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.is;
 
 import java.io.File;
 import java.io.IOException;
@@ -42,7 +44,7 @@
     public void testLoadWebSocket() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
         File baseDir = testdir.getEmptyDir();
         String cmdLine[] = new String[] {"jetty.version=TEST"};
         
@@ -56,14 +58,13 @@
         // Initialize
         BaseHome basehome = new BaseHome(config);
         
-        File file = MavenTestingUtils.getTestResourceFile("usecases/home/modules/websocket.mod");
+        File file = MavenTestingUtils.getTestResourceFile("dist-home/modules/websocket.mod");
         Module module = new Module(basehome,file.toPath());
         
         Assert.assertThat("Module Name",module.getName(),is("websocket"));
-        Assert.assertThat("Module Parents Size",module.getParentNames().size(),is(2));
-        Assert.assertThat("Module Parents",module.getParentNames(),containsInAnyOrder("annotations","server"));
-        Assert.assertThat("Module Xmls Size",module.getXmls().size(),is(1));
-        Assert.assertThat("Module Xmls",module.getXmls(),contains("etc/jetty-websockets.xml"));
+        Assert.assertThat("Module Parents Size",module.getParentNames().size(),is(1));
+        Assert.assertThat("Module Parents",module.getParentNames(),containsInAnyOrder("annotations"));
+        Assert.assertThat("Module Xmls Size",module.getXmls().size(),is(0));
         Assert.assertThat("Module Options Size",module.getLibs().size(),is(1));
         Assert.assertThat("Module Options",module.getLibs(),contains("lib/websocket/*.jar"));
     }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
index 895ac7e..7d206a3 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/ModulesTest.java
@@ -18,27 +18,32 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.contains;
-
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 import org.eclipse.jetty.start.config.CommandLineConfigSource;
 import org.eclipse.jetty.start.config.ConfigSources;
 import org.eclipse.jetty.start.config.JettyBaseConfigSource;
 import org.eclipse.jetty.start.config.JettyHomeConfigSource;
+import org.eclipse.jetty.start.graph.CriteriaSetPredicate;
+import org.eclipse.jetty.start.graph.Predicate;
+import org.eclipse.jetty.start.graph.RegexNamePredicate;
+import org.eclipse.jetty.start.graph.Selection;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.junit.Assert;
+import org.hamcrest.Matchers;
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.assertThat;
+
 public class ModulesTest
 {
-    private final static List<String> TEST_SOURCE = Collections.singletonList("<test>");
+    private final static String TEST_SOURCE = "<test>";
 
     @Rule
     public TestingDir testdir = new TestingDir();
@@ -47,20 +52,126 @@
     public void testLoadAllModules() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
-        File baseDir = testdir.getEmptyDir();
-        String cmdLine[] = new String[] {"jetty.version=TEST"};
-        
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = testdir.getEmptyPathDir().toFile();
+        String cmdLine[] = new String[] { "jetty.version=TEST" };
+
         // Configuration
         CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
         ConfigSources config = new ConfigSources();
         config.add(cmdLineSource);
         config.add(new JettyHomeConfigSource(homeDir.toPath()));
         config.add(new JettyBaseConfigSource(baseDir.toPath()));
-        
+
         // Initialize
         BaseHome basehome = new BaseHome(config);
-        
+
+        StartArgs args = new StartArgs();
+        args.parse(config);
+
+        // Test Modules
+        Modules modules = new Modules(basehome,args);
+        modules.registerAll();
+
+        // Check versions
+        assertThat("java.version.major", args.getProperties().getString("java.version.major"),equalTo("1"));
+        assertThat("java.version.minor", args.getProperties().getString("java.version.minor"),anyOf(equalTo("7"),Matchers.equalTo("8"),Matchers.equalTo("9")));
+
+        List<String> moduleNames = new ArrayList<>();
+        for (Module mod : modules)
+        {
+            // skip alpn-boot in this test (as its behavior is jdk specific)
+            if (mod.getName().equals("alpn-boot"))
+            {
+                continue;
+            }
+            moduleNames.add(mod.getName());
+        }
+
+        List<String> expected = new ArrayList<>();
+        expected.add("alpn");
+        expected.add("annotations");
+        expected.add("apache-jsp");
+        expected.add("apache-jstl");
+        expected.add("cdi");
+        expected.add("client");
+        expected.add("continuation");
+        expected.add("debuglog");
+        expected.add("deploy");
+        expected.add("ext");
+        expected.add("fcgi");
+        expected.add("gzip");
+        expected.add("hawtio");
+        expected.add("home-base-warning");
+        expected.add("http");
+        expected.add("http2");
+        expected.add("http2c");
+        expected.add("https");
+        expected.add("ipaccess");
+        expected.add("jaas");
+        expected.add("jamon");
+        expected.add("jaspi");
+        expected.add("jminix");
+        expected.add("jmx");
+        expected.add("jmx-remote");
+        expected.add("jndi");
+        expected.add("jolokia");
+        expected.add("jsp");
+        expected.add("jstl");
+        expected.add("jvm");
+        expected.add("logging");
+        expected.add("lowresources");
+        expected.add("monitor");
+        expected.add("plus");
+        expected.add("proxy");
+        expected.add("quickstart");
+        expected.add("requestlog");
+        expected.add("resources");
+        expected.add("rewrite");
+        expected.add("security");
+        expected.add("server");
+        expected.add("servlet");
+        expected.add("servlets");
+        expected.add("setuid");
+        expected.add("spring");
+        expected.add("ssl");
+        expected.add("stats");
+        expected.add("webapp");
+        expected.add("websocket");
+        expected.add("infinispan");
+        expected.add("jdbc-sessions");
+        expected.add("nosql");
+
+        ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames);
+    }
+
+    /**
+     * Test loading of only shallow modules, not deep references.
+     * In other words. ${search-dir}/modules/*.mod should be the only
+     * valid references, but ${search-dir}/alt/foo/modules/*.mod should
+     * not be considered valid.
+     * @throws IOException on test failures
+     */
+    @Test
+    public void testLoadShallowModulesOnly() throws IOException
+    {
+        // Test Env
+        File homeDir = MavenTestingUtils.getTestResourceDir("jetty home with spaces");
+        // intentionally setup top level resources dir (as this would have many
+        // deep references)
+        File baseDir = MavenTestingUtils.getTestResourcesDir();
+        String cmdLine[] = new String[] { "jetty.version=TEST" };
+
+        // Configuration
+        CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
+        ConfigSources config = new ConfigSources();
+        config.add(cmdLineSource);
+        config.add(new JettyHomeConfigSource(homeDir.toPath()));
+        config.add(new JettyBaseConfigSource(baseDir.toPath()));
+
+        // Initialize
+        BaseHome basehome = new BaseHome(config);
+
         StartArgs args = new StartArgs();
         args.parse(config);
 
@@ -71,49 +182,12 @@
         List<String> moduleNames = new ArrayList<>();
         for (Module mod : modules)
         {
-            // skip npn-boot in this test (as its behavior is jdk specific)
-            if (mod.getName().equals("npn-boot"))
-            {
-                continue;
-            }
             moduleNames.add(mod.getName());
         }
 
         List<String> expected = new ArrayList<>();
-        expected.add("jmx");
-        expected.add("client");
-        expected.add("stats");
-        expected.add("spdy");
-        expected.add("deploy");
-        expected.add("debug");
-        expected.add("security");
-        expected.add("ext");
-        expected.add("websocket");
-        expected.add("rewrite");
-        expected.add("ipaccess");
-        expected.add("xinetd");
-        expected.add("proxy");
-        expected.add("webapp");
-        expected.add("jndi");
-        expected.add("lowresources");
-        expected.add("https");
-        expected.add("plus");
-        expected.add("requestlog");
-        expected.add("jsp");
-        // (only present if enabled) expected.add("jsp-impl");
-        expected.add("monitor");
-        expected.add("xml");
-        expected.add("ssl");
-        expected.add("protonego");
-        expected.add("servlet");
-        expected.add("jaas");
-        expected.add("http");
         expected.add("base");
-        expected.add("server");
-        expected.add("annotations");
-        expected.add("resources");
-        expected.add("logging"); 
-        
+
         ConfigurationAssert.assertContainsUnordered("All Modules",expected,moduleNames);
     }
 
@@ -121,50 +195,61 @@
     public void testEnableRegexSimple() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
-        File baseDir = testdir.getEmptyDir();
-        String cmdLine[] = new String[] {"jetty.version=TEST", "java.version=1.7.0_60"};
-        
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = testdir.getEmptyPathDir().toFile();
+        String cmdLine[] = new String[] { "jetty.version=TEST", "java.version=1.8.0_31" };
+
         // Configuration
         CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
         ConfigSources config = new ConfigSources();
         config.add(cmdLineSource);
         config.add(new JettyHomeConfigSource(homeDir.toPath()));
         config.add(new JettyBaseConfigSource(baseDir.toPath()));
-        
+
         // Initialize
         BaseHome basehome = new BaseHome(config);
-        
+
         StartArgs args = new StartArgs();
         args.parse(config);
 
         // Test Modules
         Modules modules = new Modules(basehome,args);
         modules.registerAll();
-        modules.enable("[sj]{1}.*",TEST_SOURCE);
+        Predicate sjPredicate = new RegexNamePredicate("[sj]{1}.*");
+        modules.selectNode(sjPredicate,new Selection(TEST_SOURCE));
         modules.buildGraph();
 
         List<String> expected = new ArrayList<>();
         expected.add("jmx");
         expected.add("stats");
-        expected.add("spdy");
         expected.add("security");
         expected.add("jndi");
         expected.add("jsp");
         expected.add("servlet");
+        expected.add("servlets");
         expected.add("jaas");
         expected.add("server");
+        expected.add("setuid");
+        expected.add("spring");
+        expected.add("jaspi");
+        expected.add("jminix");
+        expected.add("jolokia");
+        expected.add("jamon");
+        expected.add("jstl");
+        expected.add("jmx-remote");
+        expected.add("jvm");
         // transitive
-        expected.add("base");
         expected.add("ssl");
-        expected.add("protonego");
-        expected.add("protonego-boot");
-        expected.add("protonego-impl");
-        expected.add("xml");
-        expected.add("jsp-impl");
-        
+        expected.add("apache-jsp");
+        expected.add("apache-jstl");
+        expected.add("webapp");
+        expected.add("deploy");
+        expected.add("plus");
+        expected.add("annotations");
+        expected.add("jdbc-sessions");
+
         List<String> resolved = new ArrayList<>();
-        for (Module module : modules.resolveEnabled())
+        for (Module module : modules.getSelected())
         {
             resolved.add(module.getName());
         }
@@ -176,40 +261,38 @@
     public void testResolve_ServerHttp() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
-        File baseDir = testdir.getEmptyDir();
-        String cmdLine[] = new String[] {"jetty.version=TEST"};
-        
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = testdir.getEmptyPathDir().toFile();
+        String cmdLine[] = new String[] { "jetty.version=TEST" };
+
         // Configuration
         CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
         ConfigSources config = new ConfigSources();
         config.add(cmdLineSource);
         config.add(new JettyHomeConfigSource(homeDir.toPath()));
         config.add(new JettyBaseConfigSource(baseDir.toPath()));
-        
+
         // Initialize
         BaseHome basehome = new BaseHome(config);
-        
+
         StartArgs args = new StartArgs();
         args.parse(config);
 
         // Test Modules
-        Modules modules = new Modules(basehome, args);
+        Modules modules = new Modules(basehome,args);
         modules.registerAll();
 
         // Enable 2 modules
-        modules.enable("server",TEST_SOURCE);
-        modules.enable("http",TEST_SOURCE);
+        modules.selectNode("server",new Selection(TEST_SOURCE));
+        modules.selectNode("http",new Selection(TEST_SOURCE));
 
         modules.buildGraph();
 
         // Collect active module list
-        List<Module> active = modules.resolveEnabled();
+        List<Module> active = modules.getSelected();
 
         // Assert names are correct, and in the right order
         List<String> expectedNames = new ArrayList<>();
-        expectedNames.add("base");
-        expectedNames.add("xml");
         expectedNames.add("server");
         expectedNames.add("http");
 
@@ -219,21 +302,20 @@
             actualNames.add(actual.getName());
         }
 
-        Assert.assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
+        assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
 
         // Assert Library List
         List<String> expectedLibs = new ArrayList<>();
-        expectedLibs.add("lib/jetty-util-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-io-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-xml-${jetty.version}.jar");
         expectedLibs.add("lib/servlet-api-3.1.jar");
         expectedLibs.add("lib/jetty-schemas-3.1.jar");
         expectedLibs.add("lib/jetty-http-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-continuation-${jetty.version}.jar");
         expectedLibs.add("lib/jetty-server-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-xml-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-util-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-io-${jetty.version}.jar");
 
         List<String> actualLibs = modules.normalizeLibs(active);
-        Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
+        assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
 
         // Assert XML List
         List<String> expectedXmls = new ArrayList<>();
@@ -241,27 +323,27 @@
         expectedXmls.add("etc/jetty-http.xml");
 
         List<String> actualXmls = modules.normalizeXmls(active);
-        Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
+        assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
     }
 
     @Test
     public void testResolve_WebSocket() throws IOException
     {
         // Test Env
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
-        File baseDir = testdir.getEmptyDir();
-        String cmdLine[] = new String[] {"jetty.version=TEST"};
-        
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = testdir.getEmptyPathDir().toFile();
+        String cmdLine[] = new String[] { "jetty.version=TEST" };
+
         // Configuration
         CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
         ConfigSources config = new ConfigSources();
         config.add(cmdLineSource);
         config.add(new JettyHomeConfigSource(homeDir.toPath()));
         config.add(new JettyBaseConfigSource(baseDir.toPath()));
-        
+
         // Initialize
         BaseHome basehome = new BaseHome(config);
-        
+
         StartArgs args = new StartArgs();
         args.parse(config);
 
@@ -270,23 +352,23 @@
         modules.registerAll();
 
         // Enable 2 modules
-        modules.enable("websocket",TEST_SOURCE);
-        modules.enable("http",TEST_SOURCE);
+        modules.selectNode("websocket",new Selection(TEST_SOURCE));
+        modules.selectNode("http",new Selection(TEST_SOURCE));
 
         modules.buildGraph();
         // modules.dump();
 
         // Collect active module list
-        List<Module> active = modules.resolveEnabled();
+        List<Module> active = modules.getSelected();
 
         // Assert names are correct, and in the right order
         List<String> expectedNames = new ArrayList<>();
-        expectedNames.add("base");
-        expectedNames.add("xml");
         expectedNames.add("server");
         expectedNames.add("http");
         expectedNames.add("jndi");
         expectedNames.add("security");
+        expectedNames.add("servlet");
+        expectedNames.add("webapp");
         expectedNames.add("plus");
         expectedNames.add("annotations");
         expectedNames.add("websocket");
@@ -297,28 +379,29 @@
             actualNames.add(actual.getName());
         }
 
-        Assert.assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
+        assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
 
         // Assert Library List
         List<String> expectedLibs = new ArrayList<>();
-        expectedLibs.add("lib/jetty-util-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-io-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-xml-${jetty.version}.jar");
         expectedLibs.add("lib/servlet-api-3.1.jar");
         expectedLibs.add("lib/jetty-schemas-3.1.jar");
         expectedLibs.add("lib/jetty-http-${jetty.version}.jar");
-        expectedLibs.add("lib/jetty-continuation-${jetty.version}.jar");
         expectedLibs.add("lib/jetty-server-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-xml-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-util-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-io-${jetty.version}.jar");
         expectedLibs.add("lib/jetty-jndi-${jetty.version}.jar");
         expectedLibs.add("lib/jndi/*.jar");
         expectedLibs.add("lib/jetty-security-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-servlet-${jetty.version}.jar");
+        expectedLibs.add("lib/jetty-webapp-${jetty.version}.jar");
         expectedLibs.add("lib/jetty-plus-${jetty.version}.jar");
         expectedLibs.add("lib/jetty-annotations-${jetty.version}.jar");
         expectedLibs.add("lib/annotations/*.jar");
         expectedLibs.add("lib/websocket/*.jar");
 
         List<String> actualLibs = modules.normalizeLibs(active);
-        Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
+        assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
 
         // Assert XML List
         List<String> expectedXmls = new ArrayList<>();
@@ -326,9 +409,98 @@
         expectedXmls.add("etc/jetty-http.xml");
         expectedXmls.add("etc/jetty-plus.xml");
         expectedXmls.add("etc/jetty-annotations.xml");
-        expectedXmls.add("etc/jetty-websockets.xml");
 
         List<String> actualXmls = modules.normalizeXmls(active);
-        Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
+        assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
+    }
+
+    @Test
+    public void testResolve_Alt() throws IOException
+    {
+        // Test Env
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = testdir.getEmptyPathDir().toFile();
+        String cmdLine[] = new String[] { "jetty.version=TEST" };
+
+        // Configuration
+        CommandLineConfigSource cmdLineSource = new CommandLineConfigSource(cmdLine);
+        ConfigSources config = new ConfigSources();
+        config.add(cmdLineSource);
+        config.add(new JettyHomeConfigSource(homeDir.toPath()));
+        config.add(new JettyBaseConfigSource(baseDir.toPath()));
+
+        // Initialize
+        BaseHome basehome = new BaseHome(config);
+
+        StartArgs args = new StartArgs();
+        args.parse(config);
+
+        // Test Modules
+        Modules modules = new Modules(basehome,args);
+        modules.registerAll();
+
+        // Enable test modules
+        modules.selectNode("http",new Selection(TEST_SOURCE));
+        modules.selectNode("annotations",new Selection(TEST_SOURCE));
+        modules.selectNode("deploy",new Selection(TEST_SOURCE));
+        // Enable alternate modules
+        String alt = "<alt>";
+        modules.selectNode("websocket",new Selection(alt));
+        modules.selectNode("jsp",new Selection(alt));
+
+        modules.buildGraph();
+        // modules.dump();
+
+        // Collect active module list
+        List<Module> active = modules.getSelected();
+
+        // Assert names are correct, and in the right order
+        List<String> expectedNames = new ArrayList<>();
+        expectedNames.add("apache-jsp");
+        expectedNames.add("server");
+        expectedNames.add("http");
+        expectedNames.add("jndi");
+        expectedNames.add("security");
+        expectedNames.add("servlet");
+        expectedNames.add("webapp");
+        expectedNames.add("deploy");
+        expectedNames.add("plus");
+        expectedNames.add("annotations");
+        expectedNames.add("jsp");
+        expectedNames.add("websocket");
+
+        List<String> actualNames = new ArrayList<>();
+        for (Module actual : active)
+        {
+            actualNames.add(actual.getName());
+        }
+
+        assertThat("Resolved Names: " + actualNames,actualNames,contains(expectedNames.toArray()));
+
+        // Now work with the 'alt' selected
+        List<String> expectedAlts = new ArrayList<>();
+        expectedAlts.add("apache-jsp");
+        expectedAlts.add("jsp");
+        expectedAlts.add("websocket");
+
+        for (String expectedAlt : expectedAlts)
+        {
+            Module altMod = modules.get(expectedAlt);
+            assertThat("Alt.mod[" + expectedAlt + "].selected",altMod.isSelected(),is(true));
+            Set<String> sources = altMod.getSelectedCriteriaSet();
+            assertThat("Alt.mod[" + expectedAlt + "].sources: [" + Utils.join(sources,", ") + "]",sources,contains(alt));
+        }
+
+        // Now collect the unique source list
+        List<Module> alts = modules.getMatching(new CriteriaSetPredicate(alt));
+
+        // Assert names are correct, and in the right order
+        actualNames = new ArrayList<>();
+        for (Module actual : alts)
+        {
+            actualNames.add(actual.getName());
+        }
+
+        assertThat("Resolved Alt (Sources) Names: " + actualNames,actualNames,contains(expectedAlts.toArray()));
     }
 }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java
index 48f9299..beffa96 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PathFinderTest.java
@@ -28,15 +28,22 @@
 import java.util.List;
 
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Rule;
 import org.junit.Test;
 
 public class PathFinderTest
 {
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
     @Test
     public void testFindInis() throws IOException
     {
         File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
         Path homePath = homeDir.toPath().toAbsolutePath();
+        File baseDir = testdir.getEmptyDir();
+        Path basePath = baseDir.toPath().toAbsolutePath();
 
         PathFinder finder = new PathFinder();
         finder.setFileMatcher("glob:**/*.ini");
@@ -53,15 +60,17 @@
         expected.add("${jetty.home}/start.ini");
         FSTest.toOsSeparators(expected);
 
-        BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString() });
+        BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString(), "jetty.base=" + basePath.toString() });
         BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
     }
 
     @Test
     public void testFindMods() throws IOException
     {
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
         Path homePath = homeDir.toPath().toAbsolutePath();
+        File baseDir = testdir.getEmptyDir();
+        Path basePath = baseDir.toPath().toAbsolutePath();
 
         List<String> expected = new ArrayList<>();
         File modulesDir = new File(homeDir,"modules");
@@ -82,7 +91,7 @@
         
         Files.walkFileTree(modulesPath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),1,finder);
 
-        BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString() });
+        BaseHome hb = new BaseHome(new String[] { "jetty.home=" + homePath.toString(), "jetty.base=" + basePath.toString() });
         BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
     }
 }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
index b052b33..5f89221 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
@@ -18,8 +18,7 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.*;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -89,7 +88,7 @@
 
     @Rule
     public TestingDir testingdir = new TestingDir();
-
+    
     @Test
     public void testAsJvmArg() throws IOException, InterruptedException
     {
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java
index 62a2293..ae03d0a 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/PropsTest.java
@@ -18,8 +18,11 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 
 import org.eclipse.jetty.start.Props.Prop;
 import org.junit.Test;
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/RebuildTestResources.java b/jetty-start/src/test/java/org/eclipse/jetty/start/RebuildTestResources.java
deleted file mode 100644
index c656bb7..0000000
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/RebuildTestResources.java
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.start;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.PathMatcher;
-import java.nio.file.StandardCopyOption;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.toolchain.test.FS;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-
-/**
- * Utility class to rebuild the src/test/resources/dist-home from the active build tree.
- * <p>
- * Not really meant to be run with each build. Nor is it a good idea to attempt to do that (as this would introduce a dependency from jetty-start ->
- * jetty-distribution which is a circular dependency)
- */
-public class RebuildTestResources
-{
-    public static void main(String[] args)
-    {
-        File realDistHome = MavenTestingUtils.getProjectDir("../jetty-distribution/target/distribution");
-        File outputDir = MavenTestingUtils.getTestResourceDir("dist-home");
-        try
-        {
-            new RebuildTestResources(realDistHome,outputDir).rebuild();
-        }
-        catch (Throwable t)
-        {
-            t.printStackTrace();
-        }
-    }
-
-    private static interface FileCopier
-    {
-        public void copy(Path from, Path to) throws IOException;
-    }
-
-    private static class NormalFileCopier implements FileCopier
-    {
-        @Override
-        public void copy(Path from, Path to) throws IOException
-        {
-            Files.copy(from,to,StandardCopyOption.REPLACE_EXISTING);
-        }
-    }
-
-    private static class TouchFileCopier implements FileCopier
-    {
-        @Override
-        public void copy(Path from, Path to) throws IOException
-        {
-            Files.createFile(to);
-        }
-    }
-
-    private static interface Renamer
-    {
-        public String getName(Path path);
-    }
-
-    private static class NoRenamer implements Renamer
-    {
-        @Override
-        public String getName(Path path)
-        {
-            return path.getFileName().toString();
-        }
-    }
-
-    private static class RegexRenamer implements Renamer
-    {
-        private final Pattern pat;
-        private final String replacement;
-
-        public RegexRenamer(String regex, String replacement)
-        {
-            this.pat = Pattern.compile(regex);
-            this.replacement = replacement;
-        }
-
-        @Override
-        public String getName(Path path)
-        {
-            String origName = path.getFileName().toString();
-            return pat.matcher(origName).replaceAll(replacement);
-        }
-    }
-
-    private final Path destDir;
-    private final Path srcDir;
-
-    public RebuildTestResources(File realDistHome, File outputDir) throws IOException
-    {
-        this.srcDir = realDistHome.toPath().toRealPath();
-        this.destDir = outputDir.toPath();
-    }
-
-    private void copyLibs() throws IOException
-    {
-        System.out.println("Copying libs (lib dir) ...");
-        Path libsDir = destDir.resolve("lib");
-        FS.ensureDirExists(libsDir.toFile());
-
-        PathMatcher matcher = getPathMatcher("glob:**.jar");
-        Renamer renamer = new RegexRenamer("-9\\.[0-9.]*(v[0-9]*)?(-SNAPSHOT)?(RC[0-9])?(M[0-9])?","-TEST");
-        FileCopier copier = new TouchFileCopier();
-        copyDir(srcDir.resolve("lib"),libsDir,matcher,renamer,copier);
-    }
-
-    private void copyModules() throws IOException
-    {
-        System.out.println("Copying modules ...");
-        Path modulesDir = destDir.resolve("modules");
-        FS.ensureDirExists(modulesDir.toFile());
-
-        PathMatcher matcher = getPathMatcher("glob:**.mod");
-        Renamer renamer = new NoRenamer();
-        FileCopier copier = new NormalFileCopier();
-        copyDir(srcDir.resolve("modules"),modulesDir,matcher,renamer,copier);
-    }
-
-    private void copyXmls() throws IOException
-    {
-        System.out.println("Copying xmls (etc dir) ...");
-        Path xmlDir = destDir.resolve("etc");
-        FS.ensureDirExists(xmlDir.toFile());
-
-        PathMatcher matcher = getPathMatcher("glob:**.xml");
-        Renamer renamer = new NoRenamer();
-        FileCopier copier = new TouchFileCopier();
-        copyDir(srcDir.resolve("etc"),xmlDir,matcher,renamer,copier);
-    }
-
-    private void rebuild() throws IOException
-    {
-        copyModules();
-        copyLibs();
-        copyXmls();
-        System.out.println("Done");
-    }
-
-    private PathMatcher getPathMatcher(String pattern)
-    {
-        return FileSystems.getDefault().getPathMatcher(pattern);
-    }
-
-    private void copyDir(Path from, Path to, PathMatcher fileMatcher, Renamer renamer, FileCopier copier) throws IOException
-    {
-        Files.createDirectories(to);
-
-        for (Path path : Files.newDirectoryStream(from))
-        {
-            String name = renamer.getName(path);
-            Path dest = to.resolve(name);
-            if (Files.isDirectory(path))
-            {
-                copyDir(path,dest,fileMatcher,renamer,copier);
-            }
-            else
-            {
-                if (fileMatcher.matches(path))
-                {
-                    copier.copy(path,dest);
-                }
-            }
-        }
-    }
-}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/StartMatchers.java b/jetty-start/src/test/java/org/eclipse/jetty/start/StartMatchers.java
new file mode 100644
index 0000000..b155176
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/StartMatchers.java
@@ -0,0 +1,104 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+public final class StartMatchers
+{
+    public static Matcher<Path> pathExists()
+    {
+        return new BaseMatcher<Path>()
+        {
+            @Override
+            public boolean matches(Object item)
+            {
+                final Path path = (Path)item;
+                return Files.exists(path);
+            }
+
+            @Override
+            public void describeTo(Description description)
+            {
+                description.appendText("Path should exist");
+            }
+            
+            @Override
+            public void describeMismatch(Object item, Description description)
+            {
+                description.appendText("Path did not exist ").appendValue(item);
+            }
+        };
+    }
+    
+    public static Matcher<Path> notPathExists()
+    {
+        return new BaseMatcher<Path>()
+        {
+            @Override
+            public boolean matches(Object item)
+            {
+                final Path path = (Path)item;
+                return !Files.exists(path);
+            }
+
+            @Override
+            public void describeTo(Description description)
+            {
+                description.appendText("Path should not exist");
+            }
+            
+            @Override
+            public void describeMismatch(Object item, Description description)
+            {
+                description.appendText("Path exists ").appendValue(item);
+            }
+        };
+    }
+    
+    public static Matcher<Path> fileExists()
+    {
+        return new BaseMatcher<Path>()
+        {
+            @Override
+            public boolean matches(Object item)
+            {
+                final Path path = (Path)item;
+                return Files.exists(path) && Files.isRegularFile(path);
+            }
+
+            @Override
+            public void describeTo(Description description)
+            {
+                description.appendText("File should exist");
+            }
+            
+            @Override
+            public void describeMismatch(Object item, Description description)
+            {
+                description.appendText("File did not exist ").appendValue(item);
+            }
+        };
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java
index 3998e5f..c21f136 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestBadUseCases.java
@@ -18,68 +18,78 @@
 
 package org.eclipse.jetty.start;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jetty.start.util.RebuildTestResources;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.hamcrest.Matchers.containsString;
 
 /**
  * Test bad configuration scenarios.
  */
+@RunWith(Parameterized.class)
 public class TestBadUseCases
 {
-    private void assertBadConfig(String homeName, String baseName, String expectedErrorMessage, String... cmdLineArgs) throws Exception
+    @Parameters(name = "{0}")
+    public static List<Object[]> getCases()
     {
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/" + homeName);
-        File baseDir = MavenTestingUtils.getTestResourceDir("usecases/" + baseName);
+        List<Object[]> ret = new ArrayList<>();
+
+        ret.add(new Object[]{ "http2",
+                "Missing referenced dependency: alpn-impl/alpn-0.0.0_0",
+                new String[]{"java.version=0.0.0_0"}});
+
+        ret.add(new Object[]{ "versioned-modules-too-new",
+                "Module [http3] specifies jetty version [10.0] which is newer than this version of jetty [" + RebuildTestResources.JETTY_VERSION + "]",
+                null});
+
+        return ret;
+    }
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Parameter(0)
+    public String caseName;
+
+    @Parameter(1)
+    public String expectedErrorMessage;
+
+    @Parameter(2)
+    public String[] commandLineArgs;
+
+    @Test
+    public void testBadConfig() throws Exception
+    {
+        File homeDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        File baseDir = MavenTestingUtils.getTestResourceDir("usecases/" + caseName);
 
         Main main = new Main();
         List<String> cmdLine = new ArrayList<>();
         cmdLine.add("jetty.home=" + homeDir.getAbsolutePath());
         cmdLine.add("jetty.base=" + baseDir.getAbsolutePath());
         // cmdLine.add("--debug");
-        for (String arg : cmdLineArgs)
+
+        if (commandLineArgs != null)
         {
-            cmdLine.add(arg);
+            for (String arg : commandLineArgs)
+            {
+                cmdLine.add(arg);
+            }
         }
 
-        try
-        {
-            main.processCommandLine(cmdLine);
-            fail("Expected " + UsageException.class.getName());
-        }
-        catch (UsageException e)
-        {
-            assertThat("Usage error",e.getMessage(),containsString(expectedErrorMessage));
-        }
+        expectedException.expect(UsageException.class);
+        expectedException.expectMessage(containsString(expectedErrorMessage));
+        main.processCommandLine(cmdLine);
     }
-
-    @Test
-    public void testBadJspCommandLine() throws Exception
-    {
-        assertBadConfig("home","base.with.jsp.default",
-                "Missing referenced dependency: jsp-impl/bad-jsp","jsp-impl=bad");
-    }
-
-    @Test
-    public void testBadJspImplName() throws Exception
-    {
-        assertBadConfig("home","base.with.jsp.bad",
-                "Missing referenced dependency: jsp-impl/bogus-jsp");
-    }
-    
-    @Test
-    public void testWithSpdyBadNpnVersion() throws Exception
-    {
-        assertBadConfig("home","base.enable.spdy.bad.npn.version",
-                "Missing referenced dependency: protonego-impl/npn-1.7.0_01",
-                "java.version=1.7.0_01", "protonego=npn");
-    }
-
-
 }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
index aece10c..eeaba98 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java
@@ -18,118 +18,73 @@
 
 package org.eclipse.jetty.start;
 
-import java.io.File;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * Various Home + Base use cases
  */
+@RunWith(Parameterized.class)
 public class TestUseCases
 {
-    private void assertUseCase(String homeName, String baseName, String assertName, String... cmdLineArgs) throws Exception
+    @Parameters(name = "{0}")
+    public static List<Object[]> getCases()
     {
-        File homeDir = MavenTestingUtils.getTestResourceDir("usecases/" + homeName);
-        File baseDir = MavenTestingUtils.getTestResourceDir("usecases/" + baseName);
+        List<Object[]> ret = new ArrayList<>();
+
+        ret.add(new String[] {"barebones", null});
+        ret.add(new String[] {"include-jetty-dir-logging", null});
+        ret.add(new String[] {"jmx", null});
+        ret.add(new String[] {"logging", null});
+        ret.add(new String[] {"jsp", null});
+        ret.add(new String[] {"database", null});
+        ret.add(new String[] {"deep-ext", null});
+        ret.add(new String[] {"versioned-modules", null});
+        
+        // Ones with command lines
+        ret.add(new Object[] {"http2", new String[]{"java.version=1.8.0_31"}});
+        ret.add(new Object[] {"basic-properties", new String[]{"port=9090"}});
+        ret.add(new Object[] {"agent-properties", new String[]{"java.vm.specification.version=1.6"}});
+        
+        return ret;
+    }
+
+    @Parameter(0)
+    public String caseName;
+
+    @Parameter(1)
+    public String[] commandLineArgs;
+
+    @Test
+    public void testUseCase() throws Exception
+    {
+        Path homeDir = MavenTestingUtils.getTestResourceDir("dist-home").toPath().toRealPath();
+        Path baseDir = MavenTestingUtils.getTestResourceDir("usecases/" + caseName).toPath().toRealPath();
 
         Main main = new Main();
         List<String> cmdLine = new ArrayList<>();
-        cmdLine.add("jetty.home=" + homeDir.getAbsolutePath());
-        cmdLine.add("jetty.base=" + baseDir.getAbsolutePath());
+        cmdLine.add("jetty.home=" + homeDir.toString());
+        cmdLine.add("jetty.base=" + baseDir.toString());
         // cmdLine.add("--debug");
-        for (String arg : cmdLineArgs)
+
+        if (commandLineArgs != null)
         {
-            cmdLine.add(arg);
+            for (String arg : commandLineArgs)
+            {
+                cmdLine.add(arg);
+            }
         }
+
         StartArgs args = main.processCommandLine(cmdLine);
         BaseHome baseHome = main.getBaseHome();
-        ConfigurationAssert.assertConfiguration(baseHome,args,"usecases/" + assertName);
-    }
-
-    @Test
-    public void testBarebones() throws Exception
-    {
-        assertUseCase("home","base.barebones","assert-barebones.txt");
-    }
-
-    @Test
-    public void testJMX() throws Exception
-    {
-        assertUseCase("home","base.jmx","assert-jmx.txt");
-    }
-    
-    @Test
-    public void testWithLogging() throws Exception
-    {
-        assertUseCase("home","base.logging","assert-logging.txt");
-    }
-
-    @Test
-    public void testWithIncludeJettyDir_Logging() throws Exception
-    {
-        assertUseCase("home","base.with.include.jetty.dirs","assert-include-jetty-dir-logging.txt");
-    }
-
-    @Test
-    public void testWithJspDefault() throws Exception
-    {
-        assertUseCase("home","base.with.jsp.default","assert-jsp-apache.txt");
-    }
-
-    @Test
-    public void testWithJspApache() throws Exception
-    {
-        assertUseCase("home","base.with.jsp.apache","assert-jsp-apache.txt");
-    }
-    
-    @Test
-    public void testWithJspGlassfish() throws Exception
-    {
-        assertUseCase("home","base.with.jsp.glassfish","assert-jsp-glassfish.txt");
-    }
-
-    @Test
-    public void testWithJspGlassfishCmdLine() throws Exception
-    {
-        assertUseCase("home","base.with.jsp.default","assert-jsp-glassfish.txt","jsp-impl=glassfish");
-    }
-
-    @Test
-    public void testWithMissingNpnVersion() throws Exception
-    {
-        assertUseCase("home","base.missing.npn.version","assert-missing-npn-version.txt","java.version=1.7.0_01");
-    }
-    
-    @Test
-    public void testWithSpdy() throws Exception
-    {
-        assertUseCase("home","base.enable.spdy","assert-enable-spdy.txt","java.version=1.7.0_60");
-    }
-    
-    @Test
-    public void testWithDatabase() throws Exception
-    {
-        assertUseCase("home","base.with.db","assert-with-db.txt");
-    }
-
-    @Test
-    public void testWithDeepExt() throws Exception
-    {
-        assertUseCase("home","base.with.ext","assert-with.ext.txt");
-    }
-    
-    @Test
-    public void testWithPropsBasic() throws Exception
-    {
-        assertUseCase("home","base.props.basic","assert-props.basic.txt","port=9090");
-    }
-    
-    @Test
-    public void testWithPropsAgent() throws Exception
-    {
-        assertUseCase("home","base.props.agent","assert-props.agent.txt","java.vm.specification.version=1.6");
+        ConfigurationAssert.assertConfiguration(baseHome,args,"usecases/" + caseName + ".assert.txt");
     }
 }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java
index ebad5f3..4fa8065 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/VersionTest.java
@@ -18,18 +18,46 @@
 
 package org.eclipse.jetty.start;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 import org.junit.Test;
 
 public class VersionTest
 {
     @Test
-    public void testDefaultVersion()
+    public void testParse() 
     {
-        Version version = new Version();
-        assertEquals("Default version difference to 0.0.0",0,version.compare(new Version("0.0.0")));
+        assertParse("1.8.0_45",1,8,0,45);
+        assertParse("1.8.0_45-internal",1,8,0,45);
+        assertParse("1.8.0-debug",1,8,0,-1);
+    }
+    
+    private void assertParse(String verStr, int legacyMajor, int major, int revision, int update)
+    {
+        Version ver = new Version(verStr);
+        assertThat("Version [" + verStr + "].legacyMajor", ver.getLegacyMajor(), is(legacyMajor));
+        assertThat("Version [" + verStr + "].major", ver.getMajor(), is(major));
+        assertThat("Version [" + verStr + "].revision", ver.getRevision(), is(revision));
+        assertThat("Version [" + verStr + "].update", ver.getUpdate(), is(update));
+        
+        assertThat("Version [" + verStr + "].toString", ver.toString(), is(verStr));
+    }
+
+    @Test
+    public void testToShortString() 
+    {
+        assertToShortString("1.8","1.8");
+        assertToShortString("1.8.0","1.8.0");
+        assertToShortString("1.8.0_45","1.8.0_45");
+        assertToShortString("1.8.0_45-internal","1.8.0_45");
+        assertToShortString("1.8.0-debug","1.8.0");
+    }
+    
+    private void assertToShortString(String verStr, String expectedShortString)
+    {
+        Version ver = new Version(verStr);
+        assertThat("Version [" + verStr + "].toShortString", ver.toShortString(), is(expectedShortString));
     }
 
     @Test
@@ -39,27 +67,41 @@
         assertIsNewer("1.5.0", "1.6.0");
         // assertIsNewer("1.6.0_12", "1.6.0_16"); // JDK version spec?
     }
-
+    
     @Test
     public void testOlderVersion() {
         assertIsOlder("0.0.1", "0.0.0");
         assertIsOlder("0.1.1", "0.1.0");
         assertIsOlder("1.6.0", "1.5.0");
     }
+    
+    @Test
+    public void testOlderOrEqualTo()
+    {
+        assertThat("9.2 <= 9.2",new Version("9.2").isOlderThanOrEqualTo(new Version("9.2")),is(true));
+        assertThat("9.2 <= 9.3",new Version("9.2").isOlderThanOrEqualTo(new Version("9.3")),is(true));
+        assertThat("9.3 <= 9.2",new Version("9.3").isOlderThanOrEqualTo(new Version("9.2")),is(false));
+    }
+    
+    @Test
+    public void testNewerOrEqualTo()
+    {
+        assertThat("9.2 >= 9.2",new Version("9.2").isNewerThanOrEqualTo(new Version("9.2")),is(true));
+        assertThat("9.2 >= 9.3",new Version("9.2").isNewerThanOrEqualTo(new Version("9.3")),is(false));
+        assertThat("9.3 >= 9.2",new Version("9.3").isNewerThanOrEqualTo(new Version("9.2")),is(true));
+    }
 
     private void assertIsOlder(String basever, String testver)
     {
         Version vbase = new Version(basever);
         Version vtest = new Version(testver);
-        assertTrue("Version [" + testver + "] should be older than [" + basever + "]",
-                vtest.compare(vbase) == -1);
+        assertTrue("Version [" + testver + "] should be older than [" + basever + "]", vtest.isOlderThan(vbase));
     }
 
     private void assertIsNewer(String basever, String testver)
     {
         Version vbase = new Version(basever);
         Version vtest = new Version(testver);
-        assertTrue("Version [" + testver + "] should be newer than [" + basever + "]",
-                vtest.compare(vbase) == 1);
+        assertTrue("Version [" + testver + "] should be newer than [" + basever + "]", vtest.isNewerThan(vbase));
     }
 }
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/config/ConfigSourcesTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/config/ConfigSourcesTest.java
index be355e5..4fa622f 100644
--- a/jetty-start/src/test/java/org/eclipse/jetty/start/config/ConfigSourcesTest.java
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/config/ConfigSourcesTest.java
@@ -18,10 +18,9 @@
 
 package org.eclipse.jetty.start.config;
 
-import static org.hamcrest.Matchers.*;
-
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -36,6 +35,10 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
 public class ConfigSourcesTest
 {
     @Rule
@@ -83,13 +86,13 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         ConfigSources sources = new ConfigSources();
 
@@ -107,27 +110,28 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
-        File common = testdir.getFile("common");
-        FS.ensureEmpty(common);
+        Path common = testdir.getFile("common").toPath();
+        FS.ensureEmpty(common.toFile());
+        common = common.toRealPath();
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
-                "--include-jetty-dir=" + common.getAbsolutePath());
+                "jetty.http.host=127.0.0.1",//
+                "--include-jetty-dir=" + common.toString());
 
         ConfigSources sources = new ConfigSources();
 
         String[] cmdLine = new String[0];
         sources.add(new CommandLineConfigSource(cmdLine));
-        sources.add(new JettyHomeConfigSource(home.toPath()));
-        sources.add(new JettyBaseConfigSource(base.toPath()));
+        sources.add(new JettyHomeConfigSource(home.toPath().toRealPath()));
+        sources.add(new JettyBaseConfigSource(base.toPath().toRealPath()));
 
-        assertIdOrder(sources,"<command-line>","${jetty.base}",common.getAbsolutePath(),"${jetty.home}");
+        assertIdOrder(sources,"<command-line>","${jetty.base}",common.toString(),"${jetty.home}");
     }
 
     @Test
@@ -136,18 +140,18 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         ConfigSources sources = new ConfigSources();
 
@@ -167,8 +171,8 @@
 
         assertDirOrder(sources,base,common,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -177,7 +181,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create opt
         File opt = testdir.getFile("opt");
@@ -186,13 +190,13 @@
         // Create common
         File common = new File(opt,"common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         String dirRef = "${my.opt}" + File.separator + "common";
 
@@ -213,8 +217,8 @@
 
         assertDirOrder(sources,base,common,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -223,7 +227,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create opt
         File opt = testdir.getFile("opt");
@@ -232,13 +236,13 @@
         // Create common
         File common = new File(opt,"common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1");
+                "jetty.http.host=127.0.0.1");
 
         String dirRef = "${my.opt}" + File.separator + "${my.dir}";
 
@@ -262,8 +266,8 @@
 
         assertDirOrder(sources,base,common,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
     
     @Test
@@ -272,18 +276,18 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         ConfigSources sources = new ConfigSources();
@@ -297,8 +301,8 @@
 
         assertDirOrder(sources,base,common,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
 
     @Test
@@ -307,12 +311,12 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
-        TestEnv.makeFile(common,"start.ini","jetty.port=8080");
+        TestEnv.makeFile(common,"start.ini","jetty.http.port=8080");
 
         // Create corp
         File corp = testdir.getFile("corp");
@@ -322,7 +326,7 @@
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath(), //
                 "--include-jetty-dir=" + corp.getAbsolutePath());
 
@@ -340,8 +344,8 @@
 
         assertDirOrder(sources,base,common,corp,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
     
     @Test
@@ -350,26 +354,26 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         ConfigSources sources = new ConfigSources();
@@ -386,8 +390,8 @@
 
         assertDirOrder(sources,base,common,corp,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
     
     @Test
@@ -396,13 +400,13 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
@@ -410,13 +414,13 @@
         TestEnv.makeFile(common,"start.ini", //
                 "my.corp=" + corp.getAbsolutePath(), //
                 "--include-jetty-dir=${my.corp}", //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "my.common="+common.getAbsolutePath(), //
                 "--include-jetty-dir=${my.common}");
 
@@ -435,8 +439,8 @@
 
         assertDirOrder(sources,base,common,corp,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","8080"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","8080"); // from 'common'
     }
     
     @Test
@@ -445,33 +449,33 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create devops
         File devops = testdir.getFile("devops");
         FS.ensureEmpty(devops);
         TestEnv.makeFile(devops,"start.ini", //
                 "--module=logging", //
-                "jetty.port=2222");
+                "jetty.http.port=2222");
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         ConfigSources sources = new ConfigSources();
@@ -492,8 +496,8 @@
 
         assertDirOrder(sources,base,devops,common,corp,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","2222"); // from 'common'
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","2222"); // from 'common'
     }
     
     @Test
@@ -502,33 +506,33 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create corp
         File corp = testdir.getFile("corp");
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", //
-                "jetty.port=9090");
+                "jetty.http.port=9090");
 
         // Create common
         File common = testdir.getFile("common");
         FS.ensureEmpty(common);
         TestEnv.makeFile(common,"start.ini", //
                 "--include-jetty-dir=" + corp.getAbsolutePath(), //
-                "jetty.port=8080");
+                "jetty.http.port=8080");
 
         // Create base
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         ConfigSources sources = new ConfigSources();
         
         String cmdLine[] = new String[]{
              // command line property should override all others
-                "jetty.port=7070"
+                "jetty.http.port=7070"
         };
         sources.add(new CommandLineConfigSource(cmdLine));
         sources.add(new JettyHomeConfigSource(home.toPath()));
@@ -541,8 +545,8 @@
 
         assertDirOrder(sources,base,common,corp,home);
 
-        assertProperty(sources,"jetty.host","127.0.0.1");
-        assertProperty(sources,"jetty.port","7070"); // from <command-line>
+        assertProperty(sources,"jetty.http.host","127.0.0.1");
+        assertProperty(sources,"jetty.http.port","7070"); // from <command-line>
     }
     
     @Test
@@ -551,7 +555,7 @@
         // Create home
         File home = testdir.getFile("home");
         FS.ensureEmpty(home);
-        TestEnv.copyTestDir("usecases/home",home);
+        TestEnv.copyTestDir("dist-home",home);
 
         // Create common
         File common = testdir.getFile("common");
@@ -562,14 +566,14 @@
         FS.ensureEmpty(corp);
         TestEnv.makeFile(corp,"start.ini", 
                 // standard property
-                "jetty.port=9090",
+                "jetty.http.port=9090",
                 // INTENTIONAL BAD Reference (duplicate)
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         // Populate common
         TestEnv.makeFile(common,"start.ini", 
                 // standard property
-                "jetty.port=8080",
+                "jetty.http.port=8080",
                 // reference to corp
                 "--include-jetty-dir=" + corp.getAbsolutePath());
 
@@ -577,7 +581,7 @@
         File base = testdir.getFile("base");
         FS.ensureEmpty(base);
         TestEnv.makeFile(base,"start.ini", //
-                "jetty.host=127.0.0.1",//
+                "jetty.http.host=127.0.0.1",//
                 "--include-jetty-dir=" + common.getAbsolutePath());
 
         ConfigSources sources = new ConfigSources();
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java
new file mode 100644
index 0000000..f048c99
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java
@@ -0,0 +1,154 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.start.fileinits;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+import org.eclipse.jetty.start.BaseHome;
+import org.eclipse.jetty.start.config.ConfigSources;
+import org.eclipse.jetty.start.config.JettyBaseConfigSource;
+import org.eclipse.jetty.start.config.JettyHomeConfigSource;
+import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer.Coordinates;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class MavenLocalRepoFileInitializerTest
+{
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+    
+    @Rule
+    public TestingDir testdir = new TestingDir();
+    
+    private BaseHome baseHome;
+    
+    @Before
+    public void setupBaseHome() throws IOException
+    {
+        File homeDir = testdir.getEmptyDir();
+        
+        ConfigSources config = new ConfigSources();
+        config.add(new JettyHomeConfigSource(homeDir.toPath()));
+        config.add(new JettyBaseConfigSource(homeDir.toPath()));
+
+        this.baseHome = new BaseHome(config);
+    }
+
+    @Test
+    public void testGetCoordinate_NotMaven()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "http://www.eclipse.org/jetty";
+        Coordinates coords = repo.getCoordinates(URI.create(ref));
+        assertThat("Coords",coords,nullValue());
+    }
+
+    @Test
+    public void testGetCoordinate_InvalidMaven()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "maven://www.eclipse.org/jetty";
+        expectedException.expect(RuntimeException.class);
+        expectedException.expectMessage(containsString("Not a valid maven:// uri"));
+        repo.getCoordinates(URI.create(ref));
+    }
+
+    @Test
+    public void testGetCoordinate_Normal()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "maven://org.eclipse.jetty/jetty-start/9.3.x";
+        Coordinates coords = repo.getCoordinates(URI.create(ref));
+        assertThat("Coordinates",coords,notNullValue());
+
+        assertThat("coords.groupId",coords.groupId,is("org.eclipse.jetty"));
+        assertThat("coords.artifactId",coords.artifactId,is("jetty-start"));
+        assertThat("coords.version",coords.version,is("9.3.x"));
+        assertThat("coords.type",coords.type,is("jar"));
+        assertThat("coords.classifier",coords.classifier,nullValue());
+        
+        assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), 
+                is("http://central.maven.org/maven2/org/eclipse/jetty/jetty-start/9.3.x/jetty-start-9.3.x.jar"));
+    }
+
+    @Test
+    public void testGetCoordinate_Zip()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "maven://org.eclipse.jetty/jetty-distribution/9.3.x/zip";
+        Coordinates coords = repo.getCoordinates(URI.create(ref));
+        assertThat("Coordinates",coords,notNullValue());
+
+        assertThat("coords.groupId",coords.groupId,is("org.eclipse.jetty"));
+        assertThat("coords.artifactId",coords.artifactId,is("jetty-distribution"));
+        assertThat("coords.version",coords.version,is("9.3.x"));
+        assertThat("coords.type",coords.type,is("zip"));
+        assertThat("coords.classifier",coords.classifier,nullValue());
+        
+        assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), 
+                is("http://central.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.x/jetty-distribution-9.3.x.zip"));
+    }
+
+    @Test
+    public void testGetCoordinate_TestJar()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "maven://org.eclipse.jetty/jetty-http/9.3.x/jar/tests";
+        Coordinates coords = repo.getCoordinates(URI.create(ref));
+        assertThat("Coordinates",coords,notNullValue());
+
+        assertThat("coords.groupId",coords.groupId,is("org.eclipse.jetty"));
+        assertThat("coords.artifactId",coords.artifactId,is("jetty-http"));
+        assertThat("coords.version",coords.version,is("9.3.x"));
+        assertThat("coords.type",coords.type,is("jar"));
+        assertThat("coords.classifier",coords.classifier,is("tests"));
+        
+        assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), 
+                is("http://central.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar"));
+    }
+    
+    @Test
+    public void testGetCoordinate_Test_UnspecifiedType()
+    {
+        MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome);
+        String ref = "maven://org.eclipse.jetty/jetty-http/9.3.x//tests";
+        Coordinates coords = repo.getCoordinates(URI.create(ref));
+        assertThat("Coordinates",coords,notNullValue());
+
+        assertThat("coords.groupId",coords.groupId,is("org.eclipse.jetty"));
+        assertThat("coords.artifactId",coords.artifactId,is("jetty-http"));
+        assertThat("coords.version",coords.version,is("9.3.x"));
+        assertThat("coords.type",coords.type,is("jar"));
+        assertThat("coords.classifier",coords.classifier,is("tests"));
+        
+        assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), 
+                is("http://central.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar"));
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/graph/NodeTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/graph/NodeTest.java
new file mode 100644
index 0000000..5bab4c9
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/graph/NodeTest.java
@@ -0,0 +1,75 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.start.graph;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+public class NodeTest
+{
+    private static class TestNode extends Node<TestNode>
+    {
+        public TestNode(String name)
+        {
+            setName(name);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("TestNode[%s]",getName());
+        }
+    }
+
+    @Test
+    public void testNoNameMatch()
+    {
+        TestNode node = new TestNode("a");
+        Predicate predicate = new NamePredicate("b");
+        assertThat(node.toString(),node.matches(predicate),is(false));
+    }
+    
+    @Test
+    public void testNameMatch()
+    {
+        TestNode node = new TestNode("a");
+        Predicate predicate = new NamePredicate("a");
+        assertThat(node.toString(),node.matches(predicate),is(true));
+    }
+    
+    @Test
+    public void testAnySelectionMatch()
+    {
+        TestNode node = new TestNode("a");
+        node.addSelection(new Selection("test"));
+        Predicate predicate = new AnySelectionPredicate();
+        assertThat(node.toString(),node.matches(predicate),is(true));
+    }
+    
+    @Test
+    public void testAnySelectionNoMatch()
+    {
+        TestNode node = new TestNode("a");
+        // NOT Selected - node.addSelection(new Selection("test"));
+        Predicate predicate = new AnySelectionPredicate();
+        assertThat(node.toString(),node.matches(predicate),is(false));
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/util/CorrectMavenCentralRefs.java b/jetty-start/src/test/java/org/eclipse/jetty/start/util/CorrectMavenCentralRefs.java
new file mode 100644
index 0000000..48dfc7c
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/util/CorrectMavenCentralRefs.java
@@ -0,0 +1,256 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.util;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.start.PathFinder;
+import org.eclipse.jetty.start.PathMatchers;
+import org.eclipse.jetty.start.Utils;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+
+/**
+ * Simple utility to scan all of the mod files and correct references
+ * to maven central URL in [files] sections to the new maven:// syntax
+ */
+public class CorrectMavenCentralRefs
+{
+    public static void main(String[] args)
+    {
+        Path buildRoot = MavenTestingUtils.getProjectDir("..").toPath();
+        buildRoot = buildRoot.normalize().toAbsolutePath();
+
+        // Test to make sure we are in right directory
+        Path rootPomXml = buildRoot.resolve("pom.xml");
+        Path distPomXml = buildRoot.resolve("jetty-distribution/pom.xml");
+        if (!Files.exists(rootPomXml) || !Files.exists(distPomXml))
+        {
+            System.err.println("Not build root directory: " + buildRoot);
+            System.exit(-1);
+        }
+
+        try
+        {
+            new CorrectMavenCentralRefs().fix(buildRoot);
+        }
+        catch (Throwable t)
+        {
+            t.printStackTrace(System.err);
+        }
+    }
+
+    public void fix(Path buildRoot) throws IOException
+    {
+        // Find all of the *.mod files
+        PathFinder finder = new PathFinder();
+        finder.setFileMatcher("glob:**/*.mod");
+        finder.setBase(buildRoot);
+
+        // Matcher for target directories
+        PathMatcher targetMatcher = PathMatchers.getMatcher("glob:**/target/**");
+        PathMatcher testMatcher = PathMatchers.getMatcher("glob:**/test/**");
+
+        System.out.printf("Walking path: %s%n",buildRoot);
+        Set<FileVisitOption> options = Collections.emptySet();
+        Files.walkFileTree(buildRoot,options,30,finder);
+
+        System.out.printf("Found: %d hits%n",finder.getHits().size());
+        int count = 0;
+        for (Path path : finder.getHits())
+        {
+            if (Files.isDirectory(path))
+            {
+                // skip
+                continue;
+            }
+
+            if (targetMatcher.matches(path))
+            {
+                // skip
+                continue;
+            }
+
+            if (testMatcher.matches(path))
+            {
+                // skip
+                continue;
+            }
+
+            if (processModFile(path))
+            {
+                count++;
+            }
+        }
+
+        System.out.printf("Processed %,d modules",count);
+    }
+
+    private boolean processFileRefs(List<String> lines)
+    {
+        Pattern section = Pattern.compile("\\s*\\[([^]]*)\\]\\s*");
+        int filesStart = -1;
+        int filesEnd = -1;
+
+        // Find [files] section
+        String sectionId = null;
+        int lineCount = lines.size();
+        for (int i = 0; i < lineCount; i++)
+        {
+            String line = lines.get(i).trim();
+
+            Matcher sectionMatcher = section.matcher(line);
+
+            if (sectionMatcher.matches())
+            {
+                sectionId = sectionMatcher.group(1).trim().toUpperCase(Locale.ENGLISH);
+            }
+            else
+            {
+                if ("FILES".equals(sectionId))
+                {
+                    if (filesStart < 0)
+                    {
+                        filesStart = i;
+                    }
+                    filesEnd = i;
+                }
+            }
+        }
+
+        if (filesStart == (-1))
+        {
+            // no [files] section
+            return false;
+        }
+
+        // process lines, only in files section
+        int updated = 0;
+        for (int i = filesStart; i <= filesEnd; i++)
+        {
+            String line = lines.get(i);
+            String keyword = "maven.org/maven2/";
+            int idx = line.indexOf(keyword);
+            if (idx > 0)
+            {
+                int pipe = line.indexOf('|');
+                String rawpath = line.substring(idx + keyword.length(),pipe);
+                String destpath = line.substring(pipe + 1);
+
+                String parts[] = rawpath.split("/");
+                int rev = parts.length;
+                String filename = parts[--rev];
+
+                String type = "jar";
+                int ext = filename.lastIndexOf('.');
+                if (ext > 0)
+                {
+                    type = filename.substring(ext + 1);
+                }
+                String version = parts[--rev];
+                String artifactId = parts[--rev];
+                String groupId = Utils.join(parts,0,rev,".");
+
+                String classifier = filename.replaceFirst(artifactId + '-' + version,"");
+                classifier = classifier.replaceFirst('.' + type + '$',"");
+                if (Utils.isNotBlank(classifier) && (classifier.charAt(0) == '-'))
+                {
+                    classifier = classifier.substring(1);
+                }
+
+                StringBuilder murl = new StringBuilder();
+                murl.append("maven://");
+                murl.append(groupId).append('/');
+                murl.append(artifactId).append('/');
+                murl.append(version);
+                if (!"jar".equals(type) || Utils.isNotBlank(classifier))
+                {
+                    murl.append('/').append(type);
+                    if (Utils.isNotBlank(classifier))
+                    {
+                        murl.append('/').append(classifier);
+                    }
+                }
+
+                lines.set(i,murl.toString()+'|'+destpath);
+
+                updated++;
+            }
+        }
+
+        return (updated > 0);
+    }
+
+    private boolean processModFile(Path path) throws IOException
+    {
+        List<String> lines = readLines(path);
+        if (processFileRefs(lines))
+        {
+            // the lines are now dirty, save them.
+            System.out.printf("Updating: %s%n",path);
+            saveLines(path,lines);
+            return true;
+        }
+
+        // no update performed
+        return false;
+    }
+
+    private List<String> readLines(Path path) throws IOException
+    {
+        List<String> lines = new ArrayList<>();
+
+        try (BufferedReader reader = Files.newBufferedReader(path,StandardCharsets.UTF_8))
+        {
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                lines.add(line);
+            }
+        }
+
+        return lines;
+    }
+
+    private void saveLines(Path path, List<String> lines) throws IOException
+    {
+        try (BufferedWriter writer = Files.newBufferedWriter(path,StandardCharsets.UTF_8,StandardOpenOption.TRUNCATE_EXISTING))
+        {
+            for (String line : lines)
+            {
+                writer.write(line);
+                writer.write(System.lineSeparator());
+            }
+        }
+    }
+}
diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/util/RebuildTestResources.java b/jetty-start/src/test/java/org/eclipse/jetty/start/util/RebuildTestResources.java
new file mode 100644
index 0000000..287f338
--- /dev/null
+++ b/jetty-start/src/test/java/org/eclipse/jetty/start/util/RebuildTestResources.java
@@ -0,0 +1,197 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.start.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.StandardCopyOption;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+
+/**
+ * Utility class to rebuild the src/test/resources/dist-home from the active build tree.
+ * <p>
+ * Not really meant to be run with each build. Nor is it a good idea to attempt to do that (as this would introduce a dependency from jetty-start ->
+ * jetty-distribution which is a circular dependency)
+ */
+public class RebuildTestResources
+{
+    public static final String JETTY_VERSION = "9.3";
+    
+    public static void main(String[] args)
+    {
+        File realDistHome = MavenTestingUtils.getProjectDir("../jetty-distribution/target/distribution");
+        File outputDir = MavenTestingUtils.getTestResourceDir("dist-home");
+        try
+        {
+            new RebuildTestResources(realDistHome,outputDir).rebuild();
+        }
+        catch (Throwable t)
+        {
+            t.printStackTrace();
+        }
+    }
+
+    private static interface FileCopier
+    {
+        public void copy(Path from, Path to) throws IOException;
+    }
+
+    private static class NormalFileCopier implements FileCopier
+    {
+        @Override
+        public void copy(Path from, Path to) throws IOException
+        {
+            Files.copy(from,to,StandardCopyOption.REPLACE_EXISTING);
+        }
+    }
+
+    private static class TouchFileCopier implements FileCopier
+    {
+        @Override
+        public void copy(Path from, Path to) throws IOException
+        {
+            if(Files.exists(to)) 
+            {
+                // skip if it exists
+                return;
+            }
+            Files.createFile(to);
+        }
+    }
+
+    private static interface Renamer
+    {
+        public String getName(Path path);
+    }
+
+    private static class NoRenamer implements Renamer
+    {
+        @Override
+        public String getName(Path path)
+        {
+            return path.getFileName().toString();
+        }
+    }
+
+    private static class RegexRenamer implements Renamer
+    {
+        private final Pattern pat;
+        private final String replacement;
+
+        public RegexRenamer(String regex, String replacement)
+        {
+            this.pat = Pattern.compile(regex);
+            this.replacement = replacement;
+        }
+
+        @Override
+        public String getName(Path path)
+        {
+            String origName = path.getFileName().toString();
+            return pat.matcher(origName).replaceAll(replacement);
+        }
+    }
+
+    private final Path destDir;
+    private final Path srcDir;
+
+    public RebuildTestResources(File realDistHome, File outputDir) throws IOException
+    {
+        this.srcDir = realDistHome.toPath().toRealPath();
+        this.destDir = outputDir.toPath();
+    }
+
+    private void copyLibs() throws IOException
+    {
+        System.out.println("Copying libs (lib dir) ...");
+        Path libsDir = destDir.resolve("lib");
+        FS.ensureDirExists(libsDir.toFile());
+
+        PathMatcher matcher = getPathMatcher("glob:**.jar");
+        Renamer renamer = new RegexRenamer("-9\\.[0-9.]*(v[0-9-]*)?(-SNAPSHOT)?(RC[0-9])?(M[0-9])?","-" + JETTY_VERSION);
+        FileCopier copier = new TouchFileCopier();
+        copyDir(srcDir.resolve("lib"),libsDir,matcher,renamer,copier);
+    }
+
+    private void copyModules() throws IOException
+    {
+        System.out.println("Copying modules ...");
+        Path modulesDir = destDir.resolve("modules");
+        FS.ensureDirExists(modulesDir.toFile());
+
+        PathMatcher matcher = getPathMatcher("glob:**.mod");
+        Renamer renamer = new NoRenamer();
+        FileCopier copier = new NormalFileCopier();
+        copyDir(srcDir.resolve("modules"),modulesDir,matcher,renamer,copier);
+    }
+
+    private void copyXmls() throws IOException
+    {
+        System.out.println("Copying xmls (etc dir) ...");
+        Path xmlDir = destDir.resolve("etc");
+        FS.ensureDirExists(xmlDir.toFile());
+
+        PathMatcher matcher = getPathMatcher("glob:**.xml");
+        Renamer renamer = new NoRenamer();
+        FileCopier copier = new TouchFileCopier();
+        copyDir(srcDir.resolve("etc"),xmlDir,matcher,renamer,copier);
+    }
+
+    private void rebuild() throws IOException
+    {
+        copyModules();
+        copyLibs();
+        copyXmls();
+        System.out.println("Done");
+    }
+
+    private PathMatcher getPathMatcher(String pattern)
+    {
+        return FileSystems.getDefault().getPathMatcher(pattern);
+    }
+
+    private void copyDir(Path from, Path to, PathMatcher fileMatcher, Renamer renamer, FileCopier copier) throws IOException
+    {
+        Files.createDirectories(to);
+
+        for (Path path : Files.newDirectoryStream(from))
+        {
+            String name = renamer.getName(path);
+            Path dest = to.resolve(name);
+            if (Files.isDirectory(path))
+            {
+                copyDir(path,dest,fileMatcher,renamer,copier);
+            }
+            else
+            {
+                if (fileMatcher.matches(path))
+                {
+                    copier.copy(path,dest);
+                }
+            }
+        }
+    }
+}
diff --git a/jetty-start/src/test/resources/assert-home-with-http2.txt b/jetty-start/src/test/resources/assert-home-with-http2.txt
new file mode 100644
index 0000000..f02d164
--- /dev/null
+++ b/jetty-start/src/test/resources/assert-home-with-http2.txt
@@ -0,0 +1,83 @@
+# The XMLs we expect (order is important)
+XML|${jetty.base}/etc/home-base-warning.xml
+XML|${jetty.base}/etc/jetty.xml
+XML|${jetty.base}/etc/jetty-http.xml
+XML|${jetty.base}/etc/jetty-ssl.xml
+XML|${jetty.base}/etc/jetty-ssl-context.xml
+XML|${jetty.base}/etc/jetty-alpn.xml
+XML|${jetty.base}/etc/jetty-deploy.xml
+XML|${jetty.base}/etc/jetty-http2.xml
+XML|${jetty.base}/etc/jetty-plus.xml
+XML|${jetty.base}/etc/jetty-annotations.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-3.8.2.v20130121.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-1.2.1.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-1.2.1.jar
+LIB|${jetty.base}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
+LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.base}/lib/annotations/asm-5.0.1.jar
+LIB|${jetty.base}/lib/annotations/asm-commons-5.0.1.jar
+LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
+LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-api-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-client-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-common-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-server-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-servlet-9.3.jar
+LIB|${jetty.base}/lib/jetty-alpn-server-9.3.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/http2/http2-common-9.3.jar
+LIB|${jetty.base}/lib/http2/http2-hpack-9.3.jar
+LIB|${jetty.base}/lib/http2/http2-server-9.3.jar
+LIB|${jetty.base}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/jetty-annotations-9.3.jar
+LIB|${jetty.base}/lib/jetty-http-9.3.jar
+LIB|${jetty.base}/lib/jetty-io-9.3.jar
+LIB|${jetty.base}/lib/jetty-deploy-9.3.jar
+LIB|${jetty.base}/lib/jetty-plus-9.3.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/jetty-security-9.3.jar
+LIB|${jetty.base}/lib/jetty-server-9.3.jar
+LIB|${jetty.base}/lib/jetty-servlet-9.3.jar
+LIB|${jetty.base}/lib/jetty-util-9.3.jar
+LIB|${jetty.base}/lib/jetty-webapp-9.3.jar
+LIB|${jetty.base}/lib/jetty-xml-9.3.jar
+LIB|${jetty.base}/lib/jetty-jndi-9.3.jar
+
+
+# The Properties we expect (order is irrelevant)
+# (these are the properties we actually set in the configuration)
+# PROP|java.version=1.8.0_31
+PROP|jetty.http.port=8080
+PROP|jetty.httpConfig.delayDispatchUntilContent=false
+PROP|jetty.server.dumpAfterStart=false
+PROP|jetty.server.dumpBeforeStop=false
+PROP|jetty.httpConfig.outputBufferSize=32768
+PROP|jetty.httpConfig.requestHeaderSize=8192
+PROP|jetty.httpConfig.responseHeaderSize=8192
+PROP|jetty.httpConfig.sendDateHeader=false
+PROP|jetty.httpConfig.sendServerVersion=true
+PROP|jetty.threadPool.maxThreads=200
+PROP|jetty.threadPool.minThreads=10
+PROP|jetty.threadPool.idleTimeout=60000
+
+# JVM Args
+JVM|-Xms1024m
+JVM|-Xmx1024m
+
+# Downloads
+DOWNLOAD|maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
+DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/test/config/etc/keystore?id=master|etc/keystore
+
+# Files
+FILE|lib/
+FILE|lib/ext/
+FILE|lib/alpn/
+FILE|resources/
+FILE|webapps/
diff --git a/jetty-start/src/test/resources/assert-home-with-jvm.txt b/jetty-start/src/test/resources/assert-home-with-jvm.txt
index 9774d97..871aa8d 100644
--- a/jetty-start/src/test/resources/assert-home-with-jvm.txt
+++ b/jetty-start/src/test/resources/assert-home-with-jvm.txt
@@ -1,44 +1,75 @@
 # The XMLs we expect (order is important)
-XML|${jetty.base}/etc/jetty-jmx.xml
+XML|${jetty.base}/etc/home-base-warning.xml
 XML|${jetty.base}/etc/jetty.xml
 XML|${jetty.base}/etc/jetty-http.xml
+XML|${jetty.base}/etc/jetty-deploy.xml
 XML|${jetty.base}/etc/jetty-plus.xml
 XML|${jetty.base}/etc/jetty-annotations.xml
-XML|${jetty.base}/etc/jetty-websockets.xml
+XML|${jetty.base}/etc/jetty-jmx.xml
 XML|${jetty.base}/etc/jetty-logging.xml
 
 # The LIBs we expect (order is irrelevant)
-LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
-LIB|${jetty.base}/lib/annotations/org.objectweb.asm-TEST.jar
-LIB|${jetty.base}/lib/jetty-annotations-TEST.jar
-LIB|${jetty.base}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.base}/lib/jetty-http-TEST.jar
-LIB|${jetty.base}/lib/jetty-io-TEST.jar
-LIB|${jetty.base}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.base}/lib/jetty-jndi-TEST.jar
-LIB|${jetty.base}/lib/jetty-plus-TEST.jar
-LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.base}/lib/jetty-security-TEST.jar
-LIB|${jetty.base}/lib/jetty-server-TEST.jar
-LIB|${jetty.base}/lib/jetty-util-TEST.jar
-LIB|${jetty.base}/lib/jetty-xml-TEST.jar
-LIB|${jetty.base}/lib/jndi/javax.activation-1.1.jar
-LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
-LIB|${jetty.base}/lib/servlet-api-3.1.jar
-LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-api-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-client-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-common-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-server-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-servlet-TEST.jar
 LIB|${maven-test-resources}/extra-resources
 LIB|${maven-test-resources}/extra-libs/example.jar
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-3.8.2.v20130121.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-1.2.1.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-1.2.1.jar
+LIB|${jetty.base}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
+LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.base}/lib/annotations/asm-5.0.1.jar
+LIB|${jetty.base}/lib/annotations/asm-commons-5.0.1.jar
+LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
+LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-api-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-client-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-common-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-server-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-servlet-9.3.jar
+LIB|${jetty.base}/lib/jetty-annotations-9.3.jar
+LIB|${jetty.base}/lib/jetty-http-9.3.jar
+LIB|${jetty.base}/lib/jetty-io-9.3.jar
+LIB|${jetty.base}/lib/jetty-deploy-9.3.jar
+LIB|${jetty.base}/lib/jetty-plus-9.3.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/jetty-security-9.3.jar
+LIB|${jetty.base}/lib/jetty-server-9.3.jar
+LIB|${jetty.base}/lib/jetty-servlet-9.3.jar
+LIB|${jetty.base}/lib/jetty-util-9.3.jar
+LIB|${jetty.base}/lib/jetty-webapp-9.3.jar
+LIB|${jetty.base}/lib/jetty-xml-9.3.jar
+LIB|${jetty.base}/lib/jetty-jndi-9.3.jar
+
 
 # The Properties we expect (order is irrelevant)
-# PROP|jetty.port=9090
+# (these are the properties we actually set in the configuration)
+# PROP|jetty.http.port=8080
+# (these are the ones set by default from jetty.home modules)
+PROP|jetty.http.port=8080
+PROP|jetty.httpConfig.delayDispatchUntilContent=false
+PROP|jetty.server.dumpAfterStart=false
+PROP|jetty.server.dumpBeforeStop=false
+PROP|jetty.httpConfig.outputBufferSize=32768
+PROP|jetty.httpConfig.requestHeaderSize=8192
+PROP|jetty.httpConfig.responseHeaderSize=8192
+PROP|jetty.httpConfig.sendDateHeader=false
+PROP|jetty.httpConfig.sendServerVersion=true
+PROP|jetty.threadPool.maxThreads=200
+PROP|jetty.threadPool.minThreads=10
+PROP|jetty.threadPool.idleTimeout=60000
 
 # JVM Args
 JVM|-Xms1024m
 JVM|-Xmx1024m
+
+# Files / Directories to create
+FILE|lib/
+FILE|lib/ext/
+FILE|resources/
+FILE|webapps/
diff --git a/jetty-start/src/test/resources/assert-home-with-spdy.txt b/jetty-start/src/test/resources/assert-home-with-spdy.txt
deleted file mode 100644
index aa5aea9..0000000
--- a/jetty-start/src/test/resources/assert-home-with-spdy.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.base}/etc/jetty-jmx.xml
-XML|${jetty.base}/etc/protonego-alpn.xml
-XML|${jetty.base}/etc/jetty.xml
-XML|${jetty.base}/etc/jetty-http.xml
-XML|${jetty.base}/etc/jetty-ssl.xml
-XML|${jetty.base}/etc/jetty-plus.xml
-XML|${jetty.base}/etc/jetty-spdy.xml
-XML|${jetty.base}/etc/jetty-annotations.xml
-XML|${jetty.base}/etc/jetty-deploy.xml
-XML|${jetty.base}/etc/jetty-websockets.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
-LIB|${jetty.base}/lib/annotations/org.objectweb.asm-TEST.jar
-LIB|${jetty.base}/lib/jetty-annotations-TEST.jar
-LIB|${jetty.base}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.base}/lib/jetty-http-TEST.jar
-LIB|${jetty.base}/lib/jetty-io-TEST.jar
-LIB|${jetty.base}/lib/jetty-deploy-TEST.jar
-LIB|${jetty.base}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.base}/lib/jetty-jndi-TEST.jar
-LIB|${jetty.base}/lib/jetty-plus-TEST.jar
-LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.base}/lib/jetty-security-TEST.jar
-LIB|${jetty.base}/lib/jetty-server-TEST.jar
-LIB|${jetty.base}/lib/jetty-servlet-TEST.jar
-LIB|${jetty.base}/lib/jetty-util-TEST.jar
-LIB|${jetty.base}/lib/jetty-webapp-TEST.jar
-LIB|${jetty.base}/lib/jetty-xml-TEST.jar
-LIB|${jetty.base}/lib/spdy/spdy-client-TEST.jar
-LIB|${jetty.base}/lib/spdy/spdy-core-TEST.jar
-LIB|${jetty.base}/lib/spdy/spdy-http-common-TEST.jar
-LIB|${jetty.base}/lib/spdy/spdy-http-server-TEST.jar
-LIB|${jetty.base}/lib/spdy/spdy-server-TEST.jar
-LIB|${jetty.base}/lib/jndi/javax.activation-1.1.jar
-LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
-LIB|${jetty.base}/lib/servlet-api-3.1.jar
-LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-api-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-client-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-common-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-server-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-servlet-TEST.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|java.version=1.7.0_60
-PROP|jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
-PROP|jetty.keystore=etc/keystore
-PROP|jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-PROP|jetty.secure.port=8443
-PROP|jetty.truststore=etc/keystore
-PROP|jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-PROP|protonego=alpn
-PROP|spdy.port=8443
-PROP|spdy.timeout=30000
-
-# JVM Args
-JVM|-Xms1024m
-JVM|-Xmx1024m
-
-# Downloads
-DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
-
-# Files
-FILE|lib/
-FILE|lib/alpn/
-
-
diff --git a/jetty-start/src/test/resources/assert-home.txt b/jetty-start/src/test/resources/assert-home.txt
index 5be8d46..70515e3 100644
--- a/jetty-start/src/test/resources/assert-home.txt
+++ b/jetty-start/src/test/resources/assert-home.txt
@@ -1,37 +1,64 @@
 # The XMLs we expect (order is important)
-XML|${jetty.base}/etc/jetty-jmx.xml
+XML|${jetty.base}/etc/home-base-warning.xml
 XML|${jetty.base}/etc/jetty.xml
 XML|${jetty.base}/etc/jetty-http.xml
+XML|${jetty.base}/etc/jetty-deploy.xml
 XML|${jetty.base}/etc/jetty-plus.xml
 XML|${jetty.base}/etc/jetty-annotations.xml
-XML|${jetty.base}/etc/jetty-websockets.xml
 
 # The LIBs we expect (order is irrelevant)
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
+LIB|${jetty.base}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-3.8.2.v20130121.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-1.2.1.jar
+LIB|${jetty.base}/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-1.2.1.jar
+LIB|${jetty.base}/lib/annotations/asm-5.0.1.jar
+LIB|${jetty.base}/lib/annotations/asm-commons-5.0.1.jar
 LIB|${jetty.base}/lib/annotations/javax.annotation-api-1.2.jar
-LIB|${jetty.base}/lib/annotations/org.objectweb.asm-TEST.jar
-LIB|${jetty.base}/lib/jetty-annotations-TEST.jar
-LIB|${jetty.base}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.base}/lib/jetty-http-TEST.jar
-LIB|${jetty.base}/lib/jetty-io-TEST.jar
-LIB|${jetty.base}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.base}/lib/jetty-jndi-TEST.jar
-LIB|${jetty.base}/lib/jetty-plus-TEST.jar
-LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.base}/lib/jetty-security-TEST.jar
-LIB|${jetty.base}/lib/jetty-server-TEST.jar
-LIB|${jetty.base}/lib/jetty-util-TEST.jar
-LIB|${jetty.base}/lib/jetty-xml-TEST.jar
-LIB|${jetty.base}/lib/jndi/javax.activation-1.1.jar
+LIB|${jetty.base}/lib/jetty-jndi-9.3.jar
+LIB|${jetty.base}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
 LIB|${jetty.base}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.base}/lib/jetty-annotations-9.3.jar
+LIB|${jetty.base}/lib/jetty-http-9.3.jar
+LIB|${jetty.base}/lib/jetty-io-9.3.jar
+LIB|${jetty.base}/lib/jetty-deploy-9.3.jar
+LIB|${jetty.base}/lib/jetty-plus-9.3.jar
+LIB|${jetty.base}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.base}/lib/jetty-security-9.3.jar
+LIB|${jetty.base}/lib/jetty-server-9.3.jar
+LIB|${jetty.base}/lib/jetty-servlet-9.3.jar
+LIB|${jetty.base}/lib/jetty-util-9.3.jar
+LIB|${jetty.base}/lib/jetty-webapp-9.3.jar
+LIB|${jetty.base}/lib/jetty-xml-9.3.jar
 LIB|${jetty.base}/lib/servlet-api-3.1.jar
 LIB|${jetty.base}/lib/websocket/javax.websocket-api-1.0.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-api-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-client-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-common-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-server-TEST.jar
-LIB|${jetty.base}/lib/websocket/websocket-servlet-TEST.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-client-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/javax-websocket-server-impl-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-api-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-client-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-common-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-server-9.3.jar
+LIB|${jetty.base}/lib/websocket/websocket-servlet-9.3.jar
 
 # The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
+# (these are the properties we actually set in the configuration)
+PROP|jetty.http.port=8080
+# (these are the ones set by default from jetty.home modules)
+PROP|jetty.httpConfig.delayDispatchUntilContent=false
+PROP|jetty.server.dumpAfterStart=false
+PROP|jetty.server.dumpBeforeStop=false
+PROP|jetty.httpConfig.outputBufferSize=32768
+PROP|jetty.httpConfig.requestHeaderSize=8192
+PROP|jetty.httpConfig.responseHeaderSize=8192
+PROP|jetty.httpConfig.sendDateHeader=false
+PROP|jetty.httpConfig.sendServerVersion=true
+PROP|jetty.threadPool.maxThreads=200
+PROP|jetty.threadPool.minThreads=10
+PROP|jetty.threadPool.idleTimeout=60000
+
+# Files
+FILE|lib/
+FILE|lib/ext/
+FILE|resources/
+FILE|webapps/
diff --git a/jetty-start/src/test/resources/dist-home/etc/protonego-alpn.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-alpn.xml
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/etc/protonego-alpn.xml
rename to jetty-start/src/test/resources/dist-home/etc/jetty-alpn.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-debuglog.xml
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
rename to jetty-start/src/test/resources/dist-home/etc/jetty-debuglog.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-spdy.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-gzip.xml
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/etc/jetty-spdy.xml
rename to jetty-start/src/test/resources/dist-home/etc/jetty-gzip.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-http2.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-http2.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-http2c.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-http2c.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/protonego-alpn.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-infinispan.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/protonego-alpn.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-infinispan.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-jdbc-sessions.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-jdbc-sessions.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-nosql.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-nosql.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-spdy-proxy.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-spdy-proxy.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/etc/jetty-spdy-proxy.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-ssl-context.xml
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/etc/jetty-debug.xml
copy to jetty-start/src/test/resources/dist-home/etc/jetty-ssl-context.xml
diff --git a/jetty-start/src/test/resources/dist-home/etc/jetty-xinetd.xml b/jetty-start/src/test/resources/dist-home/etc/jetty-xinetd.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/etc/jetty-xinetd.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/etc/protonego-npn.xml b/jetty-start/src/test/resources/dist-home/etc/protonego-npn.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/etc/protonego-npn.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.9.M3.jar b/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.9.M3.jar
rename to jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.9.M3.jar b/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.9.M3.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.9.M3.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/cdi-core-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/cdi-core-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/cdi-servlet-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/cdi-servlet-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/cdi-websocket-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/cdi-websocket-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-server-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-client-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-server-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/fcgi/fcgi-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar b/jetty-start/src/test/resources/dist-home/lib/http2/http2-common-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar
rename to jetty-start/src/test/resources/dist-home/lib/http2/http2-common-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar b/jetty-start/src/test/resources/dist-home/lib/http2/http2-hpack-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar
copy to jetty-start/src/test/resources/dist-home/lib/http2/http2-hpack-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar b/jetty-start/src/test/resources/dist-home/lib/http2/http2-server-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jsp/jetty-jsp-jdt-2.3.3.jar
copy to jetty-start/src/test/resources/dist-home/lib/http2/http2-server-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-alpn-server-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-alpn-server-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-alpn-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-alpn-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-alpn-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-annotations-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-annotations-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-annotations-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-annotations-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-annotations-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-client-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-client-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-alpn-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-continuation-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/jetty-alpn-client-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/jetty-continuation-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-continuation-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-continuation-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-continuation-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-deploy-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-deploy-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-deploy-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-deploy-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-deploy-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-http-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-http-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-http-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-http-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-http-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-infinispan-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-infinispan-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-io-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-io-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-io-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-io-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-io-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jaas-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-jaas-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-jaas-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jaas-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-jaas-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jaspi-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-jaspi-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-jaspi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jaspi-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-jaspi-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jmx-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-jmx-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-jmx-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jmx-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-jmx-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jndi-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-jndi-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-jndi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-jndi-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-jndi-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-nosql-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-nosql-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-plus-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-plus-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-plus-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-plus-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-plus-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-proxy-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-proxy-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-proxy-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-proxy-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-proxy-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-quickstart-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-quickstart-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-quickstart-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-quickstart-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-quickstart-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-rewrite-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-rewrite-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-rewrite-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-rewrite-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-rewrite-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-security-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-security-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-security-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-security-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-security-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-server-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-server-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-servlet-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-servlet-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-servlet-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-servlet-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-servlet-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-servlets-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-servlets-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-servlets-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-servlets-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-servlets-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-util-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-util-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-util-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-util-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-util-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-webapp-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-webapp-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-webapp-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-webapp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-webapp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-xml-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/jetty-cdi-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/jetty-xml-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/jetty-xml-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/jetty-xml-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jetty-xml-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.el-3.0.0.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/javax.el-3.0.0.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.el-3.0.0.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-2.3.2.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-2.3.2.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-2.3.2.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-api-2.3.1.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-api-2.3.1.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp-api-2.3.1.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp.jstl-1.2.2.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp.jstl-1.2.2.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/javax.servlet.jsp.jstl-1.2.2.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-1.2.0.v201105211821.jar b/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/monitor/jetty-monitor-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/monitor/jetty-monitor-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/monitor/jetty-monitor-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/monitor/jetty-monitor-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/setuid/jetty-setuid-java-1.0.1.jar b/jetty-start/src/test/resources/dist-home/lib/setuid/jetty-setuid-java-1.0.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/setuid/jetty-setuid-java-1.0.1.jar
rename to jetty-start/src/test/resources/dist-home/lib/setuid/jetty-setuid-java-1.0.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-core-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-core-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-core-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-common-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-common-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-common-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-http-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/spdy/spdy-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/spring/jetty-spring-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/spring/jetty-spring-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/spring/jetty-spring-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/spring/jetty-spring-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-server-impl-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-client-impl-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-server-impl-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-server-impl-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-server-impl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/websocket/javax-websocket-server-impl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-9.3.jar
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar
rename to jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-client-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/websocket/websocket-client-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-client-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-common-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/websocket/websocket-common-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-common-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-common-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-common-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-server-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/websocket/websocket-server-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-server-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-servlet-9.3.jar
similarity index 100%
copy from jetty-start/src/test/resources/dist-home/lib/websocket/websocket-api-TEST.jar
copy to jetty-start/src/test/resources/dist-home/lib/websocket/websocket-servlet-9.3.jar
diff --git a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-servlet-TEST.jar b/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-servlet-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/dist-home/lib/websocket/websocket-servlet-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_05.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_05.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_05.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_11.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_11.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_11.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_20.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_20.mod
new file mode 100644
index 0000000..cb91b4c
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_20.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_25.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_25.mod
new file mode 100644
index 0000000..6d6d75e
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_25.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.2.v20141202|lib/alpn/alpn-boot-8.1.2.v20141202.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.2.v20141202.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_31.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_31.mod
new file mode 100644
index 0000000..e52bd23
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_31.mod
@@ -0,0 +1,8 @@
+[name]
+alpn-boot
+
+[files]
+maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
+
+[exec]
+-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_40.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_40.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_40.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_40.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_45.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_45.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_45.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_45.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_51.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_51.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_51.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_51.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_60.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_60.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_60.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_60.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_65.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_65.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_65.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_65.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_66.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_66.mod
similarity index 100%
rename from jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_66.mod
rename to jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_66.mod
diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn.mod b/jetty-start/src/test/resources/dist-home/modules/alpn.mod
new file mode 100644
index 0000000..7928e64
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/alpn.mod
@@ -0,0 +1,53 @@
+# ALPN is provided via a -Xbootclasspath that modifies the secure connections
+# in java to support the ALPN layer needed for HTTP/2.
+#
+# This modification has a tight dependency on specific recent updates of
+# Java 1.7 and Java 1.8 (Java versions prior to 1.7u40 are not supported).
+#
+# The alpn module will use an appropriate alpn-boot jar for your
+# specific version of Java.
+#
+# IMPORTANT: Versions of Java that exist after this module was created are
+#            not guaranteed to work with existing alpn-boot jars, and might
+#            need a new alpn-boot to be created / tested / deployed by the
+#            Jetty project in order to provide support for these future
+#            Java versions.
+#
+# All versions of alpn-boot can be found at
+# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
+
+[name]
+alpn
+
+[depend]
+ssl
+alpn-impl/alpn-${java.version}
+
+[lib]
+lib/jetty-alpn-client-${jetty.version}.jar
+lib/jetty-alpn-server-${jetty.version}.jar
+
+[xml]
+etc/jetty-alpn.xml
+
+[files]
+lib/
+lib/alpn/
+
+[ini-template]
+## Overrides the order protocols are chosen by the server.
+## The default order is that specified by the order of the
+## modules declared in start.ini.
+# jetty.alpn.protocols=h2-16,http/1.1
+
+## Specifies what protocol to use when negotiation fails.
+# jetty.alpn.defaultProtocol=http/1.1
+
+## ALPN debug logging on System.err
+# jetty.alpn.debug=false
+
+[license]
+ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
+ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
+http://github.com/jetty-project/jetty-alpn
+http://openjdk.java.net/legal/gplv2+ce.html
diff --git a/jetty-start/src/test/resources/dist-home/modules/apache-jsp.mod b/jetty-start/src/test/resources/dist-home/modules/apache-jsp.mod
new file mode 100644
index 0000000..5123670
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/apache-jsp.mod
@@ -0,0 +1,10 @@
+#
+# Apache JSP Module
+#
+
+[name]
+apache-jsp
+
+[lib]
+lib/apache-jsp/*.jar
+
diff --git a/jetty-start/src/test/resources/dist-home/modules/apache-jstl.mod b/jetty-start/src/test/resources/dist-home/modules/apache-jstl.mod
new file mode 100644
index 0000000..e4a9001
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/apache-jstl.mod
@@ -0,0 +1,9 @@
+#
+# Apache JSTL 
+#
+
+[name]
+apache-jstl
+
+[lib]
+lib/apache-jstl/*.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/cdi.mod b/jetty-start/src/test/resources/dist-home/modules/cdi.mod
index 68dea58..ebffb55 100644
--- a/jetty-start/src/test/resources/dist-home/modules/cdi.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/cdi.mod
@@ -1,5 +1,5 @@
 #
-# CDI / Weld Jetty module
+# [EXPERIMENTAL] CDI / Weld Jetty module
 #
 
 [depend]
@@ -10,12 +10,24 @@
 jsp
 
 [files]
-lib/weld/
-http://central.maven.org/maven2/org/jboss/weld/servlet/weld-servlet/2.2.5.Final/weld-servlet-2.2.5.Final.jar|lib/weld/weld-servlet-2.2.5.Final.jar
+lib/cdi/
+maven://javax.enterprise/cdi-api/1.2|lib/cdi/javax.enterprise.cdi-api-1.2.jar
+maven://javax.interceptor/javax.interceptor-api/1.2|lib/cdi/javax.interceptor-api-1.2.jar
+maven://javax.inject/javax.inject/1|lib/cdi/javax.inject-1.0.jar
+maven://org.jboss.weld.servlet/weld-servlet-core/2.2.9.Final|lib/cdi/weld-servlet-core-2.2.9.Final.jar
+maven://org.jboss.weld.environment/weld-environment-common/2.2.9.Final|lib/cdi/weld-environment-common-2.2.9.Final.jar
+maven://org.jboss.weld/weld-core-impl/2.2.9.Final|lib/cdi/weld-core-impl-2.2.9.Final.jar
+maven://org.jboss.classfilewriter/jboss-classfilewriter/1.0.5.Final|lib/cdi/jboss-classfilewriter-1.0.5.Final.jar
+maven://com.google.guava/guava/13.0.1|lib/cdi/com.google.guava.guava-13.0.1.jar
+maven://org.jboss.weld/weld-spi/2.2.SP3|lib/cdi/weld-spi-2.2.SP3.jar
+maven://org.jboss.weld/weld-api/2.2.SP3|lib/cdi/weld-api-2.2.SP3.jar
+maven://org.jboss.logging/jboss-logging/3.1.3.GA|lib/cdi/jboss-logging-3.1.3.GA.jar
+
 
 [lib]
-lib/weld/weld-servlet-2.2.5.Final.jar
-lib/jetty-cdi-${jetty.version}.jar
+lib/cdi/*.jar
+lib/cdi-core-${jetty.version}.jar
+lib/cdi-servlet-${jetty.version}.jar
 
 [xml]
 etc/jetty-cdi.xml
diff --git a/jetty-start/src/test/resources/dist-home/modules/debug.mod b/jetty-start/src/test/resources/dist-home/modules/debug.mod
deleted file mode 100644
index f740ea2..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/debug.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Debug module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-debug.xml
diff --git a/jetty-start/src/test/resources/dist-home/modules/debuglog.mod b/jetty-start/src/test/resources/dist-home/modules/debuglog.mod
new file mode 100644
index 0000000..ba8b60a
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/debuglog.mod
@@ -0,0 +1,25 @@
+#
+# Debug module
+#
+
+[depend]
+server
+
+[files]
+logs/
+
+[xml]
+etc/jetty-debuglog.xml
+
+[ini-template]
+## Logging directory (relative to $jetty.base)
+# jetty.debuglog.dir=logs
+
+## Whether to append to existing file
+# jetty.debuglog.append=false
+
+## How many days to retain old log files
+# jetty.debuglog.retainDays=90
+
+## Timezone of the log entries
+# jetty.debuglog.timezone=GMT
diff --git a/jetty-start/src/test/resources/dist-home/modules/deploy.mod b/jetty-start/src/test/resources/dist-home/modules/deploy.mod
index f16b3f2..f567a20 100644
--- a/jetty-start/src/test/resources/dist-home/modules/deploy.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/deploy.mod
@@ -15,7 +15,11 @@
 etc/jetty-deploy.xml
 
 [ini-template]
-## DeployManager configuration
-# Monitored Directory name (relative to jetty.base)
-# jetty.deploy.monitoredDirName=webapps
+# Monitored directory name (relative to $jetty.base)
+# jetty.deploy.monitoredDir=webapps
 
+# Monitored directory scan period (seconds)
+# jetty.deploy.scanInterval=1
+
+# Whether to extract *.war files
+# jetty.deploy.extractWars=true
diff --git a/jetty-start/src/test/resources/dist-home/modules/fcgi.mod b/jetty-start/src/test/resources/dist-home/modules/fcgi.mod
index e837b00..14152d5 100644
--- a/jetty-start/src/test/resources/dist-home/modules/fcgi.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/fcgi.mod
@@ -12,4 +12,4 @@
 
 [ini-template]
 ## For configuration of FastCGI contexts, see
-## TODO: documentation url here
+## https://www.eclipse.org/jetty/documentation/current/fastcgi.html
diff --git a/jetty-start/src/test/resources/dist-home/modules/gzip.mod b/jetty-start/src/test/resources/dist-home/modules/gzip.mod
new file mode 100644
index 0000000..1efc834
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/gzip.mod
@@ -0,0 +1,23 @@
+#
+# GZIP module
+# Applies GzipHandler to entire server
+#
+
+[depend]
+server
+
+[xml]
+etc/jetty-gzip.xml
+
+[ini-template]
+## Minimum content length after which gzip is enabled
+# jetty.gzip.minGzipSize=2048
+
+## Check whether a file with *.gz extension exists
+# jetty.gzip.checkGzExists=false
+
+## Gzip compression level (-1 for default)
+# jetty.gzip.compressionLevel=-1
+
+## User agents for which gzip is disabled
+# jetty.gzip.excludedUserAgent=.*MSIE.6\.0.*
diff --git a/jetty-start/src/test/resources/dist-home/modules/hawtio.mod b/jetty-start/src/test/resources/dist-home/modules/hawtio.mod
index 2dfb31b..f6d0d9d 100644
--- a/jetty-start/src/test/resources/dist-home/modules/hawtio.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/hawtio.mod
@@ -22,7 +22,7 @@
 http://www.apache.org/licenses/LICENSE-2.0.html
 
 [ini-template]
-
+## Hawt.io configuration
 -Dhawtio.authenticationEnabled=false
 -Dhawtio.dirname=/dirname
 -Dhawtio.config.dir=${jetty.base}/etc/hawtio
diff --git a/jetty-start/src/test/resources/dist-home/modules/http.mod b/jetty-start/src/test/resources/dist-home/modules/http.mod
index dc34bc3..01e9862 100644
--- a/jetty-start/src/test/resources/dist-home/modules/http.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/http.mod
@@ -11,17 +11,26 @@
 [ini-template]
 ### HTTP Connector Configuration
 
-## HTTP port to listen on
-jetty.port=8080
+## Connector host/address to bind to
+# jetty.http.host=0.0.0.0
 
-## HTTP idle timeout in milliseconds
-http.timeout=30000
+## Connector port to listen on
+# jetty.http.port=8080
 
-## HTTP Socket.soLingerTime in seconds. (-1 to disable)
-# http.soLingerTime=-1
+## Connector idle timeout in milliseconds
+# jetty.http.idleTimeout=30000
 
-## Parameters to control the number and priority of acceptors and selectors
-# http.selectors=1
-# http.acceptors=1
-# http.selectorPriorityDelta=0
-# http.acceptorPriorityDelta=0
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.http.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.http.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.http.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.http.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.http.acceptorPriorityDelta=0
diff --git a/jetty-start/src/test/resources/dist-home/modules/http2.mod b/jetty-start/src/test/resources/dist-home/modules/http2.mod
new file mode 100644
index 0000000..585c1fa
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/http2.mod
@@ -0,0 +1,20 @@
+#
+# HTTP2 Support Module
+#
+
+[depend]
+ssl
+alpn
+
+[lib]
+lib/http2/*.jar
+
+[xml]
+etc/jetty-http2.xml
+
+[ini-template]
+## Max number of concurrent streams per connection
+# jetty.http2.maxConcurrentStreams=1024
+
+## Initial stream send (server to client) window
+# jetty.http2.initialStreamSendWindow=65535
diff --git a/jetty-start/src/test/resources/dist-home/modules/http2c.mod b/jetty-start/src/test/resources/dist-home/modules/http2c.mod
new file mode 100644
index 0000000..15883ca
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/http2c.mod
@@ -0,0 +1,22 @@
+#
+# HTTP2 Clear Text Support Module
+# This module adds support for HTTP/2 clear text to the
+# HTTP/1 clear text connector (defined in jetty-http.xml).
+# The resulting connector will accept both HTTP/1 and HTTP/2 connections.
+#
+
+[depend]
+http
+
+[lib]
+lib/http2/*.jar
+
+[xml]
+etc/jetty-http2c.xml
+
+[ini-template]
+## Max number of concurrent streams per connection
+# jetty.http2.maxConcurrentStreams=1024
+
+## Initial stream send (server to client) window
+# jetty.http2.initialStreamSendWindow=65535
diff --git a/jetty-start/src/test/resources/dist-home/modules/https.mod b/jetty-start/src/test/resources/dist-home/modules/https.mod
index bd1b718..092e0d7 100644
--- a/jetty-start/src/test/resources/dist-home/modules/https.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/https.mod
@@ -5,15 +5,9 @@
 [depend]
 ssl
 
+[optional]
+http2
+
 [xml]
 etc/jetty-https.xml
 
-[ini-template]
-## HTTPS Configuration
-# HTTP port to listen on
-https.port=8443
-# HTTPS idle timeout in milliseconds
-https.timeout=30000
-# HTTPS Socket.soLingerTime in seconds. (-1 to disable)
-# https.soLingerTime=-1
-
diff --git a/jetty-start/src/test/resources/dist-home/modules/infinispan.mod b/jetty-start/src/test/resources/dist-home/modules/infinispan.mod
new file mode 100644
index 0000000..afa39fc
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/infinispan.mod
@@ -0,0 +1,33 @@
+#
+# Jetty Infinispan module
+#
+
+[depend]
+annotations
+webapp
+
+[files]
+maven://org.infinispan/infinispan-core/7.1.1.Final|lib/infinispan/infinispan-core-7.1.1.Final.jar
+maven://org.infinispan/infinispan-commons/7.1.1.Final|lib/infinispan/infinispan-commons-7.1.1.Final.jar
+maven://org.jgroups/jgroups/3.6.1.Final|lib/infinispan/jgroups-3.6.1.Final.jar
+maven://org.jboss.marshalling/jboss-marshalling-osgi/1.4.4.Final|lib/infinispan/jboss-marshalling-osgi-1.4.4.Final.jar
+maven://org.jboss.logging/jboss-logging/3.1.2.GA|lib/infinispan/jboss-logging-3.1.2.GA.jar
+
+[lib]
+lib/jetty-infinispan-${jetty.version}.jar
+lib/infinispan/*.jar
+
+[xml]
+etc/jetty-infinispan.xml
+
+[license]
+Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+http://infinispan.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini-template]
+## Infinispan Session config
+
+## Unique identifier for this node in the cluster
+# jetty.infinispanSession.workerName=node1
+
diff --git a/jetty-start/src/test/resources/dist-home/modules/jaas.mod b/jetty-start/src/test/resources/dist-home/modules/jaas.mod
index 4932140..fee3f59 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jaas.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jaas.mod
@@ -12,5 +12,6 @@
 etc/jetty-jaas.xml
 
 [ini-template]
-## JAAS Configuration
-jaas.login.conf=etc/login.conf
+## The file location (relative to $jetty.base) for the
+## JAAS "java.security.auth.login.config" system property
+# jetty.jaas.login.conf=etc/login.conf
diff --git a/jetty-start/src/test/resources/dist-home/modules/jamon.mod b/jetty-start/src/test/resources/dist-home/modules/jamon.mod
index 2aeb2ad..2d1f144 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jamon.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jamon.mod
@@ -13,8 +13,8 @@
 
 [files]
 lib/jamon/
-http://central.maven.org/maven2/com/jamonapi/jamon/2.79/jamon-2.79.jar|lib/jamon/jamon-2.79.jar
-http://central.maven.org/maven2/com/jamonapi/jamon_war/2.79/jamon_war-2.79.war|lib/jamon/jamon.war
+maven://com.jamonapi/jamon/2.79|lib/jamon/jamon-2.79.jar
+maven://com.jamonapi/jamon_war/2.79/war|lib/jamon/jamon.war
 
 [lib]
 lib/jamon/**.jar
@@ -25,6 +25,7 @@
 http://jamonapi.sourceforge.net/JAMonLicense.html
 
 [ini-template]
+## Jamon Configuration
+# jamon.summaryLabels=demo
 jamon.summaryLabels=default, request.getStatus().contextpath.value.ms
-#jamon.summaryLabels=demo
 
diff --git a/jetty-start/src/test/resources/dist-home/modules/jdbc-sessions.mod b/jetty-start/src/test/resources/dist-home/modules/jdbc-sessions.mod
new file mode 100644
index 0000000..d77ff04
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/jdbc-sessions.mod
@@ -0,0 +1,27 @@
+#
+# Jetty JDBC Session module
+#
+
+[depend]
+annotations
+webapp
+
+[xml]
+etc/jetty-jdbc-sessions.xml
+
+
+[ini-template]
+## JDBC Session config
+
+## Unique identifier for this node in the cluster
+# jetty.jdbcSession.workerName=node1
+
+## The interval in seconds between sweeps of the scavenger
+# jetty.jdbcSession.scavenge=600
+
+## Uncomment either the datasource name or driverClass and connectionURL
+# jetty.jdbcSession.datasource=sessions
+# jetty.jdbcSession.driverClass=changeme
+# jetty.jdbcSession.connectionURL=changeme
+
+
diff --git a/jetty-start/src/test/resources/dist-home/modules/jminix.mod b/jetty-start/src/test/resources/dist-home/modules/jminix.mod
index b35d702..05788f0 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jminix.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jminix.mod
@@ -11,21 +11,21 @@
 
 [files]
 lib/jminix/
-http://central.maven.org/maven2/org/jminix/jminix/1.1.0/jminix-1.1.0.jar|lib/jminix/jminix-1.1.0.jar
+maven://org.jminix/jminix/1.1.0|lib/jminix/jminix-1.1.0.jar
 http://maven.restlet.com/org/restlet/org.restlet/1.1.5/org.restlet-1.1.5.jar|lib/jminix/org.restlet-1.1.5.jar
 http://maven.restlet.com/org/restlet/org.restlet.ext.velocity/1.1.5/org.restlet.ext.velocity-1.1.5.jar|lib/jminix/org.restlet.ext.velocity-1.1.5.jar
-http://central.maven.org/maven2/org/apache/velocity/velocity/1.5/velocity-1.5.jar|lib/jminix/velocity-1.5.jar
-http://central.maven.org/maven2/oro/oro/2.0.8/oro-2.0.8.jar|lib/jminix/oro-2.0.8.jar
+maven://org.apache.velocity/velocity/1.5|lib/jminix/velocity-1.5.jar
+maven://oro/oro/2.0.8|lib/jminix/oro-2.0.8.jar
 http://maven.restlet.com/com/noelios/restlet/com.noelios.restlet/1.1.5/com.noelios.restlet-1.1.5.jar|lib/jminix/com.noelios.restlet-1.1.5.jar
 http://maven.restlet.com/com/noelios/restlet/com.noelios.restlet.ext.servlet/1.1.5/com.noelios.restlet.ext.servlet-1.1.5.jar|lib/jminix/com.noelios.restlet.ext.servlet-1.1.5.jar
-http://central.maven.org/maven2/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar|lib/jminix/commons-logging-1.1.1.jar
-http://repo2.maven.org/maven2/net/sf/json-lib/json-lib/2.2.3/json-lib-2.2.3-jdk15.jar|lib/jminix/json-lib-2.2.3-jdk15.jar
-http://central.maven.org/maven2/commons-lang/commons-lang/2.4/commons-lang-2.4.jar|lib/jminix/commons-lang-2.4.jar
-http://central.maven.org/maven2/commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar|lib/jminix/commons-beanutils-1.7.0.jar
-http://central.maven.org/maven2/commons-collections/commons-collections/3.2/commons-collections-3.2.jar|lib/jminix/commons-collections-3.2.jar
-http://central.maven.org/maven2/net/sf/ezmorph/ezmorph/1.0.6/ezmorph-1.0.6.jar|lib/jminix/ezmorph-1.0.6.jar
-http://central.maven.org/maven2/org/jgroups/jgroups/2.12.1.3.Final/jgroups-2.12.1.3.Final.jar|lib/jminix/jgroups-2.12.1.3.Final.jar
-http://central.maven.org/maven2/org/jasypt/jasypt/1.8/jasypt-1.8.jar|lib/jminix/jasypt-1.8.jar
+maven://commons-logging/commons-logging/1.1.1|lib/jminix/commons-logging-1.1.1.jar
+maven://net.sf.json-lib/json-lib/2.2.3/jar/jdk15|lib/jminix/json-lib-2.2.3-jdk15.jar
+maven://commons-lang/commons-lang/2.4|lib/jminix/commons-lang-2.4.jar
+maven://commons-beanutils/commons-beanutils/1.7.0|lib/jminix/commons-beanutils-1.7.0.jar
+maven://commons-collections/commons-collections/3.2|lib/jminix/commons-collections-3.2.jar
+maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar
+maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar
+maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar
 
 [lib]
 lib/jminix/**.jar
@@ -36,6 +36,6 @@
 http://www.apache.org/licenses/LICENSE-2.0
 
 [ini-template]
-# Jminix Configuration
+## Jminix Configuration
 jminix.port=8088
 
diff --git a/jetty-start/src/test/resources/dist-home/modules/jmx-remote.mod b/jetty-start/src/test/resources/dist-home/modules/jmx-remote.mod
index b6be74a..f8a5111 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jmx-remote.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jmx-remote.mod
@@ -9,10 +9,8 @@
 etc/jetty-jmx-remote.xml
 
 [ini-template]
-## JMX Configuration
-## Enable for an open port accessible by remote machines
-# jetty.jmxrmihost=localhost
-# jetty.jmxrmiport=1099
-## Strictly speaking you shouldn't need --exec to use this in most environments.
-## If this isn't working, make sure you enable --exec as well
-# -Dcom.sun.management.jmxremote
+## The host/address to bind RMI to
+# jetty.jmxremote.rmihost=localhost
+
+## The port RMI listens to
+# jetty.jmxremote.rmiport=1099
diff --git a/jetty-start/src/test/resources/dist-home/modules/jolokia.mod b/jetty-start/src/test/resources/dist-home/modules/jolokia.mod
index 876c2fc..da8ac8f 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jolokia.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jolokia.mod
@@ -11,7 +11,7 @@
 etc/jolokia.xml
 
 [files]
-http://repo1.maven.org/maven2/org/jolokia/jolokia-war/1.2.2/jolokia-war-1.2.2.war|lib/jolokia/jolokia.war
+maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war
 
 [license]
 Jolokia is released under the Apache License 2.0
diff --git a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jsp.mod b/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jsp.mod
deleted file mode 100644
index aed547c..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jsp.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Apache JSP Module
-#
-
-[name]
-jsp-impl
-
-[lib]
-lib/apache-jsp/*.jar
-
diff --git a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jstl.mod b/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jstl.mod
deleted file mode 100644
index 804b191..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/apache-jstl.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Apache JSTL 
-#
-[name]
-jstl-impl
-
-[lib]
-lib/apache-jstl/*.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jsp.mod b/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jsp.mod
deleted file mode 100644
index 130d2b3..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jsp.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Glassfish JSP Module
-#
-[name]
-jsp-impl
-
-[lib]
-lib/jsp/*.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jstl.mod b/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jstl.mod
deleted file mode 100644
index 4b8e6f3..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/jsp-impl/glassfish-jstl.mod
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Glassfish JSTL
-[name]
-jstl-impl
-
-# This file is empty as glassfish jstl is provided by glassfish jsp
diff --git a/jetty-start/src/test/resources/dist-home/modules/jsp.mod b/jetty-start/src/test/resources/dist-home/modules/jsp.mod
index bb31ca7..a16cc93 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jsp.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jsp.mod
@@ -5,17 +5,5 @@
 [depend]
 servlet
 annotations
-jsp-impl/${jsp-impl}-jsp
+apache-jsp
 
-[ini-template]
-# JSP Configuration
-
-# Select JSP implementation, choices are
-#   glassfish : The reference implementation 
-#               default in jetty <= 9.1
-#   apache    : The apache version 
-#               default jetty >= 9.2
-jsp-impl=apache
-
-# To use a non-jdk compiler for JSP compilation when using glassfish uncomment next line
-# -Dorg.apache.jasper.compiler.disablejsr199=true
diff --git a/jetty-start/src/test/resources/dist-home/modules/jstl.mod b/jetty-start/src/test/resources/dist-home/modules/jstl.mod
index cb06244..efc310a 100644
--- a/jetty-start/src/test/resources/dist-home/modules/jstl.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/jstl.mod
@@ -1,14 +1,8 @@
 #
-# Jetty JSP Module
+# Jetty JSTL Module
 #
 
 [depend]
 jsp
-jsp-impl/${jsp-impl}-jstl
+apache-jstl
 
-[ini-template]
-# JSTL Configuration
-# The glassfish jsp-impl includes JSTL by default and this module
-# is not required to activate it.
-# The apache jsp-impl does not include JSTL by default and this module
-# is required to put JSTL on the container classpath
diff --git a/jetty-start/src/test/resources/dist-home/modules/logging.mod b/jetty-start/src/test/resources/dist-home/modules/logging.mod
index a39bfe4..4f30a88 100644
--- a/jetty-start/src/test/resources/dist-home/modules/logging.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/logging.mod
@@ -14,18 +14,23 @@
 
 [ini-template]
 ## Logging Configuration
-# Configure jetty logging for default internal behavior STDERR output
+## Configure jetty logging for default internal behavior STDERR output
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
 
-# Configure jetty logging for slf4j
+## Configure jetty logging for slf4j
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
 
-# Configure jetty logging for java.util.logging
+## Configure jetty logging for java.util.logging
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog
 
-# STDERR / STDOUT Logging
-# Number of days to retain logs
-# jetty.log.retain=90
-# Directory for logging output
-# Either a path relative to ${jetty.base} or an absolute path
-# jetty.logs=logs
+## Logging directory (relative to $jetty.base)
+# jetty.logging.dir=logs
+
+## Whether to append to existing file
+# jetty.logging.append=false
+
+## How many days to retain old log files
+# jetty.logging.retainDays=90
+
+## Timezone of the log timestamps
+# jetty.logging.timezone=GMT
diff --git a/jetty-start/src/test/resources/dist-home/modules/lowresources.mod b/jetty-start/src/test/resources/dist-home/modules/lowresources.mod
index 99112d5..2f765d9 100644
--- a/jetty-start/src/test/resources/dist-home/modules/lowresources.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/lowresources.mod
@@ -9,10 +9,20 @@
 etc/jetty-lowresources.xml
 
 [ini-template]
-## Low Resources Configuration
-# lowresources.period=1050
-# lowresources.lowResourcesIdleTimeout=200
-# lowresources.monitorThreads=true
-# lowresources.maxConnections=0
-# lowresources.maxMemory=0
-# lowresources.maxLowResourcesTime=5000
+## Scan period to look for low resources (in milliseconds)
+# jetty.lowresources.period=1000
+
+## The idle timeout to apply to low resources (in milliseconds)
+# jetty.lowresources.idleTimeout=1000
+
+## Whether to monitor ThreadPool threads for low resources
+# jetty.lowresources.monitorThreads=true
+
+## Max number of connections allowed before being in low resources mode
+# jetty.lowresources.maxConnections=0
+
+## Max memory allowed before being in low resources mode (in bytes)
+# jetty.lowresources.maxMemory=0
+
+## Max time a resource may stay in low resource mode before actions are taken (in milliseconds)
+# jetty.lowresources.maxLowResourcesTime=5000
diff --git a/jetty-start/src/test/resources/dist-home/modules/nosql.mod b/jetty-start/src/test/resources/dist-home/modules/nosql.mod
new file mode 100644
index 0000000..a5b5a9e
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/modules/nosql.mod
@@ -0,0 +1,31 @@
+#
+# Jetty NoSql module
+#
+
+[depend]
+webapp
+
+[files]
+maven://org.mongodb/mongo-java-driver/2.6.1|lib/nosql/mongo-java-driver-2.6.1.jar
+
+[lib]
+lib/jetty-nosql-${jetty.version}.jar
+lib/nosql/*.jar
+
+[xml]
+etc/jetty-nosql.xml
+
+[license]
+The java driver for the MongoDB document-based database system is hosted on GitHub and released under the Apache 2.0 license.
+http://www.mongodb.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini-template]
+## MongoDB SessionIdManager config
+
+## Unique identifier for this node in the cluster
+# jetty.nosqlSession.workerName=node1
+
+## Interval in seconds between scavenging expired sessions
+# jetty.nosqlSession.scavenge=1800
+
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_40.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_40.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_45.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_45.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_51.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_51.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_55.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_55.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_60.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_65.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_65.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_65.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_67.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_67.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_67.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_71.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_71.mod
deleted file mode 100644
index e9b4e2a..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_71.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.2.v20141202/alpn-boot-7.1.2.v20141202.jar|lib/alpn/alpn-boot-7.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.2.v20141202.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_72.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_72.mod
deleted file mode 100644
index e9b4e2a..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_72.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.2.v20141202/alpn-boot-7.1.2.v20141202.jar|lib/alpn/alpn-boot-7.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.2.v20141202.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_75.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_75.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_75.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_76.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_76.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_76.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_79.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_79.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_79.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_80.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_80.mod
deleted file mode 100644
index ac315d6..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.7.0_80.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.3.v20150130/alpn-boot-7.1.3.v20150130.jar|lib/alpn/alpn-boot-7.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_05.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_05.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_11.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_11.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_11.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_20.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_20.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_20.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_25.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_25.mod
deleted file mode 100644
index 8d13261..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_25.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.2.v20141202/alpn-boot-8.1.2.v20141202.jar|lib/alpn/alpn-boot-8.1.2.v20141202.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.2.v20141202.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_31.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_31.mod
deleted file mode 100644
index 4114979..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn-1.8.0_31.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn.mod
deleted file mode 100644
index d3e4118..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/alpn.mod
+++ /dev/null
@@ -1,42 +0,0 @@
-# ALPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2)
-#
-# This modification has a tight dependency on specific recent updates of
-# Java 1.7 and Java 1.8
-# (Java versions prior to 1.7u40 are not supported)
-#
-# The alpn protonego module will use an appropriate alpn-boot jar for your
-# specific version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing alpn-boot jars, and might
-#            need a new alpn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of alpn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/alpn-${java.version}
-
-[lib]
-lib/jetty-alpn-client-${jetty.version}.jar
-lib/jetty-alpn-server-${jetty.version}.jar
-
-[xml]
-etc/protonego-alpn.xml
-
-[files]
-lib/
-lib/alpn/
-
-[license]
-ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
-ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
-http://github.com/jetty-project/jetty-alpn
-http://openjdk.java.net/legal/gplv2+ce.html
-
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_04.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_04.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_04.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_05.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_05.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_06.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_06.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_06.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_07.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_07.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_07.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_09.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_09.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_09.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_10.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_10.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_10.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_11.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_11.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_11.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_13.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_13.mod
deleted file mode 100644
index 1645a52..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_13.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.4.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_15.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_15.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_15.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_17.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_17.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_17.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_21.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_21.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_21.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_25.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_25.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_25.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_40.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_40.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_45.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_45.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_51.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_51.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_55.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_55.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_60.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_65.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_65.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_67.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_67.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_67.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_71.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_71.mod
deleted file mode 100644
index 851aca8..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_71.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_72.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_72.mod
deleted file mode 100644
index 851aca8..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_72.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.9.v20141016/npn-boot-1.1.9.v20141016.jar|lib/npn/npn-boot-1.1.9.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.9.v20141016.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_75.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_75.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_75.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_76.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_76.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_76.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_79.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_79.mod
deleted file mode 100644
index a5fac11..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_79.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.10.v20150130/npn-boot-1.1.10.v20150130.jar|lib/npn/npn-boot-1.1.10.v20150130.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.10.v20150130.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_80.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_80.mod
deleted file mode 100644
index 2cce5fa..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn-1.7.0_80.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.11.v20150415/npn-boot-1.1.11.v20150415.jar|lib/npn/npn-boot-1.1.11.v20150415.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.11.v20150415.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn.mod b/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn.mod
deleted file mode 100644
index 1a2c71d..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego-impl/npn.mod
+++ /dev/null
@@ -1,37 +0,0 @@
-# NPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the NPN layer needed for SPDY.
-#
-# This modification has a tight dependency on specific updates of Java 1.7.
-# (No support for Java 8 exists for npn / npn-boot, use alpn instead)
-#
-# The npn module will use an appropriate npn-boot jar for your specific
-# version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing npn-boot jars, and might
-#            need a new npn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of npn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/
-
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/npn-${java.version}
-
-[xml]
-etc/protonego-npn.xml
-
-[files]
-lib/
-lib/npn/
-
-[license]
-NPN is a hosted at github under the GPL v2 with ClassPath Exception.
-NPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
-http://github.com/jetty-project/jetty-npn
-http://openjdk.java.net/legal/gplv2+ce.html
diff --git a/jetty-start/src/test/resources/dist-home/modules/protonego.mod b/jetty-start/src/test/resources/dist-home/modules/protonego.mod
deleted file mode 100644
index fbf4d08..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/protonego.mod
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Protocol Negotiatin Selection Module
-#
-
-[depend]
-protonego-impl/${protonego}
-
-[ini-template]
-# Protocol Negotiation Implementation Selection
-#  choices are:
-#    'npn'  : original implementation for SPDY (now deprecated)
-#    'alpn' : replacement for NPN, in use by current SPDY implementations
-#             and the future HTTP/2 spec
-#  Note: java 1.8+ are ALPN only.
-protonego=alpn
-
-# Configuration for NPN
-# npn.protocols=spdy/3,http/1.1
-# npn.defaultProtocol=http/1.1
-
-# Configuration for ALPN
-# alpn.protocols=h2-14,http/1.1
-# alpn.defaultProtocol=http/1.1
-
diff --git a/jetty-start/src/test/resources/dist-home/modules/proxy.mod b/jetty-start/src/test/resources/dist-home/modules/proxy.mod
index a879ae1..6b91f68 100644
--- a/jetty-start/src/test/resources/dist-home/modules/proxy.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/proxy.mod
@@ -14,9 +14,9 @@
 
 [ini-template]
 ## Proxy Configuration
-#jetty.proxy.servletClass=org.eclipse.jetty.proxy.ProxyServlet
-#jetty.proxy.servletMapping=/*
-#jetty.proxy.maxThreads=128
-#jetty.proxy.maxConnections=256
-#jetty.proxy.idleTimeout=30000
-#jetty.proxy.timeout=60000
+# jetty.proxy.servletClass=org.eclipse.jetty.proxy.ProxyServlet
+# jetty.proxy.servletMapping=/*
+# jetty.proxy.maxThreads=128
+# jetty.proxy.maxConnections=256
+# jetty.proxy.idleTimeout=30000
+# jetty.proxy.timeout=60000
diff --git a/jetty-start/src/test/resources/dist-home/modules/quickstart.mod b/jetty-start/src/test/resources/dist-home/modules/quickstart.mod
index 89db9fd..4e59dd0 100644
--- a/jetty-start/src/test/resources/dist-home/modules/quickstart.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/quickstart.mod
@@ -7,6 +7,5 @@
 plus
 annotations
 
-
 [lib]
 lib/jetty-quickstart-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/dist-home/modules/requestlog.mod b/jetty-start/src/test/resources/dist-home/modules/requestlog.mod
index f5e0614..e27b246 100644
--- a/jetty-start/src/test/resources/dist-home/modules/requestlog.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/requestlog.mod
@@ -12,19 +12,26 @@
 logs/
 
 [ini-template]
-## Request Log Configuration
-# Filename for Request Log output (relative to jetty.base)
-# requestlog.filename=/logs/yyyy_mm_dd.request.log
-# Date format for rollovered files (uses SimpleDateFormat syntax)
-# requestlog.filenameDateFormat=yyyy_MM_dd
-# How many days to retain the logs
-# requestlog.retain=90
-# If an existing log with the same name is found, just append to it
-# requestlog.append=true
-# Use the extended log output
-# requestlog.extended=true
-# Log http cookie information as well
-# requestlog.cookies=true
-# Set the log output timezone
-# requestlog.timezone=GMT
+## Logging directory (relative to $jetty.base)
+# jetty.requestlog.dir=logs
 
+## File path
+# jetty.requestlog.filePath=${jetty.requestlog.dir}/yyyy_mm_dd.request.log
+
+## Date format for rollovered files (uses SimpleDateFormat syntax)
+# jetty.requestlog.filenameDateFormat=yyyy_MM_dd
+
+## How many days to retain old log files
+# jetty.requestlog.retainDays=90
+
+## Whether to append to existing file
+# jetty.requestlog.append=true
+
+## Whether to use the extended log output
+# jetty.requestlog.extended=true
+
+## Whether to log http cookie information
+# jetty.requestlog.cookies=true
+
+## Timezone of the log entries
+# jetty.requestlog.timezone=GMT
diff --git a/jetty-start/src/test/resources/dist-home/modules/rewrite.mod b/jetty-start/src/test/resources/dist-home/modules/rewrite.mod
index d2e00c8..c8a1750 100644
--- a/jetty-start/src/test/resources/dist-home/modules/rewrite.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/rewrite.mod
@@ -10,3 +10,13 @@
 
 [xml]
 etc/jetty-rewrite.xml
+
+[ini-template]
+## Whether to rewrite the request URI
+# jetty.rewrite.rewriteRequestURI=true
+
+## Whether to rewrite the path info
+# jetty.rewrite.rewritePathInfo=false
+
+## Request attribute key under with the original path is stored
+# jetty.rewrite.originalPathAttribute=requestedPath
diff --git a/jetty-start/src/test/resources/dist-home/modules/server.mod b/jetty-start/src/test/resources/dist-home/modules/server.mod
index 3cdac35..6b5dbe9 100644
--- a/jetty-start/src/test/resources/dist-home/modules/server.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/server.mod
@@ -20,30 +20,53 @@
 etc/jetty.xml
 
 [ini-template]
-##
-## Server Threading Configuration
-##
-# minimum number of threads
-threads.min=10
-# maximum number of threads
-threads.max=200
-# thread idle timeout in milliseconds
-threads.timeout=60000
-# buffer size for output
-jetty.output.buffer.size=32768
-# request header buffer size
-jetty.request.header.size=8192
-# response header buffer size
-jetty.response.header.size=8192
-# should jetty send the server version header?
-jetty.send.server.version=true
-# should jetty send the date header?
-jetty.send.date.header=false
-# What host to listen on (leave commented to listen on all interfaces)
-#jetty.host=myhost.com
-# Dump the state of the Jetty server, components, and webapps after startup
-jetty.dump.start=false
-# Dump the state of the Jetty server, before stop
-jetty.dump.stop=false
+### ThreadPool configuration
+## Minimum number of threads
+# jetty.threadPool.minThreads=10
 
+## Maximum number of threads
+# jetty.threadPool.maxThreads=200
 
+## Thread idle timeout (in milliseconds)
+# jetty.threadPool.idleTimeout=60000
+
+### Common HTTP configuration
+## Scheme to use to build URIs for secure redirects
+# jetty.httpConfig.secureScheme=https
+
+## Port to use to build URIs for secure redirects
+# jetty.httpConfig.securePort=8443
+
+## Response content buffer size (in bytes)
+# jetty.httpConfig.outputBufferSize=32768
+
+## Max response content write length that is buffered (in bytes)
+# jetty.httpConfig.outputAggregationSize=8192
+
+## Max request headers size (in bytes)
+# jetty.httpConfig.requestHeaderSize=8192
+
+## Max response headers size (in bytes)
+# jetty.httpConfig.responseHeaderSize=8192
+
+## Whether to send the Server: header
+# jetty.httpConfig.sendServerVersion=true
+
+## Whether to send the Date: header
+# jetty.httpConfig.sendDateHeader=false
+
+## Max per-connection header cache size (in nodes)
+# jetty.httpConfig.headerCacheSize=512
+
+## Whether, for requests with content, delay dispatch until some content has arrived
+# jetty.httpConfig.delayDispatchUntilContent=true
+
+### Server configuration
+## Whether ctrl+c on the console gracefully stops the Jetty server
+# jetty.server.stopAtShutdown=true
+
+## Dump the state of the Jetty server, components, and webapps after startup
+# jetty.server.dumpAfterStart=false
+
+## Dump the state of the Jetty server, components, and webapps before shutdown
+# jetty.server.dumpBeforeStop=false
diff --git a/jetty-start/src/test/resources/dist-home/modules/servlets.mod b/jetty-start/src/test/resources/dist-home/modules/servlets.mod
index e8724b8..2e977c0 100644
--- a/jetty-start/src/test/resources/dist-home/modules/servlets.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/servlets.mod
@@ -2,6 +2,7 @@
 # Jetty Servlets Module
 #
 
+
 [depend]
 servlet
 
diff --git a/jetty-start/src/test/resources/dist-home/modules/setuid.mod b/jetty-start/src/test/resources/dist-home/modules/setuid.mod
index 64c9e23..41ef757 100644
--- a/jetty-start/src/test/resources/dist-home/modules/setuid.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/setuid.mod
@@ -6,14 +6,14 @@
 server
 
 [lib]
-lib/setuid/jetty-setuid-java-1.0.1.jar
+lib/setuid/jetty-setuid-java-1.0.3.jar
 
 [xml]
 etc/jetty-setuid.xml
 
 [ini-template]
 ## SetUID Configuration
-# jetty.startServerAsPrivileged=false
-# jetty.username=jetty
-# jetty.groupname=jetty
-# jetty.umask=002
+# jetty.setuid.startServerAsPrivileged=false
+# jetty.setuid.userName=jetty
+# jetty.setuid.groupName=jetty
+# jetty.setuid.umask=002
diff --git a/jetty-start/src/test/resources/dist-home/modules/spdy.mod b/jetty-start/src/test/resources/dist-home/modules/spdy.mod
deleted file mode 100644
index cf79dfa..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/spdy.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# SPDY Support Module
-#
-
-[depend]
-ssl
-protonego
-
-[lib]
-lib/spdy/*.jar
-
-[xml]
-etc/jetty-ssl.xml
-etc/jetty-spdy.xml
-
-[ini-template]
-## SPDY Configuration
-
-# Port for SPDY connections
-spdy.port=8443
-
-# SPDY idle timeout in milliseconds
-spdy.timeout=30000
-
-# Initial Window Size for SPDY
-#spdy.initialWindowSize=65536
diff --git a/jetty-start/src/test/resources/dist-home/modules/spring.mod b/jetty-start/src/test/resources/dist-home/modules/spring.mod
index 444afb2..39b9b8d 100644
--- a/jetty-start/src/test/resources/dist-home/modules/spring.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/spring.mod
@@ -1,6 +1,7 @@
 #
 # Spring
 #
+
 [name]
 spring
 
diff --git a/jetty-start/src/test/resources/dist-home/modules/ssl.mod b/jetty-start/src/test/resources/dist-home/modules/ssl.mod
index ef47192..809543f 100644
--- a/jetty-start/src/test/resources/dist-home/modules/ssl.mod
+++ b/jetty-start/src/test/resources/dist-home/modules/ssl.mod
@@ -2,39 +2,82 @@
 # SSL Keystore module
 #
 
+[name]
+ssl
+
 [depend]
 server
 
 [xml]
 etc/jetty-ssl.xml
+etc/jetty-ssl-context.xml
 
 [files]
-http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
+http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/test/config/etc/keystore?id=${jetty.tag.version}|etc/keystore
 
 [ini-template]
-### SSL Keystore Configuration
-# define the port to use for secure redirection
-jetty.secure.port=8443
+### TLS(SSL) Connector Configuration
 
-## Setup a demonstration keystore and truststore
-jetty.keystore=etc/keystore
-jetty.truststore=etc/keystore
+## Connector host/address to bind to
+# jetty.ssl.host=0.0.0.0
 
-## Set the demonstration passwords.
+## Connector port to listen on
+jetty.ssl.port=8443
+
+## Connector idle timeout in milliseconds
+# jetty.ssl.idleTimeout=30000
+
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.ssl.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.ssl.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.ssl.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.ssl.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.ssl.acceptorPriorityDelta=0
+
+## Whether request host names are checked to match any SNI names
+# jetty.ssl.sniHostCheck=true
+
+### SslContextFactory Configuration
 ## Note that OBF passwords are not secure, just protected from casual observation
 ## See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
-jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
-jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
 
-### Set the client auth behavior
-## Set to true if client certificate authentication is required
-# jetty.ssl.needClientAuth=true
-## Set to true if client certificate authentication is desired
-# jetty.ssl.wantClientAuth=true
+## Keystore file path (relative to $jetty.base)
+# jetty.sslContext.keyStorePath=etc/keystore
 
-## Parameters to control the number and priority of acceptors and selectors
-# ssl.selectors=1
-# ssl.acceptors=1
-# ssl.selectorPriorityDelta=0
-# ssl.acceptorPriorityDelta=0
+## Truststore file path (relative to $jetty.base)
+# jetty.sslContext.trustStorePath=etc/keystore
+
+## Keystore password
+# jetty.sslContext.keyStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+
+## Keystore type and provider
+# jetty.sslContext.keyStoreType=JKS
+# jetty.sslContext.keyStoreProvider=
+
+## KeyManager password
+# jetty.sslContext.keyManagerPassword=OBF:1u2u1wml1z7s1z7a1wnl1u2g
+
+## Truststore password
+# jetty.sslContext.trustStorePassword=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
+
+## Truststore type and provider
+# jetty.sslContext.trustStoreType=JKS
+# jetty.sslContext.trustStoreProvider=
+
+## whether client certificate authentication is required
+# jetty.sslContext.needClientAuth=false
+
+## Whether client certificate authentication is desired
+# jetty.sslContext.wantClientAuth=false
+
+## Whether cipher order is significant (since java 8 only)
+# jetty.sslContext.useCipherSuitesOrder=true
+
diff --git a/jetty-start/src/test/resources/dist-home/modules/xinetd.mod b/jetty-start/src/test/resources/dist-home/modules/xinetd.mod
deleted file mode 100644
index e53618e..0000000
--- a/jetty-start/src/test/resources/dist-home/modules/xinetd.mod
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Xinetd module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-xinetd.xml
-
-[ini-template]
-## Xinetd Configuration
-## See ${jetty.home}/etc/jetty-xinetd.xml for example service entry
-jetty.xinetd.idleTimeout=300000
-jetty.xinetd.acceptors=2
-jetty.xinetd.statsOn=false
-
diff --git a/jetty-start/src/test/resources/dist-home/start.ini b/jetty-start/src/test/resources/dist-home/start.ini
new file mode 100644
index 0000000..76987d9
--- /dev/null
+++ b/jetty-start/src/test/resources/dist-home/start.ini
@@ -0,0 +1,131 @@
+#===========================================================
+# Jetty Startup 
+#
+# Starting Jetty from this {jetty.home} is not recommended.
+#
+# A proper {jetty.base} directory should be configured, instead
+# of making changes to this {jetty.home} directory.
+#
+# See documentation about {jetty.base} at
+# http://www.eclipse.org/jetty/documentation/current/startup.html
+#
+# A demo-base directory has been provided as an example of
+# this sort of setup.
+#
+# $ cd demo-base
+# $ java -jar ../start.jar
+#
+#===========================================================
+
+# To disable the warning message, comment the following line
+--module=home-base-warning
+
+# --------------------------------------- 
+# Module: apache-jsp
+--module=apache-jsp
+
+# --------------------------------------- 
+# Module: apache-jstl
+--module=apache-jstl
+
+# --------------------------------------- 
+# Module: ext
+--module=ext
+
+# --------------------------------------- 
+# Module: resources
+--module=resources
+
+# --------------------------------------- 
+# Module: server
+--module=server
+##
+## Server Threading Configuration
+##
+# minimum number of threads
+jetty.threadPool.minThreads=10
+# maximum number of threads
+jetty.threadPool.maxThreads=200
+# thread idle timeout in milliseconds
+jetty.threadPool.idleTimeout=60000
+# buffer size for output
+jetty.httpConfig.outputBufferSize=32768
+# request header buffer size
+jetty.httpConfig.requestHeaderSize=8192
+# response header buffer size
+jetty.httpConfig.responseHeaderSize=8192
+# should jetty send the server version header?
+jetty.httpConfig.sendServerVersion=true
+# should jetty send the date header?
+jetty.httpConfig.sendDateHeader=false
+# What host to listen on (leave commented to listen on all interfaces)
+#jetty.http.host=myhost.com
+# Dump the state of the Jetty server, components, and webapps after startup
+jetty.server.dumpAfterStart=false
+# Dump the state of the Jetty server, before stop
+jetty.server.dumpBeforeStop=false
+# Enable delayed dispatch optimisation
+jetty.httpConfig.delayDispatchUntilContent=false
+
+# --------------------------------------- 
+# Module: http
+--module=http
+### HTTP Connector Configuration
+
+## HTTP port to listen on
+jetty.http.port=8080
+
+## HTTP idle timeout in milliseconds
+# jetty.http.idleTimeout=30000
+
+## HTTP Socket.soLingerTime in seconds. (-1 to disable)
+# jetty.http.soLingerTime=-1
+
+## Parameters to control the number and priority of acceptors and selectors
+# jetty.http.selectors=1
+# jetty.http.acceptors=1
+# jetty.http.acceptorPriorityDelta=0
+
+# --------------------------------------- 
+# Module: jndi
+--module=jndi
+
+# --------------------------------------- 
+# Module: security
+--module=security
+
+# --------------------------------------- 
+# Module: servlet
+--module=servlet
+
+# --------------------------------------- 
+# Module: webapp
+--module=webapp
+
+# --------------------------------------- 
+# Module: deploy
+--module=deploy
+## DeployManager configuration
+# Monitored Directory name (relative to jetty.base)
+# jetty.deploy.monitoredDir=webapps
+
+# --------------------------------------- 
+# Module: plus
+--module=plus
+
+# --------------------------------------- 
+# Module: annotations
+--module=annotations
+
+# --------------------------------------- 
+# Module: jsp
+--module=jsp
+
+# --------------------------------------- 
+# Module: websocket
+--module=websocket
+
+# --------------------------------------- 
+# Module: jstl
+--module=jstl
+
diff --git a/jetty-start/src/test/resources/jetty-version.properties b/jetty-start/src/test/resources/jetty-version.properties
new file mode 100644
index 0000000..968f6fc
--- /dev/null
+++ b/jetty-start/src/test/resources/jetty-version.properties
@@ -0,0 +1 @@
+jetty.version=9.3
\ No newline at end of file
diff --git a/jetty-start/src/test/resources/usecases/agent-properties.assert.txt b/jetty-start/src/test/resources/usecases/agent-properties.assert.txt
new file mode 100644
index 0000000..664fec8
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/agent-properties.assert.txt
@@ -0,0 +1,33 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-jmx.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-jmx-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/agent-jdk-1.6.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# PROP|java.vm.specification.version=1.6
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
diff --git a/jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.5.jar b/jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.5.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.5.jar
rename to jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.5.jar
diff --git a/jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.6.jar b/jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.6.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.6.jar
rename to jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.6.jar
diff --git a/jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.7.jar b/jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.7.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.props.agent/lib/agent-jdk-1.7.jar
rename to jetty-start/src/test/resources/usecases/agent-properties/lib/agent-jdk-1.7.jar
diff --git a/jetty-start/src/test/resources/usecases/base.props.agent/modules/agent.mod b/jetty-start/src/test/resources/usecases/agent-properties/modules/agent.mod
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.props.agent/modules/agent.mod
rename to jetty-start/src/test/resources/usecases/agent-properties/modules/agent.mod
diff --git a/jetty-start/src/test/resources/usecases/agent-properties/start.ini b/jetty-start/src/test/resources/usecases/agent-properties/start.ini
new file mode 100644
index 0000000..db061d8
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/agent-properties/start.ini
@@ -0,0 +1,4 @@
+
+--module=http,agent
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/assert-barebones.txt b/jetty-start/src/test/resources/usecases/assert-barebones.txt
deleted file mode 100644
index 164f3f9..0000000
--- a/jetty-start/src/test/resources/usecases/assert-barebones.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/assert-enable-spdy-bad-npn-version.txt b/jetty-start/src/test/resources/usecases/assert-enable-spdy-bad-npn-version.txt
deleted file mode 100644
index 84c8867..0000000
--- a/jetty-start/src/test/resources/usecases/assert-enable-spdy-bad-npn-version.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-# The XMLs we expect (order is important)
-
-# The LIBs we expect (order is irrelevant)
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|jetty.keystore=etc/keystore
-PROP|jetty.keystore.password=friendly
-PROP|jetty.keymanager.password=icecream
-PROP|jetty.truststore=etc/keystore
-PROP|jetty.truststore.password=sundae
-PROP|java.version=1.7.0_01
-
-# The Downloads
-
-# The Bootlib
diff --git a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt b/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt
deleted file mode 100644
index a69eeb6..0000000
--- a/jetty-start/src/test/resources/usecases/assert-enable-spdy.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty-jmx.xml
-XML|${jetty.home}/etc/protonego-alpn.xml
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-XML|${jetty.home}/etc/jetty-ssl.xml
-XML|${jetty.home}/etc/jetty-spdy.xml
-
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/lib/spdy/spdy-client-TEST.jar
-LIB|${jetty.home}/lib/spdy/spdy-http-server-TEST.jar
-LIB|${jetty.home}/lib/spdy/spdy-http-common-TEST.jar
-LIB|${jetty.home}/lib/spdy/spdy-server-TEST.jar
-LIB|${jetty.home}/lib/spdy/spdy-core-TEST.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|jetty.secure.port=8443
-PROP|jetty.keystore=etc/keystore
-PROP|jetty.keystore.password=friendly
-PROP|jetty.keymanager.password=icecream
-PROP|jetty.truststore=etc/keystore
-PROP|jetty.truststore.password=sundae
-PROP|java.version=1.7.0_60
-PROP|protonego=alpn
-PROP|spdy.port=8443
-PROP|spdy.timeout=30000
-
-# The Downloads
-DOWNLOAD|http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
-
-# The Bootlib
-BOOTLIB|-Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-# The Files
-FILE|lib/
-FILE|lib/alpn/
-
diff --git a/jetty-start/src/test/resources/usecases/assert-include-jetty-dir-logging.txt b/jetty-start/src/test/resources/usecases/assert-include-jetty-dir-logging.txt
deleted file mode 100644
index 4ecd847..0000000
--- a/jetty-start/src/test/resources/usecases/assert-include-jetty-dir-logging.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty-jmx.xml
-XML|${maven-test-resources}/extra-jetty-dirs/logging/etc/jetty-logging.xml
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/resources
-LIB|${maven-test-resources}/extra-jetty-dirs/logging/lib/logging/logback.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-
-# Files
-FILE|logs/
diff --git a/jetty-start/src/test/resources/usecases/assert-jmx.txt b/jetty-start/src/test/resources/usecases/assert-jmx.txt
deleted file mode 100644
index def27d7..0000000
--- a/jetty-start/src/test/resources/usecases/assert-jmx.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty-jmx.xml
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt b/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt
deleted file mode 100644
index fe3d51c..0000000
--- a/jetty-start/src/test/resources/usecases/assert-jsp-apache.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-servlet-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
-LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
-LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
-LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
-LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|jsp-impl=apache
-
-# Files / Directories to create
-# FILE|lib/
diff --git a/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt b/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt
deleted file mode 100644
index 9c17c56..0000000
--- a/jetty-start/src/test/resources/usecases/assert-jsp-glassfish.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-servlet-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/lib/jsp/javax.el-TEST.jar
-LIB|${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-TEST.jar
-LIB|${jetty.home}/lib/jsp/javax.servlet.jsp-api-TEST.jar
-LIB|${jetty.home}/lib/jsp/javax.servlet.jsp-TEST.jar
-LIB|${jetty.home}/lib/jsp/jetty-jsp-jdt-TEST.jar
-LIB|${jetty.home}/lib/jsp/org.eclipse.jdt.core-TEST.jar
-LIB|${jetty.home}/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|jsp-impl=glassfish
-
-# Files / Directories to create
-# FILE|lib/
diff --git a/jetty-start/src/test/resources/usecases/assert-logging.txt b/jetty-start/src/test/resources/usecases/assert-logging.txt
deleted file mode 100644
index c83dc2c..0000000
--- a/jetty-start/src/test/resources/usecases/assert-logging.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.base}/lib/logging/slf4j-api.jar
-LIB|${jetty.base}/lib/logging/jul-to-slf4j.jar
-LIB|${jetty.base}/lib/logging/logback-core.jar
-LIB|${jetty.base}/lib/logging/logback-classic.jar
-LIB|${jetty.base}/resources
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-
-# Other File References
-FILE|logs/
-FILE|resources/
-
-# Downloads
-DOWNLOAD|http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar|lib/logging/slf4j-api-1.6.6.jar
-DOWNLOAD|http://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar|lib/logging/logback-core-1.0.7.jar
-DOWNLOAD|http://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar|lib/logging/logback-classic-1.0.7.jar
-DOWNLOAD|https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/logback.xml|resources/logback.xml
-DOWNLOAD|https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/jetty-logging.properties|resources/jetty-logging.properties
diff --git a/jetty-start/src/test/resources/usecases/assert-missing-npn-version.txt b/jetty-start/src/test/resources/usecases/assert-missing-npn-version.txt
deleted file mode 100644
index 884767a..0000000
--- a/jetty-start/src/test/resources/usecases/assert-missing-npn-version.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty-jmx.xml
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|jetty.keystore=etc/keystore
-PROP|jetty.keystore.password=friendly
-PROP|jetty.keymanager.password=icecream
-PROP|jetty.truststore=etc/keystore
-PROP|jetty.truststore.password=sundae
-PROP|java.version=1.7.0_01
-
-# The Downloads
-
-# The Bootlib
diff --git a/jetty-start/src/test/resources/usecases/assert-props.agent.txt b/jetty-start/src/test/resources/usecases/assert-props.agent.txt
deleted file mode 100644
index 27108ab..0000000
--- a/jetty-start/src/test/resources/usecases/assert-props.agent.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty-jmx.xml
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jmx-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.base}/lib/agent-jdk-1.6.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|java.vm.specification.version=1.6
diff --git a/jetty-start/src/test/resources/usecases/assert-props.basic.txt b/jetty-start/src/test/resources/usecases/assert-props.basic.txt
deleted file mode 100644
index e56177e..0000000
--- a/jetty-start/src/test/resources/usecases/assert-props.basic.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|port=9090
diff --git a/jetty-start/src/test/resources/usecases/assert-with-db.txt b/jetty-start/src/test/resources/usecases/assert-with-db.txt
deleted file mode 100644
index 1651974..0000000
--- a/jetty-start/src/test/resources/usecases/assert-with-db.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-XML|${jetty.home}/etc/jetty-plus.xml
-XML|${jetty.home}/etc/jetty-deploy.xml
-XML|${jetty.base}/etc/jetty-db.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/lib/jetty-jndi-TEST.jar
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar
-LIB|${jetty.home}/lib/jetty-plus-TEST.jar
-LIB|${jetty.home}/lib/jetty-deploy-TEST.jar
-LIB|${jetty.home}/lib/jetty-security-TEST.jar
-LIB|${jetty.home}/lib/jndi/javax.activation-1.1.jar
-LIB|${jetty.home}/lib/jetty-webapp-TEST.jar
-LIB|${jetty.home}/lib/jetty-servlet-TEST.jar
-LIB|${jetty.base}/lib/db/mysql-driver.jar
-LIB|${jetty.base}/lib/db/bonecp.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-PROP|mysql.user=frank
-PROP|mysql.pass=secret
\ No newline at end of file
diff --git a/jetty-start/src/test/resources/usecases/assert-with-module-persistence.txt b/jetty-start/src/test/resources/usecases/assert-with-module-persistence.txt
deleted file mode 100644
index 75fb89c..0000000
--- a/jetty-start/src/test/resources/usecases/assert-with-module-persistence.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-ssl.xml
-XML|${jetty.home}/etc/jetty-https.xml
-XML|${jetty.home}/etc/jetty-plus.xml
-XML|${jetty.home}/etc/jetty-annotations.xml
-XML|${jetty.home}/etc/jetty-websockets.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/annotations/javax.annotation-api-1.2.jar
-LIB|${jetty.home}/lib/annotations/org.objectweb.asm-TEST.jar
-LIB|${jetty.home}/lib/jetty-annotations-TEST.jar
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-jndi-TEST.jar
-LIB|${jetty.home}/lib/jetty-plus-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-security-TEST.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/jndi/javax.activation-1.1.jar
-LIB|${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.home}/lib/websocket/javax.websocket-api-1.0.jar
-LIB|${jetty.home}/lib/websocket/javax-websocket-client-impl-TEST.jar
-LIB|${jetty.home}/lib/websocket/javax-websocket-server-impl-TEST.jar
-LIB|${jetty.home}/lib/websocket/websocket-api-TEST.jar
-LIB|${jetty.home}/lib/websocket/websocket-client-TEST.jar
-LIB|${jetty.home}/lib/websocket/websocket-common-TEST.jar
-LIB|${jetty.home}/lib/websocket/websocket-server-TEST.jar
-LIB|${jetty.home}/lib/websocket/websocket-servlet-TEST.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=12345
-PROP|jetty.keystore=etc/keystore
-PROP|jetty.keystore.password=friendly
-PROP|jetty.keymanager.password=icecream
-PROP|jetty.truststore=etc/keystore
-PROP|jetty.truststore.password=sundae
-
-# JVM Args
-# JVM|-Xms1024m
diff --git a/jetty-start/src/test/resources/usecases/assert-with.ext.txt b/jetty-start/src/test/resources/usecases/assert-with.ext.txt
deleted file mode 100644
index 7759a41..0000000
--- a/jetty-start/src/test/resources/usecases/assert-with.ext.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-# The XMLs we expect (order is important)
-XML|${jetty.home}/etc/jetty.xml
-XML|${jetty.home}/etc/jetty-http.xml
-
-# The LIBs we expect (order is irrelevant)
-LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
-LIB|${jetty.home}/lib/jetty-http-TEST.jar
-LIB|${jetty.home}/lib/jetty-io-TEST.jar
-LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
-LIB|${jetty.home}/lib/jetty-server-TEST.jar
-LIB|${jetty.home}/lib/jetty-util-TEST.jar
-LIB|${jetty.home}/lib/jetty-xml-TEST.jar
-LIB|${jetty.home}/lib/servlet-api-3.1.jar
-LIB|${jetty.base}/lib/ext/agent.jar
-LIB|${jetty.base}/lib/ext/jdbc/mariadb-jdbc.jar
-LIB|${jetty.base}/lib/ext/logging/slf4j-api.jar
-LIB|${jetty.base}/lib/ext/logging/jul-to-slf4j.jar
-LIB|${jetty.base}/lib/ext/logging/logback-core.jar
-LIB|${jetty.base}/lib/ext/logging/logback-classic.jar
-
-# The Properties we expect (order is irrelevant)
-PROP|jetty.port=9090
-
-# Files / Directories to create
-FILE|lib/
-FILE|lib/ext/
diff --git a/jetty-start/src/test/resources/usecases/barebones.assert.txt b/jetty-start/src/test/resources/usecases/barebones.assert.txt
new file mode 100644
index 0000000..3314346
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/barebones.assert.txt
@@ -0,0 +1,29 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
diff --git a/jetty-start/src/test/resources/usecases/barebones/start.ini b/jetty-start/src/test/resources/usecases/barebones/start.ini
new file mode 100644
index 0000000..a3d92b9
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/barebones/start.ini
@@ -0,0 +1,5 @@
+
+--module=server
+--module=http
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.barebones/start.ini b/jetty-start/src/test/resources/usecases/base.barebones/start.ini
deleted file mode 100644
index 1c0e065..0000000
--- a/jetty-start/src/test/resources/usecases/base.barebones/start.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-
---module=server
---module=http
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.enable.spdy.bad.npn.version/start.ini b/jetty-start/src/test/resources/usecases/base.enable.spdy.bad.npn.version/start.ini
deleted file mode 100644
index 13fa508..0000000
--- a/jetty-start/src/test/resources/usecases/base.enable.spdy.bad.npn.version/start.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-
---module=server,http,jmx,spdy
-
-jetty.port=9090
-
-# Some SSL keystore configuration
-jetty.keystore=etc/keystore
-jetty.keystore.password=friendly
-jetty.keymanager.password=icecream
-jetty.truststore=etc/keystore
-jetty.truststore.password=sundae
-
diff --git a/jetty-start/src/test/resources/usecases/base.enable.spdy/start.ini b/jetty-start/src/test/resources/usecases/base.enable.spdy/start.ini
deleted file mode 100644
index 13fa508..0000000
--- a/jetty-start/src/test/resources/usecases/base.enable.spdy/start.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-
---module=server,http,jmx,spdy
-
-jetty.port=9090
-
-# Some SSL keystore configuration
-jetty.keystore=etc/keystore
-jetty.keystore.password=friendly
-jetty.keymanager.password=icecream
-jetty.truststore=etc/keystore
-jetty.truststore.password=sundae
-
diff --git a/jetty-start/src/test/resources/usecases/base.jmx/start.ini b/jetty-start/src/test/resources/usecases/base.jmx/start.ini
deleted file mode 100644
index d3950e6..0000000
--- a/jetty-start/src/test/resources/usecases/base.jmx/start.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-
---module=server,http,jmx
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.logging/start.ini b/jetty-start/src/test/resources/usecases/base.logging/start.ini
deleted file mode 100644
index e18ff3d..0000000
--- a/jetty-start/src/test/resources/usecases/base.logging/start.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-
---module=server
---module=http
---module=logging
---module=resources
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.missing.npn.version/start.ini b/jetty-start/src/test/resources/usecases/base.missing.npn.version/start.ini
deleted file mode 100644
index 2915961..0000000
--- a/jetty-start/src/test/resources/usecases/base.missing.npn.version/start.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-
---module=server,http,jmx
-
-jetty.port=9090
-
-# Some SSL keystore configuration
-jetty.keystore=etc/keystore
-jetty.keystore.password=friendly
-jetty.keymanager.password=icecream
-jetty.truststore=etc/keystore
-jetty.truststore.password=sundae
-
diff --git a/jetty-start/src/test/resources/usecases/base.props.agent/start.ini b/jetty-start/src/test/resources/usecases/base.props.agent/start.ini
deleted file mode 100644
index 198a07c..0000000
--- a/jetty-start/src/test/resources/usecases/base.props.agent/start.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-
---module=http,agent
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.props.basic/start.ini b/jetty-start/src/test/resources/usecases/base.props.basic/start.ini
deleted file mode 100644
index f80bdb2..0000000
--- a/jetty-start/src/test/resources/usecases/base.props.basic/start.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-
---module=server
---module=http
-
-jetty.port=${port}
diff --git a/jetty-start/src/test/resources/usecases/base.with.db/start.ini b/jetty-start/src/test/resources/usecases/base.with.db/start.ini
deleted file mode 100644
index d5513df..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.db/start.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-
---module=http,db
-
-mysql.user=frank
-mysql.pass=secret
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/start.ini b/jetty-start/src/test/resources/usecases/base.with.ext/start.ini
deleted file mode 100644
index c8fa930..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.ext/start.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-
---module=server
---module=http
---module=ext
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.include.jetty.dirs/start.ini b/jetty-start/src/test/resources/usecases/base.with.include.jetty.dirs/start.ini
deleted file mode 100644
index 9e16be6..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.include.jetty.dirs/start.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-
---include-jetty-dir=${start.basedir}/../../extra-jetty-dirs/logging
---module=server,http,jmx
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini
deleted file mode 100644
index fcdea02..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.jsp.apache/start.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-
---module=server
---module=http
---module=jsp
-jsp-impl=apache
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini
deleted file mode 100644
index 96e495a..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.jsp.bad/start.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-
---module=server
---module=http
---module=jsp
-jsp-impl=bogus
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini
deleted file mode 100644
index bf58fa8..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.jsp.default/start.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-
---module=server
---module=http
---module=jsp
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini b/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini
deleted file mode 100644
index 7107ade..0000000
--- a/jetty-start/src/test/resources/usecases/base.with.jsp.glassfish/start.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-
---module=server
---module=http
---module=jsp
-jsp-impl=glassfish
-
-jetty.port=9090
diff --git a/jetty-start/src/test/resources/usecases/basic-properties.assert.txt b/jetty-start/src/test/resources/usecases/basic-properties.assert.txt
new file mode 100644
index 0000000..ab45829
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/basic-properties.assert.txt
@@ -0,0 +1,30 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+PROP|port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
diff --git a/jetty-start/src/test/resources/usecases/basic-properties/start.ini b/jetty-start/src/test/resources/usecases/basic-properties/start.ini
new file mode 100644
index 0000000..eaef9da
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/basic-properties/start.ini
@@ -0,0 +1,5 @@
+
+--module=server
+--module=http
+
+jetty.http.port=${port}
diff --git a/jetty-start/src/test/resources/usecases/database.assert.txt b/jetty-start/src/test/resources/usecases/database.assert.txt
new file mode 100644
index 0000000..e8fd0ec
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/database.assert.txt
@@ -0,0 +1,47 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-deploy.xml
+XML|${jetty.home}/etc/jetty-plus.xml
+XML|${jetty.base}/etc/jetty-db.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.home}/lib/jetty-jndi-9.3.jar
+LIB|${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
+LIB|${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.home}/lib/jetty-plus-9.3.jar
+LIB|${jetty.home}/lib/jetty-deploy-9.3.jar
+LIB|${jetty.home}/lib/jetty-security-9.3.jar
+LIB|${jetty.home}/lib/jetty-webapp-9.3.jar
+LIB|${jetty.home}/lib/jetty-servlet-9.3.jar
+LIB|${jetty.base}/lib/db/mysql-driver.jar
+LIB|${jetty.base}/lib/db/bonecp.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+PROP|mysql.user=frank
+PROP|mysql.pass=secret
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
+
+# Files / Directories to create
+FILE|webapps/
diff --git a/jetty-start/src/test/resources/usecases/base.with.db/etc/jetty-db.xml b/jetty-start/src/test/resources/usecases/database/etc/jetty-db.xml
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.db/etc/jetty-db.xml
rename to jetty-start/src/test/resources/usecases/database/etc/jetty-db.xml
diff --git a/jetty-start/src/test/resources/usecases/base.with.db/lib/db/bonecp.jar b/jetty-start/src/test/resources/usecases/database/lib/db/bonecp.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.db/lib/db/bonecp.jar
rename to jetty-start/src/test/resources/usecases/database/lib/db/bonecp.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.db/lib/db/mysql-driver.jar b/jetty-start/src/test/resources/usecases/database/lib/db/mysql-driver.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.db/lib/db/mysql-driver.jar
rename to jetty-start/src/test/resources/usecases/database/lib/db/mysql-driver.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.db/modules/db.mod b/jetty-start/src/test/resources/usecases/database/modules/db.mod
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.db/modules/db.mod
rename to jetty-start/src/test/resources/usecases/database/modules/db.mod
diff --git a/jetty-start/src/test/resources/usecases/database/start.ini b/jetty-start/src/test/resources/usecases/database/start.ini
new file mode 100644
index 0000000..a9a013b
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/database/start.ini
@@ -0,0 +1,7 @@
+
+--module=http,db
+
+mysql.user=frank
+mysql.pass=secret
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/deep-ext.assert.txt b/jetty-start/src/test/resources/usecases/deep-ext.assert.txt
new file mode 100644
index 0000000..bb8684e
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/deep-ext.assert.txt
@@ -0,0 +1,39 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/ext/agent.jar
+LIB|${jetty.base}/lib/ext/jdbc/mariadb-jdbc.jar
+LIB|${jetty.base}/lib/ext/logging/slf4j-api.jar
+LIB|${jetty.base}/lib/ext/logging/jul-to-slf4j.jar
+LIB|${jetty.base}/lib/ext/logging/logback-core.jar
+LIB|${jetty.base}/lib/ext/logging/logback-classic.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
+
+# Files / Directories to create
+FILE|lib/
+FILE|lib/ext/
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/agent.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/agent.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/agent.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/agent.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/jdbc/mariadb-jdbc.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/jdbc/mariadb-jdbc.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/jdbc/mariadb-jdbc.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/jdbc/mariadb-jdbc.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/jul-to-slf4j.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/jul-to-slf4j.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/jul-to-slf4j.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/jul-to-slf4j.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/logback-classic.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/logback-classic.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/logback-classic.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/logback-classic.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/logback-core.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/logback-core.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/logback-core.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/logback-core.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/slf4j-api.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/slf4j-api.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/ext/logging/slf4j-api.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/ext/logging/slf4j-api.jar
diff --git a/jetty-start/src/test/resources/usecases/base.with.ext/lib/jetty-util-alt.jar b/jetty-start/src/test/resources/usecases/deep-ext/lib/jetty-util-alt.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.with.ext/lib/jetty-util-alt.jar
rename to jetty-start/src/test/resources/usecases/deep-ext/lib/jetty-util-alt.jar
diff --git a/jetty-start/src/test/resources/usecases/deep-ext/start.ini b/jetty-start/src/test/resources/usecases/deep-ext/start.ini
new file mode 100644
index 0000000..2165a30
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/deep-ext/start.ini
@@ -0,0 +1,6 @@
+
+--module=server
+--module=http
+--module=ext
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/home/etc/README.spnego b/jetty-start/src/test/resources/usecases/home/etc/README.spnego
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/README.spnego
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jdbcRealm.properties b/jetty-start/src/test/resources/usecases/home/etc/jdbcRealm.properties
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jdbcRealm.properties
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-annotations.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-annotations.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-annotations.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-contexts.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-contexts.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-contexts.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-debug.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-debug.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-debug.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-demo.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-demo.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-demo.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-deploy.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-deploy.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-deploy.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-http.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-http.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-http.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-https.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-https.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-https.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-ipaccess.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-ipaccess.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-ipaccess.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-jaas.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-jaas.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-jaas.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-jmx.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-jmx.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-jmx.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-logging.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-logging.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-logging.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-lowresources.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-lowresources.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-lowresources.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-monitor.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-monitor.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-monitor.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-plus.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-plus.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-plus.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-proxy.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-proxy.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-proxy.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-requestlog.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-requestlog.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-requestlog.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-rewrite.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-rewrite.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-rewrite.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-setuid.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-setuid.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-setuid.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy-proxy.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy-proxy.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy-proxy.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-spdy.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-ssl.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-ssl.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-ssl.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-started.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-started.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-started.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-stats.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-stats.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-stats.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-testrealm.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-testrealm.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-testrealm.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-webapps.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-webapps.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-webapps.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-websockets.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-websockets.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-websockets.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty-xinetd.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty-xinetd.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty-xinetd.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty.conf b/jetty-start/src/test/resources/usecases/home/etc/jetty.conf
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty.conf
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/jetty.xml b/jetty-start/src/test/resources/usecases/home/etc/jetty.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/jetty.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/keystore b/jetty-start/src/test/resources/usecases/home/etc/keystore
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/keystore
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/krb5.ini b/jetty-start/src/test/resources/usecases/home/etc/krb5.ini
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/krb5.ini
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml b/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/protonego-alpn.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml b/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/protonego-npn.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/spnego.conf b/jetty-start/src/test/resources/usecases/home/etc/spnego.conf
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/spnego.conf
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/spnego.properties b/jetty-start/src/test/resources/usecases/home/etc/spnego.properties
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/spnego.properties
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/test-realm.xml b/jetty-start/src/test/resources/usecases/home/etc/test-realm.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/test-realm.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/etc/webdefault.xml b/jetty-start/src/test/resources/usecases/home/etc/webdefault.xml
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/etc/webdefault.xml
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/annotations/javax.annotation-api-1.2.jar b/jetty-start/src/test/resources/usecases/home/lib/annotations/javax.annotation-api-1.2.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/annotations/javax.annotation-api-1.2.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/annotations/org.objectweb.asm-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/annotations/org.objectweb.asm-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/annotations/org.objectweb.asm-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/javax.servlet.jsp.javax.servlet.jsp-api-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.apache-jsp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-el-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jsp/org.mortbay.jasper.apache-jsp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-impl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/apache-jstl/org.apache.taglibs.taglibs-standard-spec-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/ext/.nodelete b/jetty-start/src/test/resources/usecases/home/lib/ext/.nodelete
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/ext/.nodelete
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-annotations-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-annotations-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-annotations-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-client-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-continuation-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-continuation-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-continuation-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-deploy-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-deploy-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-deploy-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-http-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-http-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-http-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-io-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-io-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-io-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-jaas-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-jaas-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-jaas-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-jmx-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-jmx-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-jmx-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-jndi-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-jndi-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-jndi-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-jsp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-jsp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-plus-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-plus-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-plus-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-proxy-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-proxy-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-proxy-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-rewrite-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-rewrite-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-rewrite-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.RC0.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.RC0.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.RC0.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-schemas-3.1.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-security-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-security-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-security-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-server-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-servlet-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-servlet-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-servlet-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-servlets-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-servlets-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-servlets-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-util-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-util-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-util-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-webapp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-webapp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-webapp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jetty-xml-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jetty-xml-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jetty-xml-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.activation-1.1.jar b/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.activation-1.1.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.activation-1.1.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.transaction-api-1.2.jar b/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.transaction-api-1.2.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jndi/javax.transaction-api-1.2.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.el-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp-api-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/javax.servlet.jsp.jstl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/jetty-jsp-jdt-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/jetty-jsp-jdt-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/jetty-jsp-jdt-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jdt.core-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/jsp/org.eclipse.jetty.orbit.javax.servlet.jsp.jstl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/monitor/jetty-monitor-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/monitor/jetty-monitor-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/monitor/jetty-monitor-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/servlet-api-3.1.jar b/jetty-start/src/test/resources/usecases/home/lib/servlet-api-3.1.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/servlet-api-3.1.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/setuid/jetty-setuid-java-1.0.1.jar b/jetty-start/src/test/resources/usecases/home/lib/setuid/jetty-setuid-java-1.0.1.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/setuid/jetty-setuid-java-1.0.1.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-linux.so b/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-linux.so
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-linux.so
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-osx.so b/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-osx.so
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/setuid/libsetuid-osx.so
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-client-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-core-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-core-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-core-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-common-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-common-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-common-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-server-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-http-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-server-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/spdy/spdy-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-client-impl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-client-impl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-client-impl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-server-impl-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-server-impl-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax-websocket-server-impl-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax.websocket-api-1.0.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/javax.websocket-api-1.0.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/javax.websocket-api-1.0.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-api-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-api-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-api-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-client-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-client-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-client-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-common-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-common-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-common-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-server-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-server-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-server-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-servlet-TEST.jar b/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-servlet-TEST.jar
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/lib/websocket/websocket-servlet-TEST.jar
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/modules/annotations.mod b/jetty-start/src/test/resources/usecases/home/modules/annotations.mod
deleted file mode 100644
index 65e4654..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/annotations.mod
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Jetty Annotation Scanning Module
-#
-
-[depend]
-# Annotations needs plus, and jndi features
-plus
-
-[lib]
-# Annotations needs jetty annotation jars
-lib/jetty-annotations-${jetty.version}.jar
-# Need annotation processing jars too
-lib/annotations/*.jar
-
-[xml]
-# Enable annotation scanning webapp configurations
-etc/jetty-annotations.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/base.mod b/jetty-start/src/test/resources/usecases/home/modules/base.mod
deleted file mode 100644
index ad8ea32..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/base.mod
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Base Module
-#
-
-[optional]
-# JMX is optional, if it appears in the module tree then depend on it
-jmx
-
-[lib]
-lib/jetty-util-${jetty.version}.jar
-lib/jetty-io-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/client.mod b/jetty-start/src/test/resources/usecases/home/modules/client.mod
deleted file mode 100644
index 6788eac..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/client.mod
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Client Feature
-#
-
-[lib]
-# Client jars
-lib/jetty-client-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/debug.mod b/jetty-start/src/test/resources/usecases/home/modules/debug.mod
deleted file mode 100644
index f740ea2..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/debug.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Debug module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-debug.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/deploy.mod b/jetty-start/src/test/resources/usecases/home/modules/deploy.mod
deleted file mode 100644
index 94c0e40..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/deploy.mod
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Deploy Feature
-#
-
-[depend]
-webapp
-
-[lib]
-# Deploy jars
-lib/jetty-deploy-${jetty.version}.jar
-
-[xml]
-# Deploy configuration
-etc/jetty-deploy.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/ext.mod b/jetty-start/src/test/resources/usecases/home/modules/ext.mod
deleted file mode 100644
index 66c0519..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/ext.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# ext module
-#
-
-[lib]
-lib/ext/**.jar
-
-[files]
-lib/
-lib/ext/
diff --git a/jetty-start/src/test/resources/usecases/home/modules/http.mod b/jetty-start/src/test/resources/usecases/home/modules/http.mod
deleted file mode 100644
index 8515414..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/http.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Jetty HTTP Server
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-http.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/https.mod b/jetty-start/src/test/resources/usecases/home/modules/https.mod
deleted file mode 100644
index 281c5db..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/https.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Jetty HTTP Server
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-ssl.xml
-etc/jetty-https.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/ipaccess.mod b/jetty-start/src/test/resources/usecases/home/modules/ipaccess.mod
deleted file mode 100644
index 956ea0f..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/ipaccess.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# IPAccess module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-ipaccess.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jaas.mod b/jetty-start/src/test/resources/usecases/home/modules/jaas.mod
deleted file mode 100644
index 9fb04f7..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jaas.mod
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# JAAS Feature
-#
-
-[depend]
-server
-
-[lib]
-# JAAS jars
-lib/jetty-jaas-${jetty.version}.jar
-
-[xml]
-# JAAS configuration
-etc/jetty-jaas.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jmx.mod b/jetty-start/src/test/resources/usecases/home/modules/jmx.mod
deleted file mode 100644
index fd8740a..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jmx.mod
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# JMX Feature
-#
-
-[lib]
-# JMX jars (as defined in start.config)
-lib/jetty-jmx-${jetty.version}.jar
-
-[xml]
-# JMX configuration
-etc/jetty-jmx.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jndi.mod b/jetty-start/src/test/resources/usecases/home/modules/jndi.mod
deleted file mode 100644
index 33c077c..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jndi.mod
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# JNDI Support
-#
-
-[depend]
-server
-
-[lib]
-lib/jetty-jndi-${jetty.version}.jar
-lib/jndi/*.jar
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod
deleted file mode 100644
index aed547c..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/apache-jsp.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Apache JSP Module
-#
-
-[name]
-jsp-impl
-
-[lib]
-lib/apache-jsp/*.jar
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod
deleted file mode 100644
index 130d2b3..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jsp-impl/glassfish-jsp.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Glassfish JSP Module
-#
-[name]
-jsp-impl
-
-[lib]
-lib/jsp/*.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/jsp.mod b/jetty-start/src/test/resources/usecases/home/modules/jsp.mod
deleted file mode 100644
index fa5b9fd..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/jsp.mod
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Jetty JSP Module
-#
-
-[depend]
-servlet
-jsp-impl/${jsp-impl}-jsp
-
-[ini-template]
-# JSP Configuration
-
-# Select JSP implementation, choices are
-#   glassfish : The reference implementation 
-#               default in jetty <= 9.1
-#   apache    : The apache version 
-#               default jetty >= 9.2
-jsp-impl=apache
-
-# To use a non-jdk compiler for JSP compilation when using glassfish uncomment next line
-# -Dorg.apache.jasper.compiler.disablejsr199=true
diff --git a/jetty-start/src/test/resources/usecases/home/modules/logging.mod b/jetty-start/src/test/resources/usecases/home/modules/logging.mod
deleted file mode 100644
index a39bfe4..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/logging.mod
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Jetty std err/out logging
-#
-
-[xml]
-etc/jetty-logging.xml
-
-[files]
-logs/
-
-[lib]
-lib/logging/**.jar
-resources/
-
-[ini-template]
-## Logging Configuration
-# Configure jetty logging for default internal behavior STDERR output
-# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
-
-# Configure jetty logging for slf4j
-# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
-
-# Configure jetty logging for java.util.logging
-# -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog
-
-# STDERR / STDOUT Logging
-# Number of days to retain logs
-# jetty.log.retain=90
-# Directory for logging output
-# Either a path relative to ${jetty.base} or an absolute path
-# jetty.logs=logs
diff --git a/jetty-start/src/test/resources/usecases/home/modules/lowresources.mod b/jetty-start/src/test/resources/usecases/home/modules/lowresources.mod
deleted file mode 100644
index 4ca96de..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/lowresources.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Low Resources module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-lowresources.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/monitor.mod b/jetty-start/src/test/resources/usecases/home/modules/monitor.mod
deleted file mode 100644
index 67f006d..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/monitor.mod
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Jetty Monitor module
-#
-
-[depend]
-server
-client
-
-[lib]
-lib/jetty-monitor-${jetty.version}.jar
-
-[xml]
-etc/jetty-monitor.xml
\ No newline at end of file
diff --git a/jetty-start/src/test/resources/usecases/home/modules/plus.mod b/jetty-start/src/test/resources/usecases/home/modules/plus.mod
deleted file mode 100644
index b781f00..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/plus.mod
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Jetty Proxy module
-#
-
-[depend]
-server
-security
-jndi
-
-[lib]
-lib/jetty-plus-${jetty.version}.jar
-
-[xml]
-# Plus requires configuration
-etc/jetty-plus.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod
deleted file mode 100644
index 54d3731..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.1.0.v20141016/alpn-boot-7.1.0.v20141016.jar|lib/alpn/alpn-boot-7.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-7.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod
deleted file mode 100644
index a81732c..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn-1.8.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.0.v20141016/alpn-boot-8.1.0.v20141016.jar|lib/alpn/alpn-boot-8.1.0.v20141016.jar
-
-[exec]
--Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod
deleted file mode 100644
index 0e399f0..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/alpn.mod
+++ /dev/null
@@ -1,36 +0,0 @@
-# ALPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the ALPN layer needed for SPDY (and eventually HTTP/2)
-#
-# This modification has a tight dependency on specific recent updates of
-# Java 1.7 and Java 1.8
-# (Java versions prior to 1.7u40 are not supported)
-#
-# The alpn protonego module will use an appropriate alpn-boot jar for your
-# specific version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing alpn-boot jars, and might
-#            need a new alpn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of alpn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/alpn-${java.version}
-
-[lib]
-lib/jetty-alpn-client-${jetty.version}.jar
-lib/jetty-alpn-server-${jetty.version}.jar
-
-[xml]
-etc/protonego-alpn.xml
-
-[files]
-lib/
-lib/alpn/
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_04.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod
deleted file mode 100644
index 007570b..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_05.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.0.v20120525/npn-boot-1.1.0.v20120525.jar|lib/npn/npn-boot-1.1.0.v20120525.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.0.v20120525.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_06.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod
deleted file mode 100644
index 868a7a7..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_07.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.1.v20121030/npn-boot-1.1.1.v20121030.jar|lib/npn/npn-boot-1.1.1.v20121030.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.1.v20121030.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_09.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_10.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod
deleted file mode 100644
index 20c1db2..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_11.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.3.v20130313/npn-boot-1.1.3.v20130313.jar|lib/npn/npn-boot-1.1.3.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.3.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod
deleted file mode 100644
index 1645a52..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_13.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.4.v20130313/npn-boot-1.1.4.v20130313.jar|lib/npn/npn-boot-1.1.4.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.4.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_15.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_17.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_21.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod
deleted file mode 100644
index 73bc090..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_25.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar|lib/npn/npn-boot-1.1.5.v20130313.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_40.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_45.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod
deleted file mode 100644
index 465e6f0..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_51.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.6.v20130911/npn-boot-1.1.6.v20130911.jar|lib/npn/npn-boot-1.1.6.v20130911.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.6.v20130911.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_55.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod
deleted file mode 100644
index 5f8704d..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn-1.7.0_60.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-[name]
-protonego-boot
-
-[files]
-http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.8.v20141013/npn-boot-1.1.8.v20141013.jar|lib/npn/npn-boot-1.1.8.v20141013.jar
-
-[exec]
--Xbootclasspath/p:lib/npn/npn-boot-1.1.8.v20141013.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod
deleted file mode 100644
index 040aad1..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego-impl/npn.mod
+++ /dev/null
@@ -1,31 +0,0 @@
-# NPN is provided via a -Xbootclasspath that modifies the secure connections
-# in java to support the NPN layer needed for SPDY.
-#
-# This modification has a tight dependency on specific updates of Java 1.7.
-# (No support for Java 8 exists for npn / npn-boot, use alpn instead)
-#
-# The npn module will use an appropriate npn-boot jar for your specific
-# version of Java.
-#
-# IMPORTANT: Versions of Java that exist after this module was created are
-#            not guaranteed to work with existing npn-boot jars, and might
-#            need a new npn-boot to be created / tested / deployed by the
-#            Jetty project in order to provide support for these future
-#            Java versions.
-#
-# All versions of npn-boot can be found at
-# http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/
-
-
-[name]
-protonego-impl
-
-[depend]
-protonego-impl/npn-${java.version}
-
-[xml]
-etc/protonego-npn.xml
-
-[files]
-lib/
-lib/npn/
diff --git a/jetty-start/src/test/resources/usecases/home/modules/protonego.mod b/jetty-start/src/test/resources/usecases/home/modules/protonego.mod
deleted file mode 100644
index d7bba9f..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/protonego.mod
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Protocol Negotiatin Selection Module
-#
-
-[depend]
-protonego-impl/${protonego}
-
-[ini-template]
-# Protocol Negotiation Implementation Selection
-#  choices are:
-#    'npn'  : original implementation for SPDY (now deprecated)
-#    'alpn' : replacement for NPN, in use by current SPDY implementations
-#             and the future HTTP/2 spec
-#  Note: java 1.8+ are ALPN only.
-protonego=alpn
diff --git a/jetty-start/src/test/resources/usecases/home/modules/proxy.mod b/jetty-start/src/test/resources/usecases/home/modules/proxy.mod
deleted file mode 100644
index 7873329..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/proxy.mod
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Jetty Proxy module
-#
-
-[depend]
-server
-client
-
-[lib]
-lib/jetty-proxy-${jetty.version}.jar
-
-[xml]
-# Proxy requires configuration
-etc/jetty-proxy.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/requestlog.mod b/jetty-start/src/test/resources/usecases/home/modules/requestlog.mod
deleted file mode 100644
index 2b048db..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/requestlog.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Request Log module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-requestlog.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/resources.mod b/jetty-start/src/test/resources/usecases/home/modules/resources.mod
deleted file mode 100644
index 8647d81..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/resources.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Module to add resources directory to classpath
-#
-
-[lib]
-resources/
-
-[files]
-resources/
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/rewrite.mod b/jetty-start/src/test/resources/usecases/home/modules/rewrite.mod
deleted file mode 100644
index 85fe5f0..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/rewrite.mod
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Jetty Rewrite module
-#
-
-[depend]
-server
-
-[lib]
-lib/jetty-rewrite-${jetty.version}.jar
-
-[xml]
-# Annotations needs annotations configuration
-etc/jetty-rewrite.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/security.mod b/jetty-start/src/test/resources/usecases/home/modules/security.mod
deleted file mode 100644
index ba31632..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/security.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Jetty Security Module
-#
-
-[depend]
-server
-
-[lib]
-lib/jetty-security-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/server.mod b/jetty-start/src/test/resources/usecases/home/modules/server.mod
deleted file mode 100644
index b1e9f33..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/server.mod
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Base server
-#
-
-[optional]
-ext
-
-[depend]
-base
-xml
-
-[lib]
-lib/servlet-api-3.1.jar
-lib/jetty-schemas-3.1.jar
-lib/jetty-http-${jetty.version}.jar
-lib/jetty-continuation-${jetty.version}.jar
-lib/jetty-server-${jetty.version}.jar
-
-[xml]
-# Annotations needs annotations configuration
-etc/jetty.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/servlet.mod b/jetty-start/src/test/resources/usecases/home/modules/servlet.mod
deleted file mode 100644
index fdb65c5..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/servlet.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Jetty Servlet Module
-#
-
-[depend]
-server
-
-[lib]
-lib/jetty-servlet-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod b/jetty-start/src/test/resources/usecases/home/modules/spdy.mod
deleted file mode 100644
index cf79dfa..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/spdy.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# SPDY Support Module
-#
-
-[depend]
-ssl
-protonego
-
-[lib]
-lib/spdy/*.jar
-
-[xml]
-etc/jetty-ssl.xml
-etc/jetty-spdy.xml
-
-[ini-template]
-## SPDY Configuration
-
-# Port for SPDY connections
-spdy.port=8443
-
-# SPDY idle timeout in milliseconds
-spdy.timeout=30000
-
-# Initial Window Size for SPDY
-#spdy.initialWindowSize=65536
diff --git a/jetty-start/src/test/resources/usecases/home/modules/ssl.mod b/jetty-start/src/test/resources/usecases/home/modules/ssl.mod
deleted file mode 100644
index 449f581..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/ssl.mod
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# SSL Keystore module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-ssl.xml
-
-[files]
-http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore|etc/keystore
-
-[ini-template]
-## SSL Keystore Configuration
-# define the port to use for secure redirection
-jetty.secure.port=8443
-
-# Setup a demonstration keystore and truststore
-jetty.keystore=etc/keystore
-jetty.truststore=etc/keystore
-
-# Set the demonstration passwords.
-# Note that OBF passwords are not secure, just protected from casual observation
-# See http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
-jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
-jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
-
-# Set the client auth behavior
-# Set to true if client certificate authentication is required
-# jetty.ssl.needClientAuth=true
-# Set to true if client certificate authentication is desired
-# jetty.ssl.wantClientAuth=true
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/stats.mod b/jetty-start/src/test/resources/usecases/home/modules/stats.mod
deleted file mode 100644
index 0922469..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/stats.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Stats module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-stats.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/webapp.mod b/jetty-start/src/test/resources/usecases/home/modules/webapp.mod
deleted file mode 100644
index f62c554..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/webapp.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Base server
-#
-
-[depend]
-servlet
-
-[lib]
-lib/jetty-webapp-${jetty.version}.jar
diff --git a/jetty-start/src/test/resources/usecases/home/modules/websocket.mod b/jetty-start/src/test/resources/usecases/home/modules/websocket.mod
deleted file mode 100644
index f45babd..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/websocket.mod
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# WebSocket Feature
-#
-
-# WebSocket needs Annotations feature
-[depend]
-server
-annotations
-
-# WebSocket needs websocket jars (as defined in start.config)
-[lib]
-lib/websocket/*.jar
-
-# WebSocket needs websocket configuration
-[xml]
-etc/jetty-websockets.xml
-
diff --git a/jetty-start/src/test/resources/usecases/home/modules/xinetd.mod b/jetty-start/src/test/resources/usecases/home/modules/xinetd.mod
deleted file mode 100644
index fdc1b3c..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/xinetd.mod
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Stats module
-#
-
-[depend]
-server
-
-[xml]
-etc/jetty-xinetd.xml
diff --git a/jetty-start/src/test/resources/usecases/home/modules/xml.mod b/jetty-start/src/test/resources/usecases/home/modules/xml.mod
deleted file mode 100644
index d53107a..0000000
--- a/jetty-start/src/test/resources/usecases/home/modules/xml.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Jetty XML Configuration
-#
-
-[depend]
-base
-
-[lib]
-lib/jetty-xml-${jetty.version}.jar
-
diff --git a/jetty-start/src/test/resources/usecases/home/resources/.nodelete b/jetty-start/src/test/resources/usecases/home/resources/.nodelete
deleted file mode 100644
index e69de29..0000000
--- a/jetty-start/src/test/resources/usecases/home/resources/.nodelete
+++ /dev/null
diff --git a/jetty-start/src/test/resources/usecases/home/start.ini b/jetty-start/src/test/resources/usecases/home/start.ini
deleted file mode 100644
index a65a9cb..0000000
--- a/jetty-start/src/test/resources/usecases/home/start.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-
---module=server,http,jmx,annotations,websocket
diff --git a/jetty-start/src/test/resources/usecases/http2.assert.txt b/jetty-start/src/test/resources/usecases/http2.assert.txt
new file mode 100644
index 0000000..d5baccc
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/http2.assert.txt
@@ -0,0 +1,44 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-jmx.xml
+XML|${jetty.home}/etc/jetty-ssl.xml
+XML|${jetty.home}/etc/jetty-ssl-context.xml
+XML|${jetty.home}/etc/jetty-alpn.xml
+XML|${jetty.home}/etc/jetty-http2.xml
+
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-jmx-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.home}/lib/jetty-alpn-server-9.3.jar
+LIB|${jetty.home}/lib/http2/http2-common-9.3.jar
+LIB|${jetty.home}/lib/http2/http2-hpack-9.3.jar
+LIB|${jetty.home}/lib/http2/http2-server-9.3.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+#PROP|java.version=1.8.0_31
+PROP|jetty.sslContext.keyStorePath=etc/keystore
+PROP|jetty.sslContext.keyStorePassword=friendly
+PROP|jetty.sslContext.keyManagerPassword=icecream
+PROP|jetty.sslContext.trustStorePath=etc/keystore
+PROP|jetty.sslContext.trustStorePassword=sundae
+
+# The Downloads
+DOWNLOAD|maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
+DOWNLOAD|http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/test/config/etc/keystore?id=master|etc/keystore
+
+# The Bootlib
+BOOTLIB|-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
+
+# The Files
+FILE|lib/
+FILE|lib/alpn/
diff --git a/jetty-start/src/test/resources/usecases/http2/start.ini b/jetty-start/src/test/resources/usecases/http2/start.ini
new file mode 100644
index 0000000..96a9c58
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/http2/start.ini
@@ -0,0 +1,12 @@
+
+--module=server,http,jmx,http2
+
+jetty.http.port=9090
+
+# Some SSL keystore configuration
+jetty.sslContext.keyStorePath=etc/keystore
+jetty.sslContext.keyStorePassword=friendly
+jetty.sslContext.keyManagerPassword=icecream
+jetty.sslContext.trustStorePath=etc/keystore
+jetty.sslContext.trustStorePassword=sundae
+
diff --git a/jetty-start/src/test/resources/usecases/include-jetty-dir-logging.assert.txt b/jetty-start/src/test/resources/usecases/include-jetty-dir-logging.assert.txt
new file mode 100644
index 0000000..60f10dd
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/include-jetty-dir-logging.assert.txt
@@ -0,0 +1,37 @@
+# The XMLs we expect (order is important)
+XML|${maven-test-resources}/extra-jetty-dirs/logging/etc/jetty-logging.xml
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-jmx.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-jmx-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/resources
+LIB|${maven-test-resources}/extra-jetty-dirs/logging/lib/logging/logback.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
+
+# Files
+FILE|logs/
diff --git a/jetty-start/src/test/resources/usecases/home/etc/realm.properties b/jetty-start/src/test/resources/usecases/include-jetty-dir-logging/resources/some.properties
similarity index 100%
rename from jetty-start/src/test/resources/usecases/home/etc/realm.properties
rename to jetty-start/src/test/resources/usecases/include-jetty-dir-logging/resources/some.properties
diff --git a/jetty-start/src/test/resources/usecases/include-jetty-dir-logging/start.ini b/jetty-start/src/test/resources/usecases/include-jetty-dir-logging/start.ini
new file mode 100644
index 0000000..d44a453
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/include-jetty-dir-logging/start.ini
@@ -0,0 +1,6 @@
+
+--include-jetty-dir=${start.basedir}/../../extra-jetty-dirs/logging
+--module=server,http,jmx
+#--module=resources
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/jmx.assert.txt b/jetty-start/src/test/resources/usecases/jmx.assert.txt
new file mode 100644
index 0000000..205c2ea
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/jmx.assert.txt
@@ -0,0 +1,31 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-jmx.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-jmx-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
diff --git a/jetty-start/src/test/resources/usecases/jmx/start.ini b/jetty-start/src/test/resources/usecases/jmx/start.ini
new file mode 100644
index 0000000..5339629
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/jmx/start.ini
@@ -0,0 +1,4 @@
+
+--module=server,http,jmx
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/jsp.assert.txt b/jetty-start/src/test/resources/usecases/jsp.assert.txt
new file mode 100644
index 0000000..96bd0ca
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/jsp.assert.txt
@@ -0,0 +1,49 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+XML|${jetty.home}/etc/jetty-plus.xml
+XML|${jetty.home}/etc/jetty-annotations.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-annotations-9.3.jar
+LIB|${jetty.home}/lib/annotations/asm-5.0.1.jar
+LIB|${jetty.home}/lib/annotations/asm-commons-5.0.1.jar
+LIB|${jetty.home}/lib/annotations/javax.annotation-api-1.2.jar
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-jndi-9.3.jar
+LIB|${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
+LIB|${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar
+LIB|${jetty.home}/lib/jetty-plus-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-security-9.3.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-servlet-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-webapp-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.apache-jsp-9.3.jar
+LIB|${jetty.home}/lib/apache-jsp/org.eclipse.jetty.orbit.org.eclipse.jdt.core-3.8.2.v20130121.jar
+LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-el-8.0.20.M0.jar
+LIB|${jetty.home}/lib/apache-jsp/org.mortbay.jasper.apache-jsp-8.0.20.M0.jar
+
+# The Properties we expect (order is irrelevant)
+# (these are the properties we actually set in the configuration)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
+
+# Files / Directories to create
+# FILE|lib/
diff --git a/jetty-start/src/test/resources/usecases/jsp/start.ini b/jetty-start/src/test/resources/usecases/jsp/start.ini
new file mode 100644
index 0000000..f01871c
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/jsp/start.ini
@@ -0,0 +1,6 @@
+
+--module=server
+--module=http
+--module=jsp
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/logging.assert.txt b/jetty-start/src/test/resources/usecases/logging.assert.txt
new file mode 100644
index 0000000..90780a9
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/logging.assert.txt
@@ -0,0 +1,45 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+LIB|${jetty.base}/lib/logging/slf4j-api.jar
+LIB|${jetty.base}/lib/logging/jul-to-slf4j.jar
+LIB|${jetty.base}/lib/logging/logback-core.jar
+LIB|${jetty.base}/lib/logging/logback-classic.jar
+LIB|${jetty.base}/resources
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+# (these are the ones set by default from jetty.home modules)
+# PROP|jetty.http.idleTimeout=30000
+# PROP|jetty.httpConfig.delayDispatchUntilContent=false
+# PROP|jetty.server.dumpAfterStart=false
+# PROP|jetty.server.dumpBeforeStop=false
+# PROP|jetty.httpConfig.outputBufferSize=32768
+# PROP|jetty.httpConfig.requestHeaderSize=8192
+# PROP|jetty.httpConfig.responseHeaderSize=8192
+# PROP|jetty.httpConfig.sendDateHeader=false
+# PROP|jetty.httpConfig.sendServerVersion=true
+# PROP|jetty.threadPool.maxThreads=200
+# PROP|jetty.threadPool.minThreads=10
+# PROP|jetty.threadPool.idleTimeout=60000
+
+# Other File References
+FILE|logs/
+FILE|resources/
+
+# Downloads
+DOWNLOAD|http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar|lib/logging/slf4j-api-1.6.6.jar
+DOWNLOAD|http://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar|lib/logging/logback-core-1.0.7.jar
+DOWNLOAD|http://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar|lib/logging/logback-classic-1.0.7.jar
+DOWNLOAD|https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/logback.xml|resources/logback.xml
+DOWNLOAD|https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/jetty-logging.properties|resources/jetty-logging.properties
diff --git a/jetty-start/src/test/resources/usecases/base.logging/lib/logging/jul-to-slf4j.jar b/jetty-start/src/test/resources/usecases/logging/lib/logging/jul-to-slf4j.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/lib/logging/jul-to-slf4j.jar
rename to jetty-start/src/test/resources/usecases/logging/lib/logging/jul-to-slf4j.jar
diff --git a/jetty-start/src/test/resources/usecases/base.logging/lib/logging/logback-classic.jar b/jetty-start/src/test/resources/usecases/logging/lib/logging/logback-classic.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/lib/logging/logback-classic.jar
rename to jetty-start/src/test/resources/usecases/logging/lib/logging/logback-classic.jar
diff --git a/jetty-start/src/test/resources/usecases/base.logging/lib/logging/logback-core.jar b/jetty-start/src/test/resources/usecases/logging/lib/logging/logback-core.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/lib/logging/logback-core.jar
rename to jetty-start/src/test/resources/usecases/logging/lib/logging/logback-core.jar
diff --git a/jetty-start/src/test/resources/usecases/base.logging/lib/logging/slf4j-api.jar b/jetty-start/src/test/resources/usecases/logging/lib/logging/slf4j-api.jar
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/lib/logging/slf4j-api.jar
rename to jetty-start/src/test/resources/usecases/logging/lib/logging/slf4j-api.jar
diff --git a/jetty-start/src/test/resources/usecases/base.logging/modules/logging.mod b/jetty-start/src/test/resources/usecases/logging/modules/logging.mod
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/modules/logging.mod
rename to jetty-start/src/test/resources/usecases/logging/modules/logging.mod
diff --git a/jetty-start/src/test/resources/usecases/base.logging/resources/jetty-logging.properties b/jetty-start/src/test/resources/usecases/logging/resources/jetty-logging.properties
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/resources/jetty-logging.properties
rename to jetty-start/src/test/resources/usecases/logging/resources/jetty-logging.properties
diff --git a/jetty-start/src/test/resources/usecases/base.logging/resources/logback.xml b/jetty-start/src/test/resources/usecases/logging/resources/logback.xml
similarity index 100%
rename from jetty-start/src/test/resources/usecases/base.logging/resources/logback.xml
rename to jetty-start/src/test/resources/usecases/logging/resources/logback.xml
diff --git a/jetty-start/src/test/resources/usecases/logging/start.ini b/jetty-start/src/test/resources/usecases/logging/start.ini
new file mode 100644
index 0000000..083675e
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/logging/start.ini
@@ -0,0 +1,7 @@
+
+--module=server
+--module=http
+--module=logging
+--module=resources
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http.mod b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http.mod
new file mode 100644
index 0000000..cff8028
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http.mod
@@ -0,0 +1,39 @@
+#
+# Jetty HTTP Connector
+#
+
+[version]
+9.3
+
+[depend]
+server
+
+[xml]
+etc/jetty-http.xml
+
+[ini-template]
+### HTTP Connector Configuration
+
+## Connector host/address to bind to
+# jetty.http.host=0.0.0.0
+
+## Connector port to listen on
+# jetty.http.port=80
+
+## Connector idle timeout in milliseconds
+# jetty.http.idleTimeout=30000
+
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.http.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.http.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.http.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.http.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.http.acceptorPriorityDelta=0
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http3.mod b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http3.mod
new file mode 100644
index 0000000..34ec477
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/modules/http3.mod
@@ -0,0 +1,10 @@
+#
+# Fake Jetty HTTP/3 Connector
+#
+
+[version]
+10.0
+
+[depend]
+server
+
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules-too-new/start.ini b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/start.ini
new file mode 100644
index 0000000..42b2db8
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules-too-new/start.ini
@@ -0,0 +1,6 @@
+
+--module=server
+--module=http
+--module=http3
+
+jetty.http.port=9090
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules.assert.txt b/jetty-start/src/test/resources/usecases/versioned-modules.assert.txt
new file mode 100644
index 0000000..f1b8108
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules.assert.txt
@@ -0,0 +1,18 @@
+# The XMLs we expect (order is important)
+XML|${jetty.home}/etc/jetty.xml
+XML|${jetty.home}/etc/jetty-http.xml
+
+# The LIBs we expect (order is irrelevant)
+LIB|${jetty.home}/lib/jetty-http-9.3.jar
+LIB|${jetty.home}/lib/jetty-io-9.3.jar
+LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
+LIB|${jetty.home}/lib/jetty-server-9.3.jar
+LIB|${jetty.home}/lib/jetty-util-9.3.jar
+LIB|${jetty.home}/lib/jetty-xml-9.3.jar
+LIB|${jetty.home}/lib/servlet-api-3.1.jar
+
+# The Properties we expect (order is irrelevant)
+# (this is the property we actually set in jetty.base)
+PROP|jetty.http.port=9090
+PROP|from-module=old
+PROP|the-future=is-new
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules/modules/http.mod b/jetty-start/src/test/resources/usecases/versioned-modules/modules/http.mod
new file mode 100644
index 0000000..cff8028
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules/modules/http.mod
@@ -0,0 +1,39 @@
+#
+# Jetty HTTP Connector
+#
+
+[version]
+9.3
+
+[depend]
+server
+
+[xml]
+etc/jetty-http.xml
+
+[ini-template]
+### HTTP Connector Configuration
+
+## Connector host/address to bind to
+# jetty.http.host=0.0.0.0
+
+## Connector port to listen on
+# jetty.http.port=80
+
+## Connector idle timeout in milliseconds
+# jetty.http.idleTimeout=30000
+
+## Connector socket linger time in seconds (-1 to disable)
+# jetty.http.soLingerTime=-1
+
+## Number of acceptors (-1 picks default based on number of cores)
+# jetty.http.acceptors=-1
+
+## Number of selectors (-1 picks default based on number of cores)
+# jetty.http.selectors=-1
+
+## ServerSocketChannel backlog (0 picks platform default)
+# jetty.http.acceptorQueueSize=0
+
+## Thread priority delta to give to acceptor threads
+# jetty.http.acceptorPriorityDelta=0
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules/modules/new.mod b/jetty-start/src/test/resources/usecases/versioned-modules/modules/new.mod
new file mode 100644
index 0000000..ae1b359
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules/modules/new.mod
@@ -0,0 +1,10 @@
+#
+# New Module (testing module based defaults)
+#
+
+[version]
+9.3
+
+[ini]
+the-future=is-new
+
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules/modules/old.mod b/jetty-start/src/test/resources/usecases/versioned-modules/modules/old.mod
new file mode 100644
index 0000000..ff27710
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules/modules/old.mod
@@ -0,0 +1,7 @@
+#
+# Old Module (backward compat test with 9.2 modules)
+#
+
+[defaults]
+from-module=old
+
diff --git a/jetty-start/src/test/resources/usecases/versioned-modules/start.ini b/jetty-start/src/test/resources/usecases/versioned-modules/start.ini
new file mode 100644
index 0000000..c306053
--- /dev/null
+++ b/jetty-start/src/test/resources/usecases/versioned-modules/start.ini
@@ -0,0 +1,7 @@
+
+--module=server
+--module=http
+--module=old
+--module=new
+
+jetty.http.port=9090
diff --git a/jetty-util-ajax/pom.xml b/jetty-util-ajax/pom.xml
index 49ac9ab..7dd1e2c 100644
--- a/jetty-util-ajax/pom.xml
+++ b/jetty-util-ajax/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-util-ajax</artifactId>
@@ -15,54 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.slf4j;version="[1.5,2.0)";resolution:=optional,org.slf4j.impl;version="[1.5,2.0)";resolution:=optional,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-<!--
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
--->
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java
index 7d8afc1..b14568c 100644
--- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java
+++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java
@@ -39,51 +39,51 @@
 
 /**
  * JSON Parser and Generator.
- * <p />
+ * <p>
  * This class provides some static methods to convert POJOs to and from JSON
  * notation. The mapping from JSON to java is:
  *
  * <pre>
- *   object ==> Map
- *   array  ==> Object[]
- *   number ==> Double or Long
- *   string ==> String
- *   null   ==> null
- *   bool   ==> Boolean
+ *   object --&gt; Map
+ *   array  --&gt; Object[]
+ *   number --&gt; Double or Long
+ *   string --&gt; String
+ *   null   --&gt; null
+ *   bool   --&gt; Boolean
  * </pre>
 
  * The java to JSON mapping is:
  *
  * <pre>
- *   String --> string
- *   Number --> number
- *   Map    --> object
- *   List   --> array
- *   Array  --> array
- *   null   --> null
- *   Boolean--> boolean
- *   Object --> string (dubious!)
+ *   String --&gt; string
+ *   Number --&gt; number
+ *   Map    --&gt; object
+ *   List   --&gt; array
+ *   Array  --&gt; array
+ *   null   --&gt; null
+ *   Boolean--&gt; boolean
+ *   Object --&gt; string (dubious!)
  * </pre>
  *
  * The interface {@link JSON.Convertible} may be implemented by classes that
  * wish to externalize and initialize specific fields to and from JSON objects.
  * Only directed acyclic graphs of objects are supported.
- * <p />
+ * <p>
  * The interface {@link JSON.Generator} may be implemented by classes that know
  * how to render themselves as JSON and the {@link #toString(Object)} method
  * will use {@link JSON.Generator#addJSON(Appendable)} to generate the JSON.
  * The class {@link JSON.Literal} may be used to hold pre-generated JSON object.
- * <p />
+ * <p>
  * The interface {@link JSON.Convertor} may be implemented to provide static
  * converters for objects that may be registered with
  * {@link #registerConvertor(Class, Convertor)}.
  * These converters are looked up by class, interface and super class by
  * {@link #getConvertor(Class)}.
- * <p />
+ * <p>
  * If a JSON object has a "class" field, then a java class for that name is
  * loaded and the method {@link #convertTo(Class,Map)} is used to find a
  * {@link JSON.Convertor} for that class.
- * <p />
+ * <p>
  * If a JSON object has a "x-class" field then a direct lookup for a
  * {@link JSON.Convertor} for that class name is done (without loading the class).
  */
@@ -188,6 +188,7 @@
      * @param in
      *            Reader containing JSON object or array.
      * @return A Map, Object array or primitive array parsed from the JSON.
+     * @throws IOException if unable to parse
      */
     public static Object parse(Reader in) throws IOException
     {
@@ -200,6 +201,7 @@
      * @param stripOuterComment
      *            If true, an outer comment around the JSON is ignored.
      * @return A Map, Object array or primitive array parsed from the JSON.
+     * @throws IOException if unable to parse
      */
     public static Object parse(Reader in, boolean stripOuterComment) throws IOException
     {
@@ -207,10 +209,11 @@
     }
 
     /**
-     * @deprecated use {@link #parse(Reader)}
      * @param in
      *            Reader containing JSON object or array.
      * @return A Map, Object array or primitive array parsed from the JSON.
+     * @throws IOException if unable to parse
+     * @deprecated use {@link #parse(Reader)}
      */
     @Deprecated
     public static Object parse(InputStream in) throws IOException
@@ -219,12 +222,13 @@
     }
 
     /**
-     * @deprecated use {@link #parse(Reader, boolean)}
      * @param in
      *            Stream containing JSON object or array.
      * @param stripOuterComment
      *            If true, an outer comment around the JSON is ignored.
      * @return A Map, Object array or primitive array parsed from the JSON.
+     * @throws IOException if unable to parse
+     * @deprecated use {@link #parse(Reader, boolean)}
      */
     @Deprecated
     public static Object parse(InputStream in, boolean stripOuterComment) throws IOException
diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java
index 7db57c8..c19be74 100644
--- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java
+++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSONObjectConvertor.java
@@ -28,12 +28,8 @@
 
 import org.eclipse.jetty.util.ajax.JSON.Output;
 
-/* ------------------------------------------------------------ */
 /**
  * Convert an Object to JSON using reflection on getters methods.
- * 
- * 
- *
  */
 public class JSONObjectConvertor implements JSON.Convertor
 {
@@ -52,7 +48,7 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param fromJSON
+     * @param fromJSON true to convert from JSON
      * @param excluded An array of field names to exclude from the conversion
      */
     public JSONObjectConvertor(boolean fromJSON,String[] excluded)
diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml
index e145f56..6ca7c02 100644
--- a/jetty-util/pom.xml
+++ b/jetty-util/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-util</artifactId>
@@ -15,52 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2)",org.slf4j;version="[1.6,2.0)";resolution:=optional,org.slf4j.impl;version="[1.6,2.0)";resolution:=optional,*</Import-Package>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-util/src/main/config/etc/jetty-logging.xml b/jetty-util/src/main/config/etc/jetty-logging.xml
index 52589ee..dc7fe9e 100644
--- a/jetty-util/src/main/config/etc/jetty-logging.xml
+++ b/jetty-util/src/main/config/etc/jetty-logging.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure stderr and stdout to a Jetty rollover log file        -->
@@ -13,10 +12,12 @@
     <New id="ServerLog" class="java.io.PrintStream">
       <Arg>
         <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
-          <Arg><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.stderrout.log</Arg>
-          <Arg type="boolean">false</Arg>
-          <Arg type="int">90</Arg>
-          <Arg><Call class="java.util.TimeZone" name="getTimeZone"><Arg>GMT</Arg></Call></Arg>
+          <Arg><Property name="jetty.logging.dir" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.stderrout.log</Arg>
+          <Arg type="boolean"><Property name="jetty.logging.append" default="false"/></Arg>
+          <Arg type="int"><Property name="jetty.logging.retainDays" default="90"/></Arg>
+          <Arg>
+              <Call class="java.util.TimeZone" name="getTimeZone"><Arg><Property name="jetty.logging.timezone" default="GMT"/></Arg></Call>
+          </Arg>
           <Get id="ServerLogName" name="datedFilename"/>
         </New>
       </Arg>
diff --git a/jetty-util/src/main/config/modules/logging.mod b/jetty-util/src/main/config/modules/logging.mod
index a39bfe4..4f30a88 100644
--- a/jetty-util/src/main/config/modules/logging.mod
+++ b/jetty-util/src/main/config/modules/logging.mod
@@ -14,18 +14,23 @@
 
 [ini-template]
 ## Logging Configuration
-# Configure jetty logging for default internal behavior STDERR output
+## Configure jetty logging for default internal behavior STDERR output
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
 
-# Configure jetty logging for slf4j
+## Configure jetty logging for slf4j
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog
 
-# Configure jetty logging for java.util.logging
+## Configure jetty logging for java.util.logging
 # -Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog
 
-# STDERR / STDOUT Logging
-# Number of days to retain logs
-# jetty.log.retain=90
-# Directory for logging output
-# Either a path relative to ${jetty.base} or an absolute path
-# jetty.logs=logs
+## Logging directory (relative to $jetty.base)
+# jetty.logging.dir=logs
+
+## Whether to append to existing file
+# jetty.logging.append=false
+
+## How many days to retain old log files
+# jetty.logging.retainDays=90
+
+## Timezone of the log timestamps
+# jetty.logging.timezone=GMT
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
index c9b3286..522c99b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
@@ -22,12 +22,13 @@
 import java.nio.charset.StandardCharsets;
 
 
-/* ------------------------------------------------------------ */
-/** Abstract Trie implementation.
+/** 
+ * Abstract Trie implementation.
  * <p>Provides some common implementations, which may not be the most
  * efficient. For byte operations, the assumption is made that the charset
  * is ISO-8859-1</p>
- * @param <V>
+ * 
+ * @param <V> the type of object that the Trie holds
  */
 public abstract class AbstractTrie<V> implements Trie<V>
 {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java
index 44d35f1..aba3ec8 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayQueue.java
@@ -25,11 +25,12 @@
 /* ------------------------------------------------------------ */
 /**
  * Queue backed by circular array.
- * <p/>
+ * <p>
  * This partial Queue implementation (also with {@link #remove()} for stack operation)
  * is backed by a growable circular array.
+ * </p>
  *
- * @param <E>
+ * @param <E> the type of object the queue holds
  */
 public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
 {
@@ -91,6 +92,15 @@
     }
 
     /* ------------------------------------------------------------ */
+    /**
+     * @return the next slot to be used
+     */
+    public int getNextSlotUnsafe()
+    {
+        return _nextSlot;
+    }
+    
+    /* ------------------------------------------------------------ */
     @Override
     public boolean add(E e)
     {
@@ -109,9 +119,9 @@
     }
 
     /* ------------------------------------------------------------ */
-    private boolean enqueue(E e)
+    protected boolean enqueue(E e)
     {
-        if (_size == _elements.length && !grow())
+        if (_size == _elements.length && !growUnsafe())
             return false;
 
         _size++;
@@ -192,7 +202,7 @@
     }
 
     /* ------------------------------------------------------------ */
-    private E dequeue()
+    protected E dequeue()
     {
         E e = at(_nextE);
         _elements[_nextE] = null;
@@ -246,6 +256,12 @@
     }
 
     /* ------------------------------------------------------------ */
+    public int sizeUnsafe()
+    {
+        return _size;
+    }
+
+    /* ------------------------------------------------------------ */
     @Override
     public E get(int index)
     {
@@ -339,7 +355,7 @@
             if (index < 0 || index > _size)
                 throw new IndexOutOfBoundsException("!(" + 0 + "<" + index + "<=" + _size + ")");
 
-            if (_size == _elements.length && !grow())
+            if (_size == _elements.length && !growUnsafe())
                 throw new IllegalStateException("Full");
 
             if (index == _size)
@@ -384,25 +400,33 @@
     }
 
     /* ------------------------------------------------------------ */
-    protected boolean grow()
+    protected void resizeUnsafe(int newCapacity)
     {
-        synchronized (_lock)
+        newCapacity = Math.max(newCapacity,_size);
+        Object[] elements = new Object[newCapacity];
+
+        if (_size>0)
         {
-            if (_growCapacity <= 0)
-                return false;
-
-            Object[] elements = new Object[_elements.length + _growCapacity];
-
-            int split = _elements.length - _nextE;
-            if (split > 0)
+            if (_nextSlot>_nextE)
+                System.arraycopy(_elements, _nextE, elements, 0, _size);
+            else
+            {
+                int split = _elements.length - _nextE;
                 System.arraycopy(_elements, _nextE, elements, 0, split);
-            if (_nextE != 0)
                 System.arraycopy(_elements, 0, elements, split, _nextSlot);
-
-            _elements = elements;
-            _nextE = 0;
-            _nextSlot = _size;
-            return true;
+            }
         }
+        _elements = elements;
+        _nextE = 0;
+        _nextSlot = _size;
+    }
+    
+    /* ------------------------------------------------------------ */
+    protected boolean growUnsafe()
+    {
+        if (_growCapacity <= 0)
+            return false;
+        resizeUnsafe(_elements.length+_growCapacity);
+        return true;
     }
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
index 79f0871..710444d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
@@ -24,20 +24,22 @@
 import java.util.Set;
 
 
-/* ------------------------------------------------------------ */
 /** 
  * <p>A Ternary Trie String lookup data structure.</p>
- * This Trie is of a fixed size and cannot grow (which can be a good thing with regards to DOS when used as a cache).
  * <p>
- * The Trie is stored in 3 arrays:<dl>
+ * This Trie is of a fixed size and cannot grow (which can be a good thing with regards to DOS when used as a cache).
+ * </p>
+ * <p>
+ * The Trie is stored in 3 arrays:
+ * </p>
+ * <dl>
  * <dt>char[] _tree</dt><dd>This is semantically 2 dimensional array flattened into a 1 dimensional char array. The second dimension
  * is that every 4 sequential elements represents a row of: character; hi index; eq index; low index, used to build a
  * ternary trie of key strings.</dd>
- * <dt>String[] _key<dt><dd>An array of key values where each element matches a row in the _tree array. A non zero key element 
+ * <dt>String[] _key</dt><dd>An array of key values where each element matches a row in the _tree array. A non zero key element 
  * indicates that the _tree row is a complete key rather than an intermediate character of a longer key.</dd>
  * <dt>V[] _value</dt><dd>An array of values corresponding to the _key array</dd>
  * </dl>
- * </p>
  * <p>The lookup of a value will iterate through the _tree array matching characters. If the equal tree branch is followed,
  * then the _key array is looked up to see if this is a complete match.  If a match is found then the _value array is looked up
  * to return the matching value.
@@ -52,7 +54,7 @@
  * Trie is required external locks need to be applied.
  * </p>
  * 
- * @param <V>
+ * @param <V> the Entry type 
  */
 public class ArrayTernaryTrie<V> extends AbstractTrie<V>
 {
@@ -141,8 +143,8 @@
 
     /* ------------------------------------------------------------ */
     /** Copy Trie and change capacity by a factor
-     * @param trie
-     * @param factor
+     * @param trie the trie to copy from
+     * @param factor the factor to grow the capacity by
      */
     public ArrayTernaryTrie(ArrayTernaryTrie<V> trie, double factor)
     {
@@ -153,6 +155,16 @@
         _tree=Arrays.copyOf(trie._tree, capacity*ROW_SIZE);
         _key=Arrays.copyOf(trie._key, capacity);
     }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void clear()
+    {
+        _rows=0;
+        Arrays.fill(_value,null);
+        Arrays.fill(_tree,(char)0);
+        Arrays.fill(_key,null);
+    }
     
     /* ------------------------------------------------------------ */
     @Override
@@ -311,9 +323,11 @@
     private V getBest(int t,String s,int offset,int len)
     {
         int node=t;
-        loop: for(int i=0; i<len; i++)
+        int end=offset+len;
+        loop: while(offset<end)
         {
-            char c=s.charAt(offset+i);
+            char c=s.charAt(offset++);
+            len--;
             if(isCaseInsensitive() && c<128)
                 c=StringUtil.lowercases[c];
 
@@ -333,9 +347,9 @@
                     if (_key[t]!=null)
                     {
                         node=t;
-                        V best=getBest(t,s,offset+i+1,len-i-1);
-                        if (best!=null)
-                            return best;
+                        V better=getBest(t,s,offset,len);
+                        if (better!=null)
+                            return better;
                     }
                     break;
                 }
@@ -362,9 +376,11 @@
     private V getBest(int t,byte[] b, int offset, int len)
     {
         int node=t;
-        loop: for(int i=0; i<len; i++)
+        int end=offset+len;
+        loop: while(offset<end)
         {
-            byte c=(byte)(b[offset+i]&0x7f);
+            byte c=(byte)(b[offset++]&0x7f);
+            len--;
             if(isCaseInsensitive())
                 c=(byte)StringUtil.lowercases[c];
 
@@ -384,9 +400,9 @@
                     if (_key[t]!=null)
                     {
                         node=t;
-                        V best=getBest(t,b,offset+i+1,len-i-1);
-                        if (best!=null)
-                            return best;
+                        V better=getBest(t,b,offset,len);
+                        if (better!=null)
+                            return better;
                     }
                     break;
                 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
index 9dbf994..bf88ab9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -44,7 +45,7 @@
  * and not mutated during that access.  If concurrent mutations of the
  * Trie is required external locks need to be applied.
  * </p>
- * @param <V>
+ * @param <V> the entry type
  */
 public class ArrayTrie<V> extends AbstractTrie<V>
 {
@@ -132,7 +133,16 @@
         _rowIndex=new char[capacity*32];
         _key=new String[capacity];
     }
-    
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void clear()
+    {
+        _rows=0;
+        Arrays.fill(_value,null);
+        Arrays.fill(_rowIndex,(char)0);
+        Arrays.fill(_key,null);
+    }
     
     /* ------------------------------------------------------------ */
     @Override
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayUtil.java
index f1d3869..386f530 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayUtil.java
@@ -25,8 +25,8 @@
 import java.util.List;
 
 
-/* ------------------------------------------------------------ */
 /**
+ * Utility methods for Array manipulation
  */
 public class ArrayUtil
     implements Cloneable, Serializable
@@ -60,6 +60,7 @@
      * @param item The item to add
      * @param type The type of the array (in case of null array)
      * @return new array with contents of array plus item
+     * @param <T> the array entry type
      */
     public static<T> T[] addToArray(T[] array, T item, Class<?> type)
     {
@@ -86,6 +87,7 @@
      * @param item The item to add
      * @param type The type of the array (in case of null array)
      * @return new array with contents of array plus item
+     * @param <T> the array entry type
      */
     public static<T> T[] prependToArray(T item, T[] array, Class<?> type)
     {
@@ -113,6 +115,7 @@
     /**
      * @param array Any array of object
      * @return A new <i>modifiable</i> list initialised with the elements from <code>array</code>.
+     * @param <E> the array entry type
      */
     public static<E> List<E> asMutableList(E[] array)
     {	
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
index 48bc6d9..0bca3a2 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/B64Code.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
 
 
 /** Fast B64 Encoder/Decoder as described in RFC 1421.
@@ -35,12 +36,12 @@
 {
     private static final char __pad='=';
     private static final char[] __rfc1421alphabet=
-            {
-                'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
-                'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
-                'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
-                'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
-            };
+        {
+        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+        };
 
     private static final byte[] __rfc1421nibbles;
     static
@@ -52,6 +53,25 @@
             __rfc1421nibbles[(byte)__rfc1421alphabet[b]]=b;
         __rfc1421nibbles[(byte)__pad]=0;
     }
+    
+    private static final char[] __rfc4648urlAlphabet=
+        {
+        'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+        'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+        'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+        'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_'
+        };
+
+    private static final byte[] __rfc4648urlNibbles;
+    static
+    {
+        __rfc4648urlNibbles=new byte[256];
+        for (int i=0;i<256;i++)
+            __rfc4648urlNibbles[i]=-1;
+        for (byte b=0;b<64;b++)
+            __rfc4648urlNibbles[(byte)__rfc4648urlAlphabet[b]]=b;
+        __rfc4648urlNibbles[(byte)__pad]=0;
+    }
 
     private B64Code()
     {
@@ -430,6 +450,75 @@
         return;
     }
     
+    /* ------------------------------------------------------------ */
+    public static byte[] decodeRFC4648URL(String encoded)
+    {
+        if (encoded==null)
+            return null;
+
+        ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3);        
+        decodeRFC4648URL(encoded, bout);
+        return bout.toByteArray();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Base 64 decode as described in RFC 4648 URL.
+     * <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
+     * @param encoded String to decode.
+     * @param bout stream for decoded bytes
+     * @throws IllegalArgumentException if the input is not a valid
+     *         B64 encoding.
+     */
+    static public void decodeRFC4648URL (String encoded, ByteArrayOutputStream bout)
+    {
+        if (encoded==null)
+            return;
+        
+        if (bout == null)
+            throw new IllegalArgumentException("No outputstream for decoded bytes");
+        
+        int ci=0;
+        byte nibbles[] = new byte[4];
+        int s=0;
+  
+        while (ci<encoded.length())
+        {
+            char c=encoded.charAt(ci++);
+
+            if (c==__pad)
+                break;
+
+            if (Character.isWhitespace(c))
+                continue;
+
+            byte nibble=__rfc4648urlNibbles[c];
+            if (nibble<0)
+                throw new IllegalArgumentException("Not B64 encoded");
+
+            nibbles[s++]=__rfc4648urlNibbles[c];
+
+            switch(s)
+            {
+                case 1:
+                    break;
+                case 2:
+                    bout.write(nibbles[0]<<2|nibbles[1]>>>4);
+                    break;
+                case 3:
+                    bout.write(nibbles[1]<<4|nibbles[2]>>>2);
+                    break;
+                case 4:
+                    bout.write(nibbles[2]<<6|nibbles[3]);
+                    s=0;
+                    break;
+            }
+
+        }
+
+        return;
+    }
+    
 
     public static void encode(int value,Appendable buf) throws IOException
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java
index fa2e8dd..bfe6f63 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java
@@ -33,13 +33,16 @@
 
 /**
  * A BlockingQueue backed by a circular array capable or growing.
- * <p/>
+ * <p>
  * This queue is uses a variant of the two lock queue algorithm to provide an efficient queue or list backed by a growable circular array.
- * <p/>
+ * </p>
+ * <p>
  * Unlike {@link java.util.concurrent.ArrayBlockingQueue}, this class is able to grow and provides a blocking put call.
- * <p/>
+ * </p>
+ * <p>
  * The queue has both a capacity (the size of the array currently allocated) and a max capacity (the maximum size that may be allocated), which defaults to
  * {@link Integer#MAX_VALUE}.
+ * </p>
  * 
  * @param <E>
  *            The element type
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingCallback.java
index 8601d8e..68f256a 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingCallback.java
@@ -26,17 +26,15 @@
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.NonBlockingThread;
 
-/* ------------------------------------------------------------ */
 /**
  * An implementation of Callback that blocks until success or failure.
  */
-public class BlockingCallback implements Callback
+@Deprecated
+public class BlockingCallback implements Callback.NonBlocking
 {
     private static final Logger LOG = Log.getLogger(BlockingCallback.class);
-    
-    private static Throwable SUCCEEDED=new Throwable()
+    private static Throwable SUCCEEDED = new Throwable()
     {
         @Override
         public String toString() { return "SUCCEEDED"; }
@@ -44,9 +42,10 @@
     
     private final CountDownLatch _latch = new CountDownLatch(1);
     private final AtomicReference<Throwable> _state = new AtomicReference<>();
-    
+
     public BlockingCallback()
-    {}
+    {
+    }
 
     @Override
     public void succeeded()
@@ -62,7 +61,8 @@
             _latch.countDown();
     }
 
-    /** Block until the Callback has succeeded or failed and 
+    /**
+     * Blocks until the Callback has succeeded or failed and
      * after the return leave in the state to allow reuse.
      * This is useful for code that wants to repeatable use a FutureCallback to convert
      * an asynchronous API to a blocking API. 
@@ -70,9 +70,6 @@
      */
     public void block() throws IOException
     {
-        if (NonBlockingThread.isNonBlockingThread())
-            LOG.warn("Blocking a NonBlockingThread: ",new Throwable());
-        
         try
         {
             _latch.await();
@@ -94,12 +91,10 @@
             _state.set(null);
         }
     }
-    
-    
+
     @Override
     public String toString()
     {
         return String.format("%s@%x{%s}",BlockingCallback.class.getSimpleName(),hashCode(),_state.get());
     }
-
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
index 9964c3a..5add8c7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java
@@ -19,18 +19,24 @@
 package org.eclipse.jetty.util;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.RandomAccessFile;
+import java.lang.reflect.Field;
+import java.nio.Buffer;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileChannel.MapMode;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.StandardOpenOption;
 import java.util.Arrays;
 
+import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.resource.Resource;
 
 
@@ -42,10 +48,12 @@
  * The various ByteBuffer methods assume a mode and some of them will switch or enforce a mode:
  * Allocate and clear set fill mode; flip and compact switch modes; read and write assume fill 
  * and flush modes.    This duality can result in confusing code such as:
+ * </p>
  * <pre>
  *     buffer.clear();
  *     channel.write(buffer);
  * </pre>
+ * <p>
  * Which looks as if it should write no data, but in fact writes the buffer worth of garbage.
  * </p>
  * <p>
@@ -57,13 +65,14 @@
  * <p>
  * Thus this class provides alternate implementations of {@link #allocate(int)}, 
  * {@link #allocateDirect(int)} and {@link #clear(ByteBuffer)} that leave the buffer
- * in flush mode.   Thus the following tests will pass:<pre>
+ * in flush mode.   Thus the following tests will pass:
+ * </p>
+ * <pre>
  *     ByteBuffer buffer = BufferUtil.allocate(1024);
  *     assert(buffer.remaining()==0);
  *     BufferUtil.clear(buffer);
  *     assert(buffer.remaining()==0);
  * </pre>
- * </p>
  * <p>If the BufferUtil methods {@link #fill(ByteBuffer, byte[], int, int)}, 
  * {@link #append(ByteBuffer, byte[], int, int)} or {@link #put(ByteBuffer, ByteBuffer)} are used,
  * then the caller does not need to explicitly switch the buffer to fill mode.    
@@ -71,6 +80,7 @@
  * then they can use explicit calls of #flipToFill(ByteBuffer) and #flipToFlush(ByteBuffer, int)
  * to change modes.  Note because this convention attempts to avoid the copies of compact, the position
  * is not set to zero on each fill cycle and so its value must be remembered:
+ * </p>
  * <pre>
  *      int pos = BufferUtil.flipToFill(buffer);
  *      try
@@ -82,8 +92,9 @@
  *          flipToFlush(buffer, pos);
  *      }
  * </pre>
- * The flipToFill method will effectively clear the buffer if it is emtpy and will compact the buffer if there is no space.
- * 
+ * <p>
+ * The flipToFill method will effectively clear the buffer if it is empty and will compact the buffer if there is no space.
+ * </p>
  */
 public class BufferUtil
 {
@@ -312,8 +323,7 @@
             {
                 to.put(from);
                 put = remaining;
-                from.position(0);
-                from.limit(0);
+                from.position(from.limit());
             }
             else if (from.hasArray())
             {
@@ -355,7 +365,7 @@
      * @param b bytes to append
      * @param off offset into byte
      * @param len length to append
-     * @throws BufferOverflowException
+     * @throws BufferOverflowException if unable to append buffer due to space limits
      */
     public static void append(ByteBuffer to, byte[] b, int off, int len) throws BufferOverflowException
     {
@@ -392,6 +402,7 @@
     /** Appends a buffer to a buffer
      * @param to Buffer is flush mode
      * @param b buffer to append
+     * @return The position of the valid data before the flipped position.
      */
     public static int append(ByteBuffer to, ByteBuffer b)
     {
@@ -413,6 +424,7 @@
      * @param b bytes to fill
      * @param off offset into byte
      * @param len length to fill
+     * @return The position of the valid data before the flipped position.
      */
     public static int fill(ByteBuffer to, byte[] b, int off, int len)
     {
@@ -521,10 +533,13 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Convert a partial buffer to an ISO-8859-1 String
-     * @param buffer  The buffer to convert in flush mode. The buffer is unchanged
+    /** Convert a partial buffer to a String.
+     * 
+     * @param buffer the buffer to convert 
+     * @param position The position in the buffer to start the string from
+     * @param length The length of the buffer
      * @param charset The {@link Charset} to use to convert the bytes
-     * @return The buffer as a string.
+     * @return  The buffer as a string.
      */
     public static String toString(ByteBuffer buffer, int position, int length, Charset charset)
     {
@@ -553,11 +568,34 @@
      */
     public static int toInt(ByteBuffer buffer)
     {
+        return toInt(buffer,buffer.position(),buffer.remaining());
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Convert buffer to an integer. Parses up to the first non-numeric character. If no number is found an
+     * IllegalArgumentException is thrown
+     *
+     * @param buffer
+     *            A buffer containing an integer in flush mode. The position is not changed.
+     * @param position
+     *            the position in the buffer to start reading from
+     * @param length
+     *            the length of the buffer to use for conversion
+     * @return an int of the buffer bytes
+     */
+    public static int toInt(ByteBuffer buffer, int position, int length)
+    {
         int val = 0;
         boolean started = false;
         boolean minus = false;
 
-        for (int i = buffer.position(); i < buffer.limit(); i++)
+        int limit = position+length;
+        
+        if (length<=0)
+            throw new NumberFormatException(toString(buffer,position,length,StandardCharsets.UTF_8));
+        
+        for (int i = position; i < limit; i++)
         {
             byte b = buffer.get(i);
             if (b <= SPACE)
@@ -809,30 +847,14 @@
 
     public static ByteBuffer toBuffer(String s)
     {
-        return ByteBuffer.wrap(s.getBytes(StandardCharsets.ISO_8859_1));
-    }
-
-    public static ByteBuffer toDirectBuffer(String s)
-    {
-        byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
-        ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
-        buf.put(bytes);
-        buf.flip();
-        return buf;
+        return toBuffer(s, StandardCharsets.ISO_8859_1);
     }
 
     public static ByteBuffer toBuffer(String s, Charset charset)
     {
-        return ByteBuffer.wrap(s.getBytes(charset));
-    }
-
-    public static ByteBuffer toDirectBuffer(String s, Charset charset)
-    {
-        byte[] bytes = s.getBytes(charset);
-        ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
-        buf.put(bytes);
-        buf.flip();
-        return buf;
+        if (s == null)
+            return EMPTY_BUFFER;
+        return toBuffer(s.getBytes(charset));
     }
 
     /**
@@ -842,9 +864,11 @@
      *            the byte array to back buffer with.
      * @return ByteBuffer with provided byte array, in flush mode
      */
-    public static ByteBuffer toBuffer(byte array[])
+    public static ByteBuffer toBuffer(byte[] array)
     {
-        return ByteBuffer.wrap(array);
+        if (array == null)
+            return EMPTY_BUFFER;
+        return toBuffer(array, 0, array.length);
     }
 
     /**
@@ -860,17 +884,71 @@
      */
     public static ByteBuffer toBuffer(byte array[], int offset, int length)
     {
+        if (array == null)
+            return EMPTY_BUFFER;
         return ByteBuffer.wrap(array, offset, length);
     }
 
+    public static ByteBuffer toDirectBuffer(String s)
+    {
+        return toDirectBuffer(s, StandardCharsets.ISO_8859_1);
+    }
+
+    public static ByteBuffer toDirectBuffer(String s, Charset charset)
+    {
+        if (s == null)
+            return EMPTY_BUFFER;
+        byte[] bytes = s.getBytes(charset);
+        ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length);
+        buf.put(bytes);
+        buf.flip();
+        return buf;
+    }
+
     public static ByteBuffer toMappedBuffer(File file) throws IOException
     {
-        try (RandomAccessFile raf = new RandomAccessFile(file, "r"))
+        try (FileChannel channel = FileChannel.open(file.toPath(),StandardOpenOption.READ))
         {
-            return raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
+            return channel.map(MapMode.READ_ONLY, 0, file.length());
         }
     }
 
+    static final Field fdMappedByteBuffer;
+    static
+    {
+        Field fd = null;
+        try
+        {
+            fd=MappedByteBuffer.class.getDeclaredField("fd");
+            fd.setAccessible(true);
+        }
+        catch(Exception e)
+        {   
+        }
+        fdMappedByteBuffer=fd;
+    }
+
+    public static boolean isMappedBuffer(ByteBuffer buffer)
+    {
+        if (!(buffer instanceof MappedByteBuffer))
+            return false;
+        MappedByteBuffer mapped = (MappedByteBuffer) buffer;
+
+        if (fdMappedByteBuffer!=null)
+        {
+            try
+            {
+                if (fdMappedByteBuffer.get(mapped) instanceof FileDescriptor)
+                    return true;
+            }
+            catch(Exception e)
+            {
+            }
+        }            
+        return false;
+    }
+    
+    
     public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
     {
         int len=(int)resource.length();
@@ -928,7 +1006,6 @@
     
     /* ------------------------------------------------------------ */
     /** Convert Buffer to string ID independent of content
-     * @param buffer
      */
     private static void idString(ByteBuffer buffer, StringBuilder out) 
     {
@@ -949,7 +1026,7 @@
     
     /* ------------------------------------------------------------ */
     /** Convert Buffer to string ID independent of content
-     * @param buffer
+     * @param buffer the buffet to generate a string ID from
      * @return A string showing the buffer ID
      */
     public static String toIDString(ByteBuffer buffer)
@@ -962,7 +1039,7 @@
     
     /* ------------------------------------------------------------ */
     /** Convert Buffer to a detail debug string of pointers and content
-     * @param buffer
+     * @param buffer the buffer to generate a detail string from
      * @return A string showing the pointers and content of the buffer
      */
     public static String toDetailString(ByteBuffer buffer)
@@ -991,38 +1068,46 @@
 
     private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
     {
-        for (int i = 0; i < buffer.position(); i++)
+        try
         {
-            appendContentChar(buf,buffer.get(i));
-            if (i == 16 && buffer.position() > 32)
+            for (int i = 0; i < buffer.position(); i++)
             {
-                buf.append("...");
-                i = buffer.position() - 16;
+                appendContentChar(buf,buffer.get(i));
+                if (i == 16 && buffer.position() > 32)
+                {
+                    buf.append("...");
+                    i = buffer.position() - 16;
+                }
             }
+            buf.append("<<<");
+            for (int i = buffer.position(); i < buffer.limit(); i++)
+            {
+                appendContentChar(buf,buffer.get(i));
+                if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
+                {
+                    buf.append("...");
+                    i = buffer.limit() - 16;
+                }
+            }
+            buf.append(">>>");
+            int limit = buffer.limit();
+            buffer.limit(buffer.capacity());
+            for (int i = limit; i < buffer.capacity(); i++)
+            {
+                appendContentChar(buf,buffer.get(i));
+                if (i == limit + 16 && buffer.capacity() > limit + 32)
+                {
+                    buf.append("...");
+                    i = buffer.capacity() - 16;
+                }
+            }
+            buffer.limit(limit);
         }
-        buf.append("<<<");
-        for (int i = buffer.position(); i < buffer.limit(); i++)
+        catch(Throwable x)
         {
-            appendContentChar(buf,buffer.get(i));
-            if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
-            {
-                buf.append("...");
-                i = buffer.limit() - 16;
-            }
+            Log.getRootLogger().ignore(x);
+            buf.append("!!concurrent mod!!");
         }
-        buf.append(">>>");
-        int limit = buffer.limit();
-        buffer.limit(buffer.capacity());
-        for (int i = limit; i < buffer.capacity(); i++)
-        {
-            appendContentChar(buf,buffer.get(i));
-            if (i == limit + 16 && buffer.capacity() > limit + 32)
-            {
-                buf.append("...");
-                i = buffer.capacity() - 16;
-            }
-        }
-        buffer.limit(limit);
     }
 
     private static void appendContentChar(StringBuilder buf, byte b)
@@ -1040,6 +1125,33 @@
         else
             buf.append("\\x").append(TypeUtil.toHexString(b));
     }
+    
+
+    /* ------------------------------------------------------------ */
+    /** Convert buffer to a Hex Summary String.
+     * @param buffer the buffer to generate a hex byte summary from
+     * @return A string showing the escaped content of the buffer around the
+     * position and limit (marked with &lt;&lt;&lt; and &gt;&gt;&gt;)
+     */
+    public static String toHexSummary(ByteBuffer buffer)
+    {
+        if (buffer == null)
+            return "null";
+        StringBuilder buf = new StringBuilder();
+        
+        buf.append("b[").append(buffer.remaining()).append("]=");
+        for (int i = buffer.position(); i < buffer.limit(); i++)
+        {
+            TypeUtil.toHex(buffer.get(i),buf);
+            if (i == buffer.position() + 24 && buffer.limit() > buffer.position() + 32)
+            {
+                buf.append("...");
+                i = buffer.limit() - 8;
+            }
+        }
+        return buf.toString();
+    }
+
 
     private final static int[] decDivisors =
             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
@@ -1084,4 +1196,5 @@
 
 
 
+
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Callback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Callback.java
index 6425e29..8c8f543 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Callback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Callback.java
@@ -27,37 +27,53 @@
 public interface Callback
 {
     /**
+     * Instance of Adapter that can be used when the callback methods need an empty
+     * implementation without incurring in the cost of allocating a new Adapter object.
+     */
+    static Callback NOOP = new Callback(){};
+
+
+    /**
      * <p>Callback invoked when the operation completes.</p>
      *
      * @see #failed(Throwable)
      */
-    public abstract void succeeded();
+    default void succeeded()
+    {}
 
     /**
      * <p>Callback invoked when the operation fails.</p>
      * @param x the reason for the operation failure
      */
-    public void failed(Throwable x);
+    default void failed(Throwable x)
+    {}
 
     /**
+     * @return True if the callback is known to never block the caller
+     */
+    default boolean isNonBlocking()
+    {
+        return false;
+    }
+    
+    
+    /**
+     * Callback interface that declares itself as non-blocking
+     */
+    interface NonBlocking extends Callback
+    {
+        @Override
+        public default boolean isNonBlocking()
+        {
+            return true;
+        }
+    }
+    
+    
+    /**
      * <p>Empty implementation of {@link Callback}</p>
      */
-    public static class Adapter implements Callback
-    {
-        /**
-         * Instance of Adapter that can be used when the callback methods need an empty
-         * implementation without incurring in the cost of allocating a new Adapter object.
-         */
-        public static final Adapter INSTANCE = new Adapter();
-
-        @Override
-        public void succeeded()
-        {
-        }
-
-        @Override
-        public void failed(Throwable x)
-        {
-        }
-    }
+    @Deprecated
+    static class Adapter implements Callback
+    {}
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/CompletableCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/CompletableCallback.java
index 674afd5..47a67df 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/CompletableCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/CompletableCallback.java
@@ -21,16 +21,18 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
+ * <p>
  * A callback to be used by driver code that needs to know whether the callback has been
  * succeeded or failed (that is, completed) just after the asynchronous operation or not,
  * typically because further processing depends on the callback being completed.
  * The driver code competes with the asynchronous operation to complete the callback.
- * <p />
+ * </p>
+ * <p>
  * If the callback is already completed, the driver code continues the processing,
  * otherwise it suspends it. If it is suspended, the callback will be completed some time
  * later, and {@link #resume()} or {@link #abort(Throwable)} will be called to allow the
  * application to resume the processing.
- * <p />
+ * </p>
  * Typical usage:
  * <pre>
  * CompletableCallback callback = new CompletableCallback()
@@ -132,6 +134,7 @@
 
     /**
      * Callback method invoked when this callback is failed.
+     * @param failure the throwable reprsenting the callback failure
      */
     public abstract void abort(Throwable failure);
 
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
index 86a0b36..efa6851 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java
@@ -25,6 +25,8 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicIntegerArray;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.atomic.AtomicReferenceArray;
@@ -32,14 +34,16 @@
 /**
  * A concurrent, unbounded implementation of {@link Queue} that uses singly-linked array blocks
  * to store elements.
- * <p/>
+ * <p>
  * This class is a drop-in replacement for {@link ConcurrentLinkedQueue}, with similar performance
  * but producing less garbage because arrays are used to store elements rather than nodes.
- * <p/>
+ * </p>
+ * <p>
  * The algorithm used is a variation of the algorithm from Gidenstam, Sundell and Tsigas
  * (http://www.adm.hb.se/~AGD/Presentations/CacheAwareQueue_OPODIS.pdf).
+ * </p>
  *
- * @param <T>
+ * @param <T> the Array entry type
  */
 public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
 {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/DateCache.java b/jetty-util/src/main/java/org/eclipse/jetty/util/DateCache.java
index 924e745..81ea82c 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/DateCache.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/DateCache.java
@@ -23,7 +23,6 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
-/* ------------------------------------------------------------ */
 /**  Date Format Cache.
  * Computes String representations of Dates and caches
  * the results so that subsequent requests within the same second
@@ -37,9 +36,7 @@
  *
  * If consecutive calls are frequently very different, then this
  * may be a little slower than a normal DateFormat.
- *
  */
-
 public class DateCache
 {
     public static final String DEFAULT_FORMAT="EEE MMM dd HH:mm:ss zzz yyyy";
@@ -77,6 +74,7 @@
     /* ------------------------------------------------------------ */
     /** Constructor.
      * Make a DateCache that will use the given format
+     * @param format the format to use
      */
     public DateCache(String format)
     {
@@ -161,7 +159,7 @@
 
     /* ------------------------------------------------------------ */
     /** Format a date according to our stored formatter.
-     * @param inDate 
+     * @param inDate the Date
      * @return Formatted date
      */
     public String format(Date inDate)
@@ -187,7 +185,7 @@
     /** Format a date according to our stored formatter.
      * If it happens to be in the same second as the last formatNow
      * call, then the format is reused.
-     * @param inDate 
+     * @param inDate the date in milliseconds since unix epoch 
      * @return Formatted date
      */
     public String format(long inDate)
@@ -215,7 +213,7 @@
      * The passed time is expected to be close to the current time, so it is 
      * compared to the last value passed and if it is within the same second,
      * the format is reused.  Otherwise a new cached format is created.
-     * @param now 
+     * @param now the milliseconds since unix epoch 
      * @return Formatted date
      */
     public String formatNow(long now)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/DecoratedObjectFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/DecoratedObjectFactory.java
new file mode 100644
index 0000000..a669c55
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/DecoratedObjectFactory.java
@@ -0,0 +1,119 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * An ObjectFactory enhanced by {@link Decorator} instances.
+ * <p>
+ * Consistent single location for all Decorator behavior, with equal behavior in a ServletContext and also for a stand
+ * alone client.
+ * <p>
+ * Used by ServletContextHandler, WebAppContext, WebSocketServerFactory, and WebSocketClient.
+ * <p>
+ * Can be found in the ServletContext Attributes at the {@link #ATTR DecoratedObjectFactory.ATTR} key.
+ */
+public class DecoratedObjectFactory implements Iterable<Decorator>
+{
+    private static final Logger LOG = Log.getLogger(DecoratedObjectFactory.class);
+
+    /**
+     * ServletContext attribute for the active DecoratedObjectFactory
+     */
+    public static final String ATTR = DecoratedObjectFactory.class.getName();
+
+    private List<Decorator> decorators = new ArrayList<>();
+
+    public void addDecorator(Decorator decorator)
+    {
+        LOG.debug("Adding Decorator: {}", decorator);
+        this.decorators.add(decorator);
+    }
+
+    public void clear()
+    {
+        this.decorators.clear();
+    }
+
+    public <T> T createInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Creating Instance: " + clazz);
+        }
+        T o = clazz.newInstance();
+        return decorate(o);
+    }
+
+    public <T> T decorate(T obj)
+    {
+        T f = obj;
+        // Decorate is always backwards
+        for (int i = decorators.size() - 1; i >= 0; i--)
+        {
+            f = decorators.get(i).decorate(f);
+        }
+        return f;
+    }
+
+    public void destroy(Object obj)
+    {
+        for (Decorator decorator : this.decorators)
+        {
+            decorator.destroy(obj);
+        }
+    }
+
+    public List<Decorator> getDecorators()
+    {
+        return Collections.unmodifiableList(decorators);
+    }
+
+    @Override
+    public Iterator<Decorator> iterator()
+    {
+        return this.decorators.iterator();
+    }
+
+    public void setDecorators(List<? extends Decorator> decorators)
+    {
+        this.decorators.clear();
+        if (decorators != null)
+        {
+            this.decorators.addAll(decorators);
+        }
+    }
+    
+    @Override
+    public String toString()
+    {
+        StringBuilder str = new StringBuilder();
+        str.append(this.getClass().getName()).append("[decorators=");
+        str.append(Integer.toString(decorators.size()));
+        str.append("]");
+        return str.toString();
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java
new file mode 100644
index 0000000..1a59f7e
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Decorator.java
@@ -0,0 +1,35 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+/**
+ * Interface for 3rd party libraries to decorate recently created objects in Jetty.
+ * <p>
+ * Most common use is weld/CDI.
+ * <p>
+ * This was moved from org.eclipse.jetty.servlet.ServletContextHandler to allow
+ * client applications to also use Weld/CDI to decorate objects.  
+ * Such as websocket client (which has no servlet api requirement)
+ */
+public interface Decorator
+{
+    <T> T decorate(T o);
+
+    void destroy(Object o);
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java b/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java
new file mode 100644
index 0000000..fd94906
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/DeprecationWarning.java
@@ -0,0 +1,86 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class DeprecationWarning implements Decorator
+{
+    private static final Logger LOG = Log.getLogger(DeprecationWarning.class);
+
+    @Override
+    public <T> T decorate(T o)
+    {
+        if (o == null)
+        {
+            return null;
+        }
+
+        Class<?> clazz = o.getClass();
+
+        try
+        {
+            Deprecated depr = clazz.getAnnotation(Deprecated.class);
+            if (depr != null)
+            {
+                LOG.warn("Using @Deprecated Class {}",clazz.getName());
+            }
+        }
+        catch (Throwable t)
+        {
+            LOG.ignore(t);
+        }
+
+        verifyIndirectTypes(clazz.getSuperclass(),clazz,"Class");
+        for (Class<?> ifaceClazz : clazz.getInterfaces())
+        {
+            verifyIndirectTypes(ifaceClazz,clazz,"Interface");
+        }
+
+        return o;
+    }
+
+    private void verifyIndirectTypes(Class<?> superClazz, Class<?> clazz, String typeName)
+    {
+        try
+        {
+            // Report on super class deprecation too
+            while (superClazz != null && superClazz != Object.class)
+            {
+                Deprecated supDepr = superClazz.getAnnotation(Deprecated.class);
+                if (supDepr != null)
+                {
+                    LOG.warn("Using indirect @Deprecated {} {} - (seen from {})",typeName,superClazz.getName(),clazz);
+                }
+
+                superClazz = superClazz.getSuperclass();
+            }
+        }
+        catch (Throwable t)
+        {
+            LOG.ignore(t);
+        }
+    }
+
+    @Override
+    public void destroy(Object o)
+    {
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java
index af6dfd4..a087a6b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostMap.java
@@ -23,8 +23,8 @@
 import java.util.HashSet;
 import java.util.Map;
 
-/* ------------------------------------------------------------ */
 /**
+ * @param <TYPE> the element type
  */
 @SuppressWarnings("serial")
 public class HostMap<TYPE> extends HashMap<String, TYPE>
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IO.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IO.java
index 6e7b482..c5a75bf 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IO.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IO.java
@@ -17,7 +17,9 @@
 //
 
 package org.eclipse.jetty.util;
+
 import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -30,7 +32,6 @@
 import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
 import java.nio.channels.GatheringByteChannel;
 import java.nio.charset.Charset;
 
@@ -42,10 +43,10 @@
  * Provides stream handling utilities in
  * singleton Threadpool implementation accessed by static members.
  */
-public class IO 
+public class IO
 {
     private static final Logger LOG = Log.getLogger(IO.class);
-    
+
     /* ------------------------------------------------------------------- */
     public final static String
         CRLF      = "\015\012";
@@ -79,9 +80,9 @@
             this.read=read;
             this.write=write;
         }
-        
+
         /* ------------------------------------------------------------ */
-        /* 
+        /*
          * @see java.lang.Runnable#run()
          */
         public void run()
@@ -108,46 +109,56 @@
             }
         }
     }
-    
+
     /* ------------------------------------------------------------------- */
     /** Copy Stream in to Stream out until EOF or exception.
+     * @param in the input stream to read from (until EOF)
+     * @param out the output stream to write to
+     * @throws IOException if unable to copy streams
      */
     public static void copy(InputStream in, OutputStream out)
          throws IOException
     {
         copy(in,out,-1);
     }
-    
+
     /* ------------------------------------------------------------------- */
     /** Copy Reader to Writer out until EOF or exception.
+     * @param in the read to read from (until EOF)
+     * @param out the writer to write to
+     * @throws IOException if unable to copy the streams
      */
     public static void copy(Reader in, Writer out)
          throws IOException
     {
         copy(in,out,-1);
     }
-    
+
     /* ------------------------------------------------------------------- */
     /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
+     * @param in the stream to read from
+     * @param out the stream to write to
+     * @param byteCount the number of bytes to copy
+     * @throws IOException if unable to copy the streams
      */
     public static void copy(InputStream in,
                             OutputStream out,
                             long byteCount)
          throws IOException
-    {     
+    {
         byte buffer[] = new byte[bufferSize];
         int len=bufferSize;
-        
+
         if (byteCount>=0)
         {
             while (byteCount>0)
             {
                 int max = byteCount<bufferSize?(int)byteCount:bufferSize;
                 len=in.read(buffer,0,max);
-                
+
                 if (len==-1)
                     break;
-                
+
                 byteCount -= len;
                 out.write(buffer,0,len);
             }
@@ -162,19 +173,23 @@
                 out.write(buffer,0,len);
             }
         }
-    }  
-    
+    }
+
     /* ------------------------------------------------------------------- */
     /** Copy Reader to Writer for byteCount bytes or until EOF or exception.
+     * @param in the Reader to read from
+     * @param out the Writer to write to
+     * @param byteCount the number of bytes to copy
+     * @throws IOException if unable to copy streams
      */
     public static void copy(Reader in,
                             Writer out,
                             long byteCount)
          throws IOException
-    {  
+    {
         char buffer[] = new char[bufferSize];
         int len=bufferSize;
-        
+
         if (byteCount>=0)
         {
             while (byteCount>0)
@@ -182,11 +197,11 @@
                 if (byteCount<bufferSize)
                     len=in.read(buffer,0,(int)byteCount);
                 else
-                    len=in.read(buffer,0,bufferSize);                   
-                
+                    len=in.read(buffer,0,bufferSize);
+
                 if (len==-1)
                     break;
-                
+
                 byteCount -= len;
                 out.write(buffer,0,len);
             }
@@ -216,9 +231,9 @@
 
     /* ------------------------------------------------------------ */
     /** Copy files or directories
-     * @param from
-     * @param to
-     * @throws IOException
+     * @param from the file to copy
+     * @param to the destination to copy to
+     * @throws IOException if unable to copy
      */
     public static void copy(File from,File to) throws IOException
     {
@@ -238,7 +253,7 @@
         }
         else
             to.mkdirs();
-        
+
         File[] files = from.listFiles();
         if (files!=null)
         {
@@ -251,7 +266,7 @@
             }
         }
     }
-    
+
     /* ------------------------------------------------------------ */
     public static void copyFile(File from,File to) throws IOException
     {
@@ -261,18 +276,25 @@
             copy(in,out);
         }
     }
-    
+
     /* ------------------------------------------------------------ */
     /** Read input stream to string.
+     * @param in the stream to read from (until EOF)
+     * @return the String parsed from stream (default Charset)
+     * @throws IOException if unable to read the stream (or handle the charset)
      */
     public static String toString(InputStream in)
         throws IOException
     {
         return toString(in,(Charset)null);
     }
-    
+
     /* ------------------------------------------------------------ */
     /** Read input stream to string.
+     * @param in the stream to read from (until EOF)
+     * @param encoding the encoding to use (can be null to use default Charset)
+     * @return the String parsed from the stream
+     * @throws IOException if unable to read the stream (or handle the charset)
      */
     public static String toString(InputStream in,String encoding)
         throws IOException
@@ -281,6 +303,10 @@
     }
 
     /** Read input stream to string.
+     * @param in the stream to read from (until EOF)
+     * @param encoding the Charset to use (can be null to use default Charset)
+     * @return the String parsed from the stream
+     * @throws IOException if unable to read the stream (or handle the charset)
      */
     public static String toString(InputStream in, Charset encoding)
             throws IOException
@@ -294,6 +320,9 @@
 
     /* ------------------------------------------------------------ */
     /** Read input stream to string.
+     * @param in the reader to read from (until EOF)
+     * @return the String parsed from the reader
+     * @throws IOException if unable to read the stream (or handle the charset)
      */
     public static String toString(Reader in)
         throws IOException
@@ -307,7 +336,8 @@
     /* ------------------------------------------------------------ */
     /** Delete File.
      * This delete will recursively delete directories - BE CAREFULL
-     * @param file The file to be deleted.
+     * @param file The file (or directory) to be deleted.
+     * @return true if anything was deleted. (note: this does not mean that all content in a directory was deleted)
      */
     public static boolean delete(File file)
     {
@@ -322,7 +352,24 @@
         return file.delete();
     }
 
-    /* ------------------------------------------------------------ */
+    /**
+     * Closes an arbitrary closable, and logs exceptions at ignore level
+     *
+     * @param closeable the closeable to close
+     */
+    public static void close(Closeable closeable)
+    {
+        try
+        {
+            if (closeable != null)
+                closeable.close();
+        }
+        catch (IOException ignore)
+        {
+            LOG.ignore(ignore);
+        }
+    }
+
     /**
      * closes an input stream, and logs exceptions
      *
@@ -330,52 +377,39 @@
      */
     public static void close(InputStream is)
     {
-        try
-        {
-            if (is != null)
-                is.close();
-        }
-        catch (IOException e)
-        {
-            LOG.ignore(e);
-        }
+        close((Closeable)is);
+    }
+
+    /**
+     * closes an output stream, and logs exceptions
+     *
+     * @param os the output stream to close
+     */
+    public static void close(OutputStream os)
+    {
+        close((Closeable)os);
     }
 
     /**
      * closes a reader, and logs exceptions
-     * 
+     *
      * @param reader the reader to close
      */
     public static void close(Reader reader)
     {
-        try
-        {
-            if (reader != null)
-                reader.close();
-        } catch (IOException e)
-        {
-            LOG.ignore(e);
-        }
+        close((Closeable)reader);
     }
 
     /**
      * closes a writer, and logs exceptions
-     * 
+     *
      * @param writer the writer to close
      */
     public static void close(Writer writer)
     {
-        try
-        {
-            if (writer != null)
-                writer.close();
-        } 
-        catch (IOException e)
-        {
-            LOG.ignore(e);
-        }
+        close((Closeable)writer);
     }
-    
+
     /* ------------------------------------------------------------ */
     public static byte[] readBytes(InputStream in)
         throws IOException
@@ -388,15 +422,22 @@
     /* ------------------------------------------------------------ */
     /**
      * A gathering write utility wrapper.
-     * <p>This method wraps a gather write with a loop that handles the limitations of some operating systems that
-     * have a limit on the number of buffers written.  The method loops on the write until either all the content
-     * is written or no progress is made.
-     * @param out The GatheringgByteChannel to write to
-     * @param buffers The buffers to write
-     * @param offset The offset into the buffers array
-     * @param length The length in buffers to write
+     * <p>
+     * This method wraps a gather write with a loop that handles the limitations of some operating systems that have a
+     * limit on the number of buffers written. The method loops on the write until either all the content is written or
+     * no progress is made.
+     *
+     * @param out
+     *            The GatheringByteChannel to write to
+     * @param buffers
+     *            The buffers to write
+     * @param offset
+     *            The offset into the buffers array
+     * @param length
+     *            The length in buffers to write
      * @return The total bytes written
      * @throws IOException
+     *             if unable write to the GatheringByteChannel
      */
     public static long write(GatheringByteChannel out, ByteBuffer[] buffers, int offset, int length) throws IOException
     {
@@ -405,14 +446,14 @@
         {
             // Write as much as we can
             long wrote=out.write(buffers,offset,length);
-            
+
             // If we can't write any more, give up
             if (wrote==0)
                 break;
-            
+
             // count the total
             total+=wrote;
-            
+
             // Look for unwritten content
             for (int i=offset;i<buffers.length;i++)
             {
@@ -426,32 +467,12 @@
             }
             length=0;
         }
-        
+
         return total;
     }
-    
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * closes an output stream, and logs exceptions
-     *
-     * @param os the output stream to close
-     */
-    public static void close(OutputStream os)
-    {
-        try
-        {
-            if (os != null)
-                os.close();
-        }
-        catch (IOException e)
-        {
-            LOG.ignore(e);
-        }
-    }
 
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * @return An outputstream to nowhere
      */
     public static OutputStream getNullStream()
@@ -460,17 +481,17 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * @return An outputstream to nowhere
      */
     public static InputStream getClosedStream()
     {
         return __closedStream;
     }
-    
+
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
-    private static class NullOS extends OutputStream                                    
+    private static class NullOS extends OutputStream
     {
         @Override
         public void close(){}
@@ -485,10 +506,10 @@
     }
     private static NullOS __nullStream = new NullOS();
 
-    
+
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
-    private static class ClosedIS extends InputStream                                    
+    private static class ClosedIS extends InputStream
     {
         @Override
         public int read() throws IOException
@@ -497,28 +518,28 @@
         }
     }
     private static ClosedIS __closedStream = new ClosedIS();
-    
+
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * @return An writer to nowhere
      */
     public static Writer getNullWriter()
     {
         return __nullWriter;
     }
-    
+
     /* ------------------------------------------------------------ */
-    /** 
+    /**
      * @return An writer to nowhere
      */
     public static PrintWriter getNullPrintWriter()
     {
         return __nullPrintWriter;
     }
-    
+
     /* ------------------------------------------------------------ */
     /* ------------------------------------------------------------ */
-    private static class NullWrite extends Writer                                    
+    private static class NullWrite extends Writer
     {
         @Override
         public void close(){}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java
index 5395724..e1292b1 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java
@@ -32,14 +32,15 @@
  * four octet wildcard specifications (a.b.c.d) that are defined as follows.
  * </p>
  * <pre>
- * nnn - an absolute value (0-255)
- * mmm-nnn - an inclusive range of absolute values, 
- *           with following shorthand notations:
- *           nnn- => nnn-255
- *           -nnn => 0-nnn
- *           -    => 0-255
- * a,b,... - a list of wildcard specifications
+ *     nnn  - an absolute value (0-255)
+ * mmm-nnn  - an inclusive range of absolute values, 
+ *            with following shorthand notations:
+ *              nnn- =&gt; nnn-255
+ *             -nnn  =&gt; 0-nnn
+ *             -     =&gt; 0-255
+ *          a,b,...  - a list of wildcard specifications
  * </pre>
+ * @param <TYPE> the Map Entry value type
  */
 @SuppressWarnings("serial")
 public class IPAddressMap<TYPE> extends HashMap<String, TYPE>
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java
index 80d13c3..9ee2e66 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java
@@ -19,7 +19,9 @@
 package org.eclipse.jetty.util;
 
 import java.util.HashSet;
+import java.util.Objects;
 import java.util.Set;
+import java.util.function.Predicate;
 
 
 /** Utility class to maintain a set of inclusions and exclusions.
@@ -63,9 +65,12 @@
     }
     
     /**
-     * Construct an IncludeExclude
+     * Construct an IncludeExclude.
+     * <p>
+     * If the {@link Set} class also implements {@link Predicate}, then that Predicate is
+     * used to match against the set, otherwise a simple {@link Set#contains(Object)} test is used.
      * @param setClass The type of {@link Set} to using internally
-     * @param predicate A predicate function to test if a passed ITEM is matched by the passed SET}
+     * @param <SET> the {@link Set} type
      */
     public <SET extends Set<ITEM>> IncludeExclude(Class<SET> setClass)
     {
@@ -96,12 +101,18 @@
      * Construct an IncludeExclude
      * 
      * @param includeSet the Set of items that represent the included space 
-     * @param includePredicate the Predicate for included item testing (null for simple {@link Set#contains(Object)} test)
+     * @param includePredicate the Predicate for included item testing
      * @param excludeSet the Set of items that represent the excluded space
-     * @param excludePredicate the Predicate for excluded item testing (null for simple {@link Set#contains(Object)} test)
+     * @param excludePredicate the Predicate for excluded item testing
+     * @param <SET> the {@link Set} type
      */
     public <SET extends Set<ITEM>> IncludeExclude(Set<ITEM> includeSet, Predicate<ITEM> includePredicate, Set<ITEM> excludeSet, Predicate<ITEM> excludePredicate)
     {
+        Objects.requireNonNull(includeSet,"Include Set");
+        Objects.requireNonNull(includePredicate,"Include Predicate");
+        Objects.requireNonNull(excludeSet,"Exclude Set");
+        Objects.requireNonNull(excludePredicate,"Exclude Predicate");
+        
         _includes = includeSet;
         _includePredicate = includePredicate;
         _excludes = excludeSet;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
index 8d24dd9..b04a93d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java
@@ -19,35 +19,40 @@
 package org.eclipse.jetty.util;
 
 import java.nio.channels.ClosedChannelException;
-import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.util.thread.Locker;
 
 /**
  * This specialized callback implements a pattern that allows
  * a large job to be broken into smaller tasks using iteration
  * rather than recursion.
- * <p/>
+ * <p>
  * A typical example is the write of a large content to a socket,
  * divided in chunks. Chunk C1 is written by thread T1, which
  * also invokes the callback, which writes chunk C2, which invokes
  * the callback again, which writes chunk C3, and so forth.
- * <p/>
+ * </p>
+ * <p>
  * The problem with the example is that if the callback thread
  * is the same that performs the I/O operation, then the process
  * is recursive and may result in a stack overflow.
  * To avoid the stack overflow, a thread dispatch must be performed,
  * causing context switching and cache misses, affecting performance.
- * <p/>
+ * </p>
+ * <p>
  * To avoid this issue, this callback uses an AtomicReference to
  * record whether success callback has been called during the processing
  * of a sub task, and if so then the processing iterates rather than
  * recurring.
- * <p/>
+ * </p>
+ * <p>
  * Subclasses must implement method {@link #process()} where the sub
  * task is executed and a suitable {@link IteratingCallback.Action} is
  * returned to this callback to indicate the overall progress of the job.
  * This callback is passed to the asynchronous execution of each sub
  * task and a call the {@link #succeeded()} on this callback represents
  * the completion of the sub task.
+ * </p>
  */
 public abstract class IteratingCallback implements Callback
 {
@@ -67,37 +72,32 @@
          * and set iterating to true.
          */
         PROCESSING,
-        
+
         /**
          * Waiting for a schedule callback
          */
         PENDING,
-        
+
         /**
          * Called by a schedule callback
          */
         CALLED,
-        
+
         /**
-         * The overall job has succeeded as indicated by a {@link Action#SUCCEEDED} return 
+         * The overall job has succeeded as indicated by a {@link Action#SUCCEEDED} return
          * from {@link IteratingCallback#process()}
          */
         SUCCEEDED,
-        
+
         /**
          * The overall job has failed as indicated by a call to {@link IteratingCallback#failed(Throwable)}
          */
         FAILED,
-        
+
         /**
          * This callback has been closed and cannot be reset.
-         */ 
-        CLOSED,
-        
-        /**
-         * State is locked while leaving processing state to check the iterate boolean
          */
-        LOCKED
+        CLOSED
     }
 
     /**
@@ -118,32 +118,34 @@
          * may have not yet been invoked.
          */
         SCHEDULED,
-        
+
         /**
          * Indicates that {@link #process()} has completed the overall job.
          */
         SUCCEEDED
     }
 
-    private final AtomicReference<State> _state;
+    private Locker _locker = new Locker();
+    private State _state;
     private boolean _iterate;
-    
-    
+
+
     protected IteratingCallback()
     {
-        _state = new AtomicReference<>(State.IDLE);
+        _state = State.IDLE;
     }
-    
+
     protected IteratingCallback(boolean needReset)
     {
-        _state = new AtomicReference<>(needReset ? State.SUCCEEDED : State.IDLE);
+        _state = needReset ? State.SUCCEEDED : State.IDLE;
     }
-    
+
     /**
      * Method called by {@link #iterate()} to process the sub task.
-     * <p/>
+     * <p>
      * Implementations must start the asynchronous execution of the sub task
      * (if any) and return an appropriate action:
+     * </p>
      * <ul>
      * <li>{@link Action#IDLE} when no sub tasks are available for execution
      * but the overall job is not completed yet</li>
@@ -152,90 +154,83 @@
      * <li>{@link Action#SUCCEEDED} when the overall job is completed</li>
      * </ul>
      *
+     * @return the appropriate Action
+     *
      * @throws Exception if the sub task processing throws
      */
     protected abstract Action process() throws Exception;
 
     /**
-     * @deprecated Use {@link #onCompleteSuccess()} instead.
-     */
-    @Deprecated
-    protected void completed()
-    {
-    }
-
-    /**
      * Invoked when the overall task has completed successfully.
      *
      * @see #onCompleteFailure(Throwable)
      */
     protected void onCompleteSuccess()
     {
-        completed();
     }
-    
+
     /**
      * Invoked when the overall task has completed with a failure.
+     * @param cause the throwable to indicate cause of failure
      *
      * @see #onCompleteSuccess()
      */
-    protected void onCompleteFailure(Throwable x)
+    protected void onCompleteFailure(Throwable cause)
     {
     }
 
     /**
      * This method must be invoked by applications to start the processing
-     * of sub tasks.  It can be called at any time by any thread, and it's 
+     * of sub tasks.  It can be called at any time by any thread, and it's
      * contract is that when called, then the {@link #process()} method will
-     * be called during or soon after, either by the calling thread or by 
+     * be called during or soon after, either by the calling thread or by
      * another thread.
      */
     public void iterate()
     {
+        boolean process=false;
+
         loop: while (true)
         {
-            State state=_state.get();
-            switch (state)
+            try (Locker.Lock lock = _locker.lock())
             {
-                case PENDING:
-                case CALLED:
-                    // process will be called when callback is handled
-                    break loop;
-                    
-                case IDLE:
-                    if (!_state.compareAndSet(state,State.PROCESSING))
-                        continue;
-                    processing();
-                    break loop;
-                    
-                case PROCESSING:
-                    if (!_state.compareAndSet(state,State.LOCKED))
-                        continue;
-                    // Tell the thread that is processing that it must iterate again
-                    _iterate=true;
-                    _state.set(State.PROCESSING);
-                    break loop;
-                    
-                case LOCKED:
-                    Thread.yield();
-                    continue loop;
+                switch (_state)
+                {
+                    case PENDING:
+                    case CALLED:
+                        // process will be called when callback is handled
+                        break loop;
 
-                case FAILED:
-                case SUCCEEDED:
-                    break loop;
+                    case IDLE:
+                        _state=State.PROCESSING;
+                        process=true;
+                        break loop;
 
-                case CLOSED:
-                default:
-                    throw new IllegalStateException("state="+state);
+                    case PROCESSING:
+                        _iterate=true;
+                        break loop;
+
+                    case FAILED:
+                    case SUCCEEDED:
+                        break loop;
+
+                    case CLOSED:
+                    default:
+                        throw new IllegalStateException(toString());
+                }
             }
         }
+        if (process)
+            processing();
     }
 
-    private void processing() 
+    private void processing()
     {
         // This should only ever be called when in processing state, however a failed or close call
         // may happen concurrently, so state is not assumed.
-        
+
+        boolean on_complete_success=false;
+
         // While we are processing
         processing: while (true)
         {
@@ -251,13 +246,10 @@
                 break processing;
             }
 
-            // loop until we have successfully acted on the action we have just received
-            acting: while(true)
+            // acted on the action we have just received
+            try(Locker.Lock lock = _locker.lock())
             {
-                // action handling needs to know the state
-                State state=_state.get();
-                
-                switch (state)
+                switch (_state)
                 {
                     case PROCESSING:
                     {
@@ -265,67 +257,56 @@
                         {
                             case IDLE:
                             {
-                                // lock the state
-                                if (!_state.compareAndSet(state,State.LOCKED))
-                                    continue acting;
-
                                 // Has iterate been called while we were processing?
                                 if (_iterate)
                                 {
                                     // yes, so skip idle and keep processing
                                     _iterate=false;
-                                    _state.set(State.PROCESSING);
+                                    _state=State.PROCESSING;
                                     continue processing;
                                 }
 
                                 // No, so we can go idle
-                                _state.set(State.IDLE);
+                                _state=State.IDLE;
                                 break processing;
                             }
-                            
+
                             case SCHEDULED:
                             {
-                                if (!_state.compareAndSet(state, State.PENDING))
-                                    continue acting;
                                 // we won the race against the callback, so the callback has to process and we can break processing
+                                _state=State.PENDING;
                                 break processing;
                             }
-                            
+
                             case SUCCEEDED:
                             {
-                                if (!_state.compareAndSet(state, State.LOCKED))
-                                    continue acting;
+                                // we lost the race against the callback,
                                 _iterate=false;
-                                _state.set(State.SUCCEEDED);
-                                onCompleteSuccess();
+                                _state=State.SUCCEEDED;
+                                on_complete_success=true;
                                 break processing;
                             }
 
                             default:
-                                throw new IllegalStateException("state="+state+" action="+action); 
+                                throw new IllegalStateException(String.format("%s[action=%s]", this, action));
                         }
                     }
-                    
+
                     case CALLED:
                     {
                         switch (action)
                         {
                             case SCHEDULED:
                             {
-                                if (!_state.compareAndSet(state, State.PROCESSING))
-                                    continue acting;
                                 // we lost the race, so we have to keep processing
+                                _state=State.PROCESSING;
                                 continue processing;
                             }
 
                             default:
-                                throw new IllegalStateException("state="+state+" action="+action); 
+                                throw new IllegalStateException(String.format("%s[action=%s]", this, action));
                         }
                     }
-                        
-                    case LOCKED:
-                        Thread.yield();
-                        continue acting;
 
                     case SUCCEEDED:
                     case FAILED:
@@ -335,12 +316,15 @@
                     case IDLE:
                     case PENDING:
                     default:
-                        throw new IllegalStateException("state="+state+" action="+action); 
+                        throw new IllegalStateException(String.format("%s[action=%s]", this, action));
                 }
             }
         }
+
+        if (on_complete_success)
+            onCompleteSuccess();
     }
-    
+
     /**
      * Invoked when the sub task succeeds.
      * Subclasses that override this method must always remember to call
@@ -349,41 +333,36 @@
     @Override
     public void succeeded()
     {
-        loop: while (true)
+        boolean process=false;
+        try(Locker.Lock lock = _locker.lock())
         {
-            State state = _state.get();
-            switch (state)
+            switch (_state)
             {
                 case PROCESSING:
                 {
-                    if (!_state.compareAndSet(state, State.CALLED))
-                        continue loop;
-                    break loop;
+                    _state=State.CALLED;
+                    break;
                 }
                 case PENDING:
                 {
-                    if (!_state.compareAndSet(state, State.PROCESSING))
-                        continue loop;
-                    processing();
-                    break loop;
+                    _state=State.PROCESSING;
+                    process=true;
+                    break;
                 }
                 case CLOSED:
                 case FAILED:
                 {
                     // Too late!
-                    break loop;
+                    break;
                 }
-                case LOCKED:
-                {
-                    Thread.yield();
-                    continue loop;
-                }       
                 default:
                 {
-                    throw new IllegalStateException("state="+state);
+                    throw new IllegalStateException(toString());
                 }
             }
         }
+        if (process)
+            processing();
     }
 
     /**
@@ -394,73 +373,58 @@
     @Override
     public void failed(Throwable x)
     {
-        loop: while (true)
+        boolean failure=false;
+        try(Locker.Lock lock = _locker.lock())
         {
-            State state = _state.get();
-            switch (state)
+            switch (_state)
             {
                 case SUCCEEDED:
                 case FAILED:
                 case IDLE:
                 case CLOSED:
                 case CALLED:
-                {
                     // too late!.
-                    break loop;
-                }
-                case LOCKED:
-                {
-                    Thread.yield();
-                    continue loop;
-                }  
-                case PENDING: 
-                case PROCESSING: 
-                {
-                    if (!_state.compareAndSet(state, State.FAILED))
-                        continue loop;
+                    break;
 
-                    onCompleteFailure(x);
-                    break loop;
+                case PENDING:
+                case PROCESSING:
+                {
+                    _state=State.FAILED;
+                    failure=true;
+                    break;
                 }
                 default:
-                    throw new IllegalStateException("state="+state);
+                    throw new IllegalStateException(toString());
             }
         }
+        if (failure)
+            onCompleteFailure(x);
     }
 
     public void close()
     {
-        loop: while (true)
+        boolean failure=false;
+        try(Locker.Lock lock = _locker.lock())
         {
-            State state = _state.get();
-            switch (state)
+            switch (_state)
             {
                 case IDLE:
                 case SUCCEEDED:
                 case FAILED:
-                {
-                    if (!_state.compareAndSet(state, State.CLOSED))
-                        continue loop;
-                    break loop;
-                }
+                    _state=State.CLOSED;
+                    break;
+
                 case CLOSED:
-                {
-                    break loop;
-                }
-                case LOCKED:
-                {
-                    Thread.yield();
-                    continue loop;
-                }    
+                    break;
+
                 default:
-                {
-                    if (!_state.compareAndSet(state, State.CLOSED))
-                        continue loop;
-                    onCompleteFailure(new ClosedChannelException());
-                    break loop;
-                }
+                    _state=State.CLOSED;
+                    failure=true;
             }
         }
+
+        if(failure)
+            onCompleteFailure(new ClosedChannelException());
     }
 
     /*
@@ -469,20 +433,29 @@
      */
     boolean isIdle()
     {
-        return _state.get() == State.IDLE;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _state == State.IDLE;
+        }
     }
 
     public boolean isClosed()
     {
-        return _state.get() == State.CLOSED;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _state == State.CLOSED;
+        }
     }
-    
+
     /**
      * @return whether this callback has failed
      */
     public boolean isFailed()
     {
-        return _state.get() == State.FAILED;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _state == State.FAILED;
+        }
     }
 
     /**
@@ -490,51 +463,42 @@
      */
     public boolean isSucceeded()
     {
-        return _state.get() == State.SUCCEEDED;
+        try(Locker.Lock lock = _locker.lock())
+        {
+            return _state == State.SUCCEEDED;
+        }
     }
 
     /**
      * Resets this callback.
-     * <p/>
+     * <p>
      * A callback can only be reset to IDLE from the
      * SUCCEEDED or FAILED states or if it is already IDLE.
+     * </p>
      *
      * @return true if the reset was successful
      */
     public boolean reset()
     {
-        while (true)
+        try(Locker.Lock lock = _locker.lock())
         {
-            State state=_state.get();
-            switch(state)
+            switch(_state)
             {
                 case IDLE:
                     return true;
-                    
+
                 case SUCCEEDED:
-                    if (!_state.compareAndSet(state, State.LOCKED))
-                        continue;
-                    _iterate=false;
-                    _state.set(State.IDLE);
-                    return true;
-                    
                 case FAILED:
-                    if (!_state.compareAndSet(state, State.LOCKED))
-                        continue;
                     _iterate=false;
-                    _state.set(State.IDLE);
+                    _state=State.IDLE;
                     return true;
 
-                case LOCKED:
-                    Thread.yield();
-                    continue;
-                    
                 default:
                     return false;
             }
         }
     }
-    
+
     @Override
     public String toString()
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
index 1cf154c..64a792e 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingNestedCallback.java
@@ -46,6 +46,12 @@
     {
         _callback=callback;
     }
+
+    @Override
+    public boolean isNonBlocking()
+    { 
+        return _callback.isNonBlocking();
+    }
     
     @Override
     protected void onCompleteSuccess()
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java
index 864c6af..39f1857 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Jetty.java
@@ -21,6 +21,7 @@
 public class Jetty
 {
     public static final String VERSION;
+    public static final String POWERED_BY;
 
     static
     {
@@ -30,10 +31,13 @@
                 pkg.getImplementationVersion() != null)
             VERSION = pkg.getImplementationVersion();
         else
-            VERSION = System.getProperty("jetty.version", "9.2.z-SNAPSHOT");
+            VERSION = System.getProperty("jetty.version", "9.3.z-SNAPSHOT");
+        
+        POWERED_BY="<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// "+VERSION+"</a>";
     }
 
     private Jetty()
     {
     }
+    
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java b/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java
index 3b259c7..43c6523 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/LazyList.java
@@ -27,21 +27,23 @@
 import java.util.List;
 import java.util.ListIterator;
 
-/* ------------------------------------------------------------ */
-/** Lazy List creation.
+/** 
+ * Lazy List creation.
+ * <p>
  * A List helper class that attempts to avoid unnecessary List
  * creation.   If a method needs to create a List to return, but it is
  * expected that this will either be empty or frequently contain a
  * single item, then using LazyList will avoid additional object
  * creations by using {@link Collections#EMPTY_LIST} or
  * {@link Collections#singletonList(Object)} where possible.
+ * </p>
  * <p>
  * LazyList works by passing an opaque representation of the list in
  * and out of all the LazyList methods.  This opaque object is either
  * null for an empty list, an Object for a list with a single entry
  * or an {@link ArrayList} for a list of items.
- *
- * <p><h4>Usage</h4>
+ * </p>
+ * <strong>Usage</strong>
  * <pre>
  *   Object lazylist =null;
  *   while(loopCondition)
@@ -162,7 +164,9 @@
 
     /* ------------------------------------------------------------ */
     /** Ensure the capacity of the underlying list.
-     * 
+     * @param list the list to grow 
+     * @param initialSize the size to grow to
+     * @return the new List with new size
      */
     public static Object ensureSize(Object list, int initialSize)
     {
@@ -230,6 +234,7 @@
      * @param list A LazyList returned from LazyList.add(Object)
      * @return The List of added items, which may be an EMPTY_LIST
      * or a SingletonList.
+     * @param <E> the list entry type
      */
     public static<E> List<E> getList(Object list)
     {
@@ -245,6 +250,7 @@
      * empty list.
      * @return The List of added items, which may be null, an EMPTY_LIST
      * or a SingletonList.
+     * @param <E> the list entry type
      */
     @SuppressWarnings("unchecked")
     public static<E> List<E> getList(Object list, boolean nullForEmpty)
@@ -365,6 +371,7 @@
      * @param list  A LazyList returned from LazyList.add(Object) or null
      * @param i int index
      * @return the item from the list.
+     * @param <E> the list entry type
      */
     @SuppressWarnings("unchecked")
     public static <E> E get(Object list, int i)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Loader.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Loader.java
index c045070..dc47989 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Loader.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Loader.java
@@ -69,10 +69,10 @@
     /* ------------------------------------------------------------ */
     /** Load a class.
      * 
-     * @param loadClass
-     * @param name
+     * @param loadClass a similar class, belong in the same classloader of the desired class to load
+     * @param name the name of the new class to load, using the same ClassLoader as the <code>loadClass</code> 
      * @return Class
-     * @throws ClassNotFoundException
+     * @throws ClassNotFoundException if not able to find the class
      */
     @SuppressWarnings("rawtypes")
     public static Class loadClass(Class loadClass,String name)
@@ -153,7 +153,9 @@
      * above the given classloader.
      * 
      * This is primarily used for jasper.
+     * @param loader the classloader to use
      * @return the system class path
+     * @throws Exception if unable to generate the classpath from the resource references
      */
     public static String getClassPath(ClassLoader loader) throws Exception
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MemoryUtils.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MemoryUtils.java
index 514af03..c77ccc1 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MemoryUtils.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MemoryUtils.java
@@ -22,8 +22,7 @@
 import java.security.PrivilegedAction;
 
 /**
- * {@link MemoryUtils} provides an abstraction over memory properties and operations.
- * <p />
+ * MemoryUtils provides an abstraction over memory properties and operations.
  */
 public class MemoryUtils
 {
@@ -67,5 +66,4 @@
     {
         return getCacheLineBytes() >> 3;
     }
-
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
index 7653ca6..a58b00f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiException.java
@@ -86,7 +86,7 @@
      * If this multi exception is empty then no action is taken. If it
      * contains a single exception that is thrown, otherwise the this
      * multi exception is thrown. 
-     * @exception Exception 
+     * @exception Exception the Error or Exception if nested is 1, or the MultiException itself if nested is more than 1.
      */
     public void ifExceptionThrow()
         throws Exception
@@ -146,6 +146,7 @@
      * If this multi exception is empty then no action is taken. If it
      * contains a any exceptions then this
      * multi exception is thrown. 
+     * @throws MultiException the multiexception if there are nested exception
      */
     public void ifExceptionThrowMulti()
         throws MultiException
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java
index 1a057c6..c341df5 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java
@@ -28,6 +28,7 @@
 
 /** 
  * A multi valued Map.
+ * @param <V> the entry type for multimap values
  */
 @SuppressWarnings("serial")
 public class MultiMap<V> extends HashMap<String,List<V>>
@@ -283,7 +284,7 @@
      * Test for a specific single value in the map.
      * <p>
      * NOTE: This is a SLOW operation, and is actively discouraged.
-     * @param value
+     * @param value the value to search for
      * @return true if contains simple value
      */
     public boolean containsSimpleValue(V value)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
index 4fbc2a7..946d708 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
@@ -30,6 +30,9 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -37,7 +40,6 @@
 import java.util.Locale;
 
 import javax.servlet.MultipartConfigElement;
-import javax.servlet.ServletException;
 import javax.servlet.http.Part;
 
 import org.eclipse.jetty.util.log.Log;
@@ -125,7 +127,7 @@
 
             if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null)
                 createFile();
-           
+
             _out.write(bytes, offset, length);
             _size += length;
         }
@@ -134,7 +136,7 @@
         throws IOException
         {
             _file = File.createTempFile("MultiPart", "", MultiPartInputStreamParser.this._tmpDir);
-            
+
             if (_deleteOnExit)
                 _file.deleteOnExit();
             FileOutputStream fos = new FileOutputStream(_file);
@@ -173,7 +175,7 @@
         {
             if (name == null)
                 return null;
-            return (String)_headers.getValue(name.toLowerCase(Locale.ENGLISH), 0);
+            return _headers.getValue(name.toLowerCase(Locale.ENGLISH), 0);
         }
 
         /**
@@ -209,8 +211,8 @@
            }
         }
 
-        
-        /** 
+
+        /**
          * @see javax.servlet.http.Part#getSubmittedFileName()
          */
         @Override
@@ -239,7 +241,7 @@
          */
         public long getSize()
         {
-            return _size;         
+            return _size;
         }
 
         /**
@@ -250,7 +252,7 @@
             if (_file == null)
             {
                 _temporary = false;
-                
+
                 //part data is only in the ByteArrayOutputStream and never been written to disk
                 _file = new File (_tmpDir, fileName);
 
@@ -272,10 +274,11 @@
             {
                 //the part data is already written to a temporary file, just rename it
                 _temporary = false;
-                
-                File f = new File(_tmpDir, fileName);
-                if (_file.renameTo(f))
-                    _file = f;
+
+                Path src = _file.toPath();
+                Path target = src.resolveSibling(fileName);
+                Files.move(src, target, StandardCopyOption.REPLACE_EXISTING);
+                _file = target.toFile();
             }
         }
 
@@ -287,13 +290,13 @@
         public void delete() throws IOException
         {
             if (_file != null && _file.exists())
-                _file.delete();     
+                _file.delete();
         }
-        
+
         /**
          * Only remove tmp files.
-         * 
-         * @throws IOException
+         *
+         * @throws IOException if unable to delete the file
          */
         public void cleanUp() throws IOException
         {
@@ -303,7 +306,8 @@
 
 
         /**
-         * Get the file, if any, the data has been written to.
+         * Get the file
+         * @return the file, if any, the data has been written to.
          */
         public File getFile ()
         {
@@ -338,13 +342,14 @@
        _contextTmpDir = contextTmpDir;
        if (_contextTmpDir == null)
            _contextTmpDir = new File (System.getProperty("java.io.tmpdir"));
-       
+
        if (_config == null)
            _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath());
     }
 
     /**
      * Get the already parsed parts.
+     * @return the parts that were parsed
      */
     public Collection<Part> getParsedParts()
     {
@@ -352,7 +357,7 @@
             return Collections.emptyList();
 
         Collection<List<Part>> values = _parts.values();
-        List<Part> parts = new ArrayList<Part>();
+        List<Part> parts = new ArrayList<>();
         for (List<Part> o: values)
         {
             List<Part> asList = LazyList.getList(o, false);
@@ -363,8 +368,8 @@
 
     /**
      * Delete any tmp storage for parts, and clear out the parts list.
-     * 
-     * @throws MultiException
+     *
+     * @throws MultiException if unable to delete the parts
      */
     public void deleteParts ()
     throws MultiException
@@ -376,30 +381,30 @@
             try
             {
                 ((MultiPartInputStreamParser.MultiPart)p).cleanUp();
-            } 
+            }
             catch(Exception e)
-            {     
-                err.add(e); 
+            {
+                err.add(e);
             }
         }
         _parts.clear();
-        
+
         err.ifExceptionThrowMulti();
     }
 
-   
+
     /**
      * Parse, if necessary, the multipart data and return the list of Parts.
-     * 
-     * @throws IOException
-     * @throws ServletException
+     *
+     * @return the parts
+     * @throws IOException if unable to get the parts
      */
     public Collection<Part> getParts()
-    throws IOException, ServletException
+    throws IOException
     {
         parse();
         Collection<List<Part>> values = _parts.values();
-        List<Part> parts = new ArrayList<Part>();
+        List<Part> parts = new ArrayList<>();
         for (List<Part> o: values)
         {
             List<Part> asList = LazyList.getList(o, false);
@@ -411,27 +416,26 @@
 
     /**
      * Get the named Part.
-     * 
-     * @param name
-     * @throws IOException
-     * @throws ServletException
+     *
+     * @param name the part name
+     * @return the parts
+     * @throws IOException if unable to get the part
      */
     public Part getPart(String name)
-    throws IOException, ServletException
+    throws IOException
     {
         parse();
-        return (Part)_parts.getValue(name, 0);
+        return _parts.getValue(name, 0);
     }
 
 
     /**
      * Parse, if necessary, the multipart stream.
-     * 
-     * @throws IOException
-     * @throws ServletException
+     *
+     * @throws IOException if unable to parse
      */
     protected void parse ()
-    throws IOException, ServletException
+    throws IOException
     {
         //have we already parsed the input?
         if (_parts != null)
@@ -439,7 +443,7 @@
 
         //initialize
         long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize
-        _parts = new MultiMap<Part>();
+        _parts = new MultiMap<>();
 
         //if its not a multipart request, don't parse it
         if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
@@ -471,28 +475,29 @@
             bend = (bend < 0? _contentType.length(): bend);
             contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart,bend)).trim());
         }
-        
+
         String boundary="--"+contentTypeBoundary;
-        byte[] byteBoundary=(boundary+"--").getBytes(StandardCharsets.ISO_8859_1);
+        String lastBoundary=boundary+"--";
+        byte[] byteBoundary=lastBoundary.getBytes(StandardCharsets.ISO_8859_1);
 
         // Get first boundary
         String line = null;
         try
         {
-            line=((ReadLineInputStream)_in).readLine();  
+            line=((ReadLineInputStream)_in).readLine();
         }
         catch (IOException e)
         {
             LOG.warn("Badly formatted multipart request");
             throw e;
         }
-        
+
         if (line == null)
             throw new IOException("Missing content for multipart request");
-        
+
         boolean badFormatLogged = false;
         line=line.trim();
-        while (line != null && !line.equals(boundary))
+        while (line != null && !line.equals(boundary) && !line.equals(lastBoundary))
         {
             if (!badFormatLogged)
             {
@@ -506,6 +511,10 @@
         if (line == null)
             throw new IOException("Missing initial multi part boundary");
 
+        // Empty multipart.
+        if (line.equals(lastBoundary))
+            return;
+
         // Read each part
         boolean lastPart=false;
 
@@ -514,20 +523,20 @@
             String contentDisposition=null;
             String contentType=null;
             String contentTransferEncoding=null;
-            
-            MultiMap<String> headers = new MultiMap<String>();
+
+            MultiMap<String> headers = new MultiMap<>();
             while(true)
             {
                 line=((ReadLineInputStream)_in).readLine();
-                
+
                 //No more input
                 if(line==null)
                     break outer;
-                
+
                 //end of headers:
                 if("".equals(line))
                     break;
-           
+
                 total += line.length();
                 if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
                     throw new IllegalStateException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
@@ -591,7 +600,7 @@
             part.setContentType(contentType);
             _parts.add(name, part);
             part.open();
-            
+
             InputStream partInput = null;
             if ("base64".equalsIgnoreCase(contentTransferEncoding))
             {
@@ -623,7 +632,7 @@
             else
                 partInput = _in;
 
-            
+
             try
             {
                 int state=-2;
@@ -642,7 +651,7 @@
                             throw new IllegalStateException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")");
 
                         state=-2;
-                        
+
                         // look for CR and/or LF
                         if(c==13||c==10)
                         {
@@ -657,7 +666,7 @@
                             }
                             break;
                         }
-                        
+
                         // Look for boundary
                         if(b>=0&&b<byteBoundary.length&&c==byteBoundary[b])
                         {
@@ -681,7 +690,7 @@
                             part.write(c);
                         }
                     }
-                    
+
                     // Check for incomplete boundary match, writing out the chars we matched along the way
                     if((b>0&&b<byteBoundary.length-2)||(b==byteBoundary.length-1))
                     {
@@ -695,18 +704,18 @@
                         part.write(byteBoundary,0,b);
                         b=-1;
                     }
-                    
+
                     // Boundary match. If we've run out of input or we matched the entire final boundary marker, then this is the last part.
                     if(b>0||c==-1)
                     {
-                       
+
                         if(b==byteBoundary.length)
                             lastPart=true;
                         if(state==10)
                             state=-2;
                         break;
                     }
-                    
+
                     // handle CR LF
                     if(cr)
                         part.write(13);
@@ -729,7 +738,7 @@
         if (!lastPart)
             throw new IOException("Incomplete parts");
     }
-    
+
     public void setDeleteOnExit(boolean deleteOnExit)
     {
         _deleteOnExit = deleteOnExit;
@@ -749,8 +758,8 @@
         String value = nameEqualsValue.substring(idx+1).trim();
         return QuotedStringTokenizer.unquoteOnly(value);
     }
-    
-    
+
+
     /* ------------------------------------------------------------ */
     private String filenameValue(String nameEqualsValue)
     {
@@ -778,7 +787,7 @@
             return QuotedStringTokenizer.unquoteOnly(value, true);
     }
 
-    
+
 
     private static class Base64InputStream extends InputStream
     {
@@ -787,7 +796,7 @@
         byte[] _buffer;
         int _pos;
 
-    
+
         public Base64InputStream(ReadLineInputStream rlis)
         {
             _in = rlis;
@@ -802,7 +811,7 @@
                 //We need to put them back into the bytes returned from this
                 //method because the parsing of the multipart content uses them
                 //as markers to determine when we've reached the end of a part.
-                _line = _in.readLine(); 
+                _line = _in.readLine();
                 if (_line==null)
                     return -1;  //nothing left
                 if (_line.startsWith("--"))
@@ -820,7 +829,7 @@
 
                 _pos=0;
             }
-            
+
             return _buffer[_pos++];
         }
     }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartOutputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartOutputStream.java
index c39ae59..49af8ff 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartOutputStream.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartOutputStream.java
@@ -24,7 +24,6 @@
 import java.nio.charset.StandardCharsets;
 
 
-/* ================================================================ */
 /** Handle a multipart MIME response.
  *
  * 
@@ -100,6 +99,8 @@
     
     /* ------------------------------------------------------------ */
     /** Start creation of the next Content.
+     * @param contentType the content type of the part
+     * @throws IOException if unable to write the part
      */
     public void startPart(String contentType)
          throws IOException
@@ -118,6 +119,9 @@
         
     /* ------------------------------------------------------------ */
     /** Start creation of the next Content.
+     * @param contentType the content type of the part
+     * @param headers the part headers
+     * @throws IOException if unable to write the part
      */
     public void startPart(String contentType, String[] headers)
          throws IOException
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartWriter.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartWriter.java
index 78f8ed9..eb94df7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartWriter.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartWriter.java
@@ -87,6 +87,8 @@
     
     /* ------------------------------------------------------------ */
     /** Start creation of the next Content.
+     * @param contentType the content type
+     * @throws IOException if unable to write the part
      */
     public void startPart(String contentType)
          throws IOException
@@ -105,6 +107,7 @@
     
     /* ------------------------------------------------------------ */
     /** end creation of the next Content.
+     * @throws IOException if unable to write the part
      */
     public void endPart()
          throws IOException
@@ -116,6 +119,9 @@
         
     /* ------------------------------------------------------------ */
     /** Start creation of the next Content.
+     * @param contentType the content type of the part
+     * @param headers the part headers
+     * @throws IOException if unable to write the part
      */
     public void startPart(String contentType, String[] headers)
          throws IOException
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java
new file mode 100644
index 0000000..1bc2762
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PathWatcher.java
@@ -0,0 +1,1454 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import static java.nio.file.StandardWatchEventKinds.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Watch a Path (and sub directories) for Path changes.
+ * <p>
+ * Suitable replacement for the old {@link Scanner} implementation.
+ * <p>
+ * Allows for configured Excludes and Includes using {@link FileSystem#getPathMatcher(String)} syntax.
+ * <p>
+ * Reports activity via registered {@link Listener}s
+ */
+public class PathWatcher extends AbstractLifeCycle implements Runnable
+{
+    public static class Config
+    {
+        public static final int UNLIMITED_DEPTH = -9999;
+        
+        private static final String PATTERN_SEP;
+
+        static
+        {
+            String sep = File.separator;
+            if (File.separatorChar == '\\')
+            {
+                sep = "\\\\";
+            }
+            PATTERN_SEP = sep;
+        }
+
+        protected final Path dir;
+        protected int recurseDepth = 0; // 0 means no sub-directories are scanned
+        protected List<PathMatcher> includes;
+        protected List<PathMatcher> excludes;
+        protected boolean excludeHidden = false;
+
+        public Config(Path path)
+        {
+            this.dir = path;
+            includes = new ArrayList<>();
+            excludes = new ArrayList<>();
+        }
+
+        /**
+         * Add an exclude PathMatcher
+         *
+         * @param matcher
+         *            the path matcher for this exclude
+         */
+        public void addExclude(PathMatcher matcher)
+        {
+            this.excludes.add(matcher);
+        }
+
+        /**
+         * Add an exclude PathMatcher.
+         * <p>
+         * Note: this pattern is FileSystem specific (so use "/" for Linux and OSX, and "\\" for Windows)
+         *
+         * @param syntaxAndPattern
+         *            the PathMatcher syntax and pattern to use
+         * @see FileSystem#getPathMatcher(String) for detail on syntax and pattern
+         */
+        public void addExclude(final String syntaxAndPattern)
+        {
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Adding exclude: [{}]",syntaxAndPattern);
+            }
+            addExclude(dir.getFileSystem().getPathMatcher(syntaxAndPattern));
+        }
+
+        /**
+         * Add a <code>glob:</code> syntax pattern exclude reference in a directory relative, os neutral, pattern.
+         *
+         * <pre>
+         *    On Linux:
+         *    Config config = new Config(Path("/home/user/example"));
+         *    config.addExcludeGlobRelative("*.war") =&gt; "glob:/home/user/example/*.war"
+         * 
+         *    On Windows
+         *    Config config = new Config(Path("D:/code/examples"));
+         *    config.addExcludeGlobRelative("*.war") =&gt; "glob:D:\\code\\examples\\*.war"
+         *
+         * </pre>
+         *
+         * @param pattern
+         *            the pattern, in unixy format, relative to config.dir
+         */
+        public void addExcludeGlobRelative(String pattern)
+        {
+            addExclude(toGlobPattern(dir,pattern));
+        }
+
+        /**
+         * Exclude hidden files and hidden directories
+         */
+        public void addExcludeHidden()
+        {
+            if (!excludeHidden)
+            {
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("Adding hidden files and directories to exclusions");
+                }
+                excludeHidden = true;
+
+                addExclude("regex:^.*" + PATTERN_SEP + "\\..*$"); // ignore hidden files
+                addExclude("regex:^.*" + PATTERN_SEP + "\\..*" + PATTERN_SEP + ".*$"); // ignore files in hidden directories
+            }
+        }
+
+        /**
+         * Add multiple exclude PathMatchers
+         *
+         * @param syntaxAndPatterns
+         *            the list of PathMatcher syntax and patterns to use
+         * @see FileSystem#getPathMatcher(String) for detail on syntax and pattern
+         */
+        public void addExcludes(List<String> syntaxAndPatterns)
+        {
+            for (String syntaxAndPattern : syntaxAndPatterns)
+            {
+                addExclude(syntaxAndPattern);
+            }
+        }
+
+        /**
+         * Add an include PathMatcher
+         *
+         * @param matcher
+         *            the path matcher for this include
+         */
+        public void addInclude(PathMatcher matcher)
+        {
+            this.includes.add(matcher);
+        }
+
+        /**
+         * Add an include PathMatcher
+         *
+         * @param syntaxAndPattern
+         *            the PathMatcher syntax and pattern to use
+         * @see FileSystem#getPathMatcher(String) for detail on syntax and pattern
+         */
+        public void addInclude(String syntaxAndPattern)
+        {
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Adding include: [{}]",syntaxAndPattern);
+            }
+            addInclude(dir.getFileSystem().getPathMatcher(syntaxAndPattern));
+        }
+
+        /**
+         * Add a <code>glob:</code> syntax pattern reference in a directory relative, os neutral, pattern.
+         *
+         * <pre>
+         *    On Linux:
+         *    Config config = new Config(Path("/home/user/example"));
+         *    config.addIncludeGlobRelative("*.war") =&gt; "glob:/home/user/example/*.war"
+         * 
+         *    On Windows
+         *    Config config = new Config(Path("D:/code/examples"));
+         *    config.addIncludeGlobRelative("*.war") =&gt; "glob:D:\\code\\examples\\*.war"
+         *
+         * </pre>
+         *
+         * @param pattern
+         *            the pattern, in unixy format, relative to config.dir
+         */
+        public void addIncludeGlobRelative(String pattern)
+        {
+            addInclude(toGlobPattern(dir,pattern));
+        }
+
+        /**
+         * Add multiple include PathMatchers
+         *
+         * @param syntaxAndPatterns
+         *            the list of PathMatcher syntax and patterns to use
+         * @see FileSystem#getPathMatcher(String) for detail on syntax and pattern
+         */
+        public void addIncludes(List<String> syntaxAndPatterns)
+        {
+            for (String syntaxAndPattern : syntaxAndPatterns)
+            {
+                addInclude(syntaxAndPattern);
+            }
+        }
+
+        /**
+         * Build a new config from a this configuration.
+         * <p>
+         * Useful for working with sub-directories that also need to be watched.
+         *
+         * @param dir
+         *            the directory to build new Config from (using this config as source of includes/excludes)
+         * @return the new Config
+         */
+        public Config asSubConfig(Path dir)
+        {
+            Config subconfig = new Config(dir);
+            subconfig.includes = this.includes;
+            subconfig.excludes = this.excludes;
+            if (dir == this.dir)
+                subconfig.recurseDepth = this.recurseDepth; // TODO shouldn't really do a subconfig for this
+            else
+            {
+                if (this.recurseDepth == UNLIMITED_DEPTH)
+                    subconfig.recurseDepth = UNLIMITED_DEPTH;
+                else
+                    subconfig.recurseDepth = this.recurseDepth - (dir.getNameCount() - this.dir.getNameCount());                
+            }
+            return subconfig;
+        }
+
+        public int getRecurseDepth()
+        {
+            return recurseDepth;
+        }
+        
+        public boolean isRecurseDepthUnlimited ()
+        {
+            return this.recurseDepth == UNLIMITED_DEPTH;
+        }
+        
+        public Path getPath ()
+        {
+            return this.dir;
+        }
+
+        private boolean hasMatch(Path path, List<PathMatcher> matchers)
+        {
+            for (PathMatcher matcher : matchers)
+            {
+                if (matcher.matches(path))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean isExcluded(Path dir) throws IOException
+        {
+            if (excludeHidden)
+            {
+                if (Files.isHidden(dir))
+                {
+                    if (NOISY_LOG.isDebugEnabled())
+                    {
+                        NOISY_LOG.debug("isExcluded [Hidden] on {}",dir);
+                    }
+                    return true;
+                }
+            }
+
+            if (excludes.isEmpty())
+            {
+                // no excludes == everything allowed
+                return false;
+            }
+
+            boolean matched = hasMatch(dir,excludes);
+            if (NOISY_LOG.isDebugEnabled())
+            {
+                NOISY_LOG.debug("isExcluded [{}] on {}",matched,dir);
+            }
+            return matched;
+        }
+
+        public boolean isIncluded(Path dir)
+        {
+            if (includes.isEmpty())
+            {
+                // no includes == everything allowed
+                if (NOISY_LOG.isDebugEnabled())
+                {
+                    NOISY_LOG.debug("isIncluded [All] on {}",dir);
+                }
+                return true;
+            }
+
+            boolean matched = hasMatch(dir,includes);
+            if (NOISY_LOG.isDebugEnabled())
+            {
+                NOISY_LOG.debug("isIncluded [{}] on {}",matched,dir);
+            }
+            return matched;
+        }
+
+        public boolean matches(Path path)
+        {
+            try
+            {
+                return !isExcluded(path) && isIncluded(path);
+            }
+            catch (IOException e)
+            {
+                LOG.warn("Unable to match path: " + path,e);
+                return false;
+            }
+        }
+
+        /**
+         * Set the recurse depth for the directory scanning.
+         * <p>
+         * -999 indicates arbitrarily deep recursion, 0 indicates no recursion, 1 is only one directory deep, and so on.
+         *
+         * @param depth
+         *            the number of directories deep to recurse
+         */
+        public void setRecurseDepth(int depth)
+        {
+            this.recurseDepth = depth;
+        }
+        
+   
+
+        /**
+         * Determine if the provided child directory should be recursed into based on the configured {@link #setRecurseDepth(int)}
+         *
+         * @param child
+         *            the child directory to test against
+         * @return true if recurse should occur, false otherwise
+         */
+        public boolean shouldRecurseDirectory(Path child)
+        {
+            if (!child.startsWith(dir))
+            {
+                // not part of parent? don't recurse
+                return false;
+            }
+
+            //If not limiting depth, should recurse all
+            if (isRecurseDepthUnlimited())
+                return true;
+            
+            //Depth limited, check it
+            int childDepth = dir.relativize(child).getNameCount();
+            return (childDepth <= recurseDepth);
+        }
+
+        private String toGlobPattern(Path path, String subPattern)
+        {
+            StringBuilder s = new StringBuilder();
+            s.append("glob:");
+
+            boolean needDelim = false;
+
+            // Add root (aka "C:\" for Windows)
+            Path root = path.getRoot();
+            if (root != null)
+            {
+                if (NOISY_LOG.isDebugEnabled())
+                {
+                    NOISY_LOG.debug("Path: {} -> Root: {}",path,root);
+                }
+                for (char c : root.toString().toCharArray())
+                {
+                    if (c == '\\')
+                    {
+                        s.append(PATTERN_SEP);
+                    }
+                    else
+                    {
+                        s.append(c);
+                    }
+                }
+            }
+            else
+            {
+                needDelim = true;
+            }
+
+            // Add the individual path segments
+            for (Path segment : path)
+            {
+                if (needDelim)
+                {
+                    s.append(PATTERN_SEP);
+                }
+                s.append(segment);
+                needDelim = true;
+            }
+
+            // Add the sub pattern (if specified)
+            if ((subPattern != null) && (subPattern.length() > 0))
+            {
+                if (needDelim)
+                {
+                    s.append(PATTERN_SEP);
+                }
+                for (char c : subPattern.toCharArray())
+                {
+                    if (c == '/')
+                    {
+                        s.append(PATTERN_SEP);
+                    }
+                    else
+                    {
+                        s.append(c);
+                    }
+                }
+            }
+
+            return s.toString();
+        }
+
+        @Override
+        public String toString()
+        {
+            StringBuilder s = new StringBuilder();
+            s.append(dir);
+            if (recurseDepth > 0)
+            {
+                s.append(" [depth=").append(recurseDepth).append("]");
+            }
+            return s.toString();
+        }
+    }
+    
+    public static class DepthLimitedFileVisitor extends SimpleFileVisitor<Path>
+    {
+        private Config base;
+        private PathWatcher watcher;
+        
+        public DepthLimitedFileVisitor (PathWatcher watcher, Config base)
+        {
+            this.base = base;
+            this.watcher = watcher;
+        }
+
+        /*
+         * 2 situations:
+         * 
+         * 1. a subtree exists at the time a dir to watch is added (eg watching /tmp/xxx and it contains aaa/)
+         *  - will start with /tmp/xxx for which we want to register with the poller
+         *  - want to visit each child
+         *     - if child is file, gen add event
+         *     - if child is dir, gen add event but ONLY register it if inside depth limit and ONLY continue visit of child if inside depth limit
+         * 2. a subtree is added inside a watched dir (eg watching /tmp/xxx, add aaa/ to xxx/)
+         *  - will start with /tmp/xxx/aaa 
+         *    - gen add event but ONLY register it if inside depth limit and ONLY continue visit of children if inside depth limit
+         *    
+         */
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
+        {
+            //In a directory:
+            // 1. the dir is the base directory
+            //   - register it with the poll mechanism
+            //   - generate pending add event (iff notifiable and matches patterns)
+            //   - continue the visit (sibling dirs, sibling files)
+            // 2. the dir is a subdir at some depth in the basedir's tree
+            //   - if the level of the subdir less or equal to base's limit
+            //     - register it wih the poll mechanism
+            //     - generate pending add event (iff notifiable and matches patterns)
+            //   - else stop visiting this dir
+
+            if (!base.isExcluded(dir))
+            {
+                if (base.isIncluded(dir))
+                {
+                    if (watcher.isNotifiable())
+                    {
+                        // Directory is specifically included in PathMatcher, then
+                        // it should be notified as such to interested listeners
+                        PathWatchEvent event = new PathWatchEvent(dir,PathWatchEventType.ADDED);
+                        if (LOG.isDebugEnabled())
+                        {
+                            LOG.debug("Pending {}",event);
+                        }
+                        watcher.addToPendingList(dir, event);
+                    }
+                }
+
+                //Register the dir with the watcher if it is:
+                // - the base dir and recursion is unlimited
+                // - the base dir and its depth is 0 (meaning we want to capture events from it, but not necessarily its children)
+                // - the base dir and we are recursing it and the depth is within the limit
+                // - a child dir and its depth is within the limits
+                if ((base.getPath().equals(dir) && (base.isRecurseDepthUnlimited() || base.getRecurseDepth() >= 0)) || base.shouldRecurseDirectory(dir))
+                    watcher.register(dir,base);
+            }
+
+            //Continue walking the tree of this dir if it is:
+            // - the base dir and recursion is unlimited
+            // - the base dir and we're not recursing in it
+            // - the base dir and we are recursing it and the depth is within the limit
+            // - a child dir and its depth is within the limits
+            if ((base.getPath().equals(dir)&& (base.isRecurseDepthUnlimited() || base.getRecurseDepth() >= 0)) || base.shouldRecurseDirectory(dir))
+                return FileVisitResult.CONTINUE;
+            else 
+                return FileVisitResult.SKIP_SUBTREE;   
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
+        {
+            // In a file:
+            //    - register with poll mechanism
+            //    - generate pending add event (iff notifiable and matches patterns)
+            
+            if (base.matches(file) && watcher.isNotifiable())
+            {
+                PathWatchEvent event = new PathWatchEvent(file,PathWatchEventType.ADDED);
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("Pending {}",event);
+                }
+                watcher.addToPendingList(file, event);
+            }
+
+            return FileVisitResult.CONTINUE;
+        }
+        
+    }
+
+    /**
+     * Listener for path change events
+     */
+    public static interface Listener extends EventListener
+    {
+        void onPathWatchEvent(PathWatchEvent event);
+    }
+    
+    /**
+     * EventListListener
+     *
+     * Listener that reports accumulated events in one shot
+     */
+    public static interface EventListListener extends EventListener
+    {
+        void onPathWatchEvents(List<PathWatchEvent> events);
+    }
+
+    /**
+     * PathWatchEvent
+     *
+     * Represents a file event. Reported to registered listeners.
+     */
+    public static class PathWatchEvent
+    {
+        private final Path path;
+        private final PathWatchEventType type;
+        private int count = 0;
+     
+        public PathWatchEvent(Path path, PathWatchEventType type)
+        {
+            this.path = path;
+            this.count = 1;
+            this.type = type;
+
+        }
+
+        public PathWatchEvent(Path path, WatchEvent<Path> event)
+        {
+            this.path = path;
+            this.count = event.count();
+            if (event.kind() == ENTRY_CREATE)
+            {
+                this.type = PathWatchEventType.ADDED;
+            }
+            else if (event.kind() == ENTRY_DELETE)
+            {
+                this.type = PathWatchEventType.DELETED;
+            }
+            else if (event.kind() == ENTRY_MODIFY)
+            {
+                this.type = PathWatchEventType.MODIFIED;
+            }
+            else
+            {
+                this.type = PathWatchEventType.UNKNOWN;
+            }
+        }
+
+        /** 
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            if (obj == null)
+            {
+                return false;
+            }
+            if (getClass() != obj.getClass())
+            {
+                return false;
+            }
+            PathWatchEvent other = (PathWatchEvent)obj;
+            if (path == null)
+            {
+                if (other.path != null)
+                {
+                    return false;
+                }
+            }
+            else if (!path.equals(other.path))
+            {
+                return false;
+            }
+            if (type != other.type)
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public Path getPath()
+        {
+            return path;
+        }
+
+        public PathWatchEventType getType()
+        {
+            return type;
+        }
+        
+        public void incrementCount(int num)
+        {
+            count += num;
+        }
+
+        public int getCount()
+        {
+            return count;
+        }
+        
+        /** 
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode()
+        {
+            final int prime = 31;
+            int result = 1;
+            result = (prime * result) + ((path == null)?0:path.hashCode());
+            result = (prime * result) + ((type == null)?0:type.hashCode());
+            return result;
+        }
+
+        /** 
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString()
+        {
+            return String.format("PathWatchEvent[%s|%s]",type,path);
+        }
+    }
+    
+    
+    
+    /**
+     * PathPendingEvents
+     *
+     * For a given path, a list of events that are awaiting the
+     * quiet time. The list is in the order that the event were
+     * received from the WatchService
+     */
+    public static class PathPendingEvents
+    {
+        private Path _path;
+        private List<PathWatchEvent> _events;
+        private long _timestamp;
+        private long _lastFileSize = -1;
+
+        public PathPendingEvents (Path path)
+        {
+            _path = path;
+        }
+        
+        public PathPendingEvents (Path path, PathWatchEvent event)
+        {
+            this (path);
+            addEvent(event);
+        }
+        
+        public void addEvent (PathWatchEvent event)
+        {
+            long now = System.currentTimeMillis();
+            _timestamp = now;
+
+            if (_events == null)
+            {
+                _events = new ArrayList<PathWatchEvent>();
+                _events.add(event);
+            }
+            else
+            {
+                //Check if the same type of event is already present, in which case we
+                //can increment its counter. Otherwise, add it
+                PathWatchEvent existingType = null;
+                for (PathWatchEvent e:_events)
+                {
+                    if (e.getType() == event.getType())
+                    {
+                        existingType = e;
+                        break;
+                    }
+                }
+
+                if (existingType == null)
+                {
+                    _events.add(event);
+                }
+                else
+                {
+                    existingType.incrementCount(event.getCount());
+                }
+            }
+
+        }
+        
+        public List<PathWatchEvent> getEvents()
+        {
+            return _events;
+        }
+
+        public long getTimestamp()
+        {
+            return _timestamp;
+        }
+   
+        
+        /**
+         * Check to see if the file referenced by this Event is quiet.
+         * <p>
+         * Will validate the timestamp to see if it is expired, as well as if the file size hasn't changed within the quiet period.
+         * <p>
+         * Always updates timestamp to 'now' on use of this method.
+         * 
+         * @param now the time now 
+         *
+         * @param expiredDuration
+         *            the expired duration past the timestamp to be considered expired
+         * @param expiredUnit
+         *            the unit of time for the expired check
+         * @return true if expired, false if not
+         */
+        public boolean isQuiet(long now, long expiredDuration, TimeUnit expiredUnit)
+        {
+
+            long pastdue = _timestamp + expiredUnit.toMillis(expiredDuration);
+            _timestamp = now;
+
+            long fileSize = _path.toFile().length(); // File.length() returns 0 for non existant files
+            boolean fileSizeChanged = (_lastFileSize != fileSize);
+            _lastFileSize = fileSize;
+
+            if ((now > pastdue) && (!fileSizeChanged /*|| fileSize == 0*/))
+            {
+                // Quiet period timestamp has expired, and file size hasn't changed, or the file
+                // has been deleted.
+                // Consider this a quiet event now.
+                return true;
+            }
+
+            return false;
+        }
+
+    }
+
+    /**
+     * PathWatchEventType
+     *
+     * Type of an event
+     */
+    public static enum PathWatchEventType
+    {
+        ADDED, DELETED, MODIFIED, UNKNOWN;
+    }
+
+    private static final boolean IS_WINDOWS;
+
+    static
+    {
+        String os = System.getProperty("os.name");
+        if (os == null)
+        {
+            IS_WINDOWS = false;
+        }
+        else
+        {
+            String osl = os.toLowerCase(Locale.ENGLISH);
+            IS_WINDOWS = osl.contains("windows");
+        }
+    }
+
+    private static final Logger LOG = Log.getLogger(PathWatcher.class);
+    /**
+     * super noisy debug logging
+     */
+    private static final Logger NOISY_LOG = Log.getLogger(PathWatcher.class.getName() + ".Noisy");
+
+    @SuppressWarnings("unchecked")
+    protected static <T> WatchEvent<T> cast(WatchEvent<?> event)
+    {
+        return (WatchEvent<T>)event;
+    }
+
+    private static final WatchEvent.Kind<?> WATCH_EVENT_KINDS[] = { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY };
+    
+    private  WatchService watchService;
+    private  WatchEvent.Modifier watchModifiers[];
+    private  boolean nativeWatchService;
+    
+    private Map<WatchKey, Config> keys = new HashMap<>();
+    private List<EventListener> listeners = new CopyOnWriteArrayList<>(); //a listener may modify the listener list directly or by stopping the PathWatcher
+    private List<Config> configs = new ArrayList<>();
+
+    /**
+     * Update Quiet Time - set to 1000 ms as default (a lower value in Windows is not supported)
+     */
+    private long updateQuietTimeDuration = 1000;
+    private TimeUnit updateQuietTimeUnit = TimeUnit.MILLISECONDS;
+    private Thread thread;
+    private boolean _notifyExistingOnStart = true;
+    private Map<Path, PathPendingEvents> pendingEvents = new LinkedHashMap<>();
+    
+    
+    
+    /**
+     * Construct new PathWatcher
+     */
+    public PathWatcher()
+    {
+    }
+    
+    /**
+     * Request watch on a the given path (either file or dir)
+     * using all Config defaults. In the case of a dir,
+     * the default is not to recurse into subdirs for watching.
+     * 
+     * @param file the path to watch
+     */
+    public void watch (final Path file)
+    {
+        //Make a config for the dir above it and
+        //include a match only for the given path
+        //using all defaults for the configuration
+        Path abs = file;
+        if (!abs.isAbsolute())
+        {
+            abs = file.toAbsolutePath();
+        }
+        
+        //Check we don't already have a config for the parent directory. 
+        //If we do, add in this filename.
+        Config config = null;
+        Path parent = abs.getParent();
+        for (Config c:configs)
+        {
+            if (c.getPath().equals(parent))
+            {
+                config = c;
+                break;
+            }
+        }
+        
+        //Make a new config
+        if (config == null)
+        {
+            config = new Config(abs.getParent());
+            // the include for the directory itself
+            config.addIncludeGlobRelative("");
+            //add the include for the file
+            config.addIncludeGlobRelative(file.getFileName().toString());
+            watch(config);
+        }
+        else
+            //add the include for the file
+            config.addIncludeGlobRelative(file.getFileName().toString());
+    }
+    
+    /**
+     * Request watch on a path with custom Config 
+     * provided.
+     * 
+     * @param config the configuration to watch
+     */
+    public void watch (final Config config)
+    {
+        //Add a custom config
+        configs.add(config);
+    }
+    
+    /**
+     * Register path in the config with the file watch service,
+     * walking the tree if it happens to be a directory.
+     * 
+     * @param baseDir the base directory configuration to watch
+     * @throws IOException if unable to walk the filesystem tree
+     */
+    protected void prepareConfig (final Config baseDir) throws IOException
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Watching directory {}",baseDir);
+        }
+        Files.walkFileTree(baseDir.getPath(), new DepthLimitedFileVisitor(this, baseDir));
+    }
+
+    
+    
+    /**
+     * Add a listener for changes the watcher notices.
+     * 
+     * @param listener change listener
+     */
+    public void addListener(EventListener listener)
+    {
+        listeners.add(listener);
+    }
+
+    /**
+     * Append some info on the paths that we are watching.
+     * 
+     * @param s
+     */
+    private void appendConfigId(StringBuilder s)
+    {
+        List<Path> dirs = new ArrayList<>();
+
+        for (Config config : keys.values())
+        {
+            dirs.add(config.dir);
+        }
+
+        Collections.sort(dirs);
+
+        s.append("[");
+        if (dirs.size() > 0)
+        {
+            s.append(dirs.get(0));
+            if (dirs.size() > 1)
+            {
+                s.append(" (+").append(dirs.size() - 1).append(")");
+            }
+        }
+        else
+        {
+            s.append("<null>");
+        }
+        s.append("]");
+    }
+
+    /** 
+     * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
+     */
+    @Override
+    protected void doStart() throws Exception
+    {
+        //create a new watchservice
+        createWatchService();
+        
+        //ensure setting of quiet time is appropriate now we have a watcher
+        setUpdateQuietTime(getUpdateQuietTimeMillis(), TimeUnit.MILLISECONDS);
+
+        // Register all watched paths, walking dir hierarchies as needed, possibly generating
+        // fake add events if notifyExistingOnStart is true
+        for (Config c:configs)
+            prepareConfig(c);
+        
+        // Start Thread for watcher take/pollKeys loop
+        StringBuilder threadId = new StringBuilder();
+        threadId.append("PathWatcher-Thread");
+        appendConfigId(threadId);
+
+        thread = new Thread(this,threadId.toString());
+        thread.setDaemon(true);
+        thread.start();
+        super.doStart();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
+     */
+    @Override
+    protected void doStop() throws Exception
+    {
+        if (watchService != null)
+            watchService.close(); //will invalidate registered watch keys, interrupt thread in take or poll
+        watchService = null;
+        thread = null;
+        keys.clear();
+        pendingEvents.clear();
+        super.doStop();
+    }
+    
+    
+    /**
+     * Remove all current configs and listeners.
+     */
+    public void reset ()
+    {
+        if (!isStopped())
+            throw new IllegalStateException("PathWatcher must be stopped before reset.");
+        
+        configs.clear();
+        listeners.clear();
+    }
+    
+    
+    /**
+     * Create a fresh WatchService and determine if it is a 
+     * native implementation or not.
+     * 
+     * @throws IOException
+     */
+    private void createWatchService () throws IOException
+    {
+        //create a watch service
+        this.watchService = FileSystems.getDefault().newWatchService();
+
+        WatchEvent.Modifier modifiers[] = null;
+        boolean nativeService = true;
+        // Try to determine native behavior
+        // See http://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-else
+        try
+        {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            Class<?> pollingWatchServiceClass = Class.forName("sun.nio.fs.PollingWatchService",false,cl);
+            if (pollingWatchServiceClass.isAssignableFrom(this.watchService.getClass()))
+            {
+                nativeService = false;
+                LOG.info("Using Non-Native Java {}",pollingWatchServiceClass.getName());
+                Class<?> c = Class.forName("com.sun.nio.file.SensitivityWatchEventModifier");
+                Field f = c.getField("HIGH");
+                modifiers = new WatchEvent.Modifier[]
+                        {
+                         (WatchEvent.Modifier)f.get(c)
+                        };
+            }
+        }
+        catch (Throwable t)
+        {
+            // Unknown JVM environment, assuming native.
+            LOG.ignore(t);
+        }
+
+        this.watchModifiers = modifiers;
+        this.nativeWatchService = nativeService;
+    }
+    
+    /**
+     * Check to see if the watcher is in a state where it should generate
+     * watch events to the listeners. Used to determine if watcher should generate
+     * events for existing files and dirs on startup.
+     * 
+     * @return true if the watcher should generate events to the listeners.
+     */
+    protected boolean isNotifiable ()
+    {
+        return (isStarted() || (!isStarted() && isNotifyExistingOnStart()));
+    }
+
+    /**
+     * Get an iterator over the listeners.
+     * 
+     * @return iterator over the listeners.
+     */
+    public Iterator<EventListener> getListeners()
+    {
+        return listeners.iterator();
+    }
+
+    /**
+     * Change the quiet time.
+     * 
+     * @return the quiet time in millis
+     */
+    public long getUpdateQuietTimeMillis()
+    {
+        return TimeUnit.MILLISECONDS.convert(updateQuietTimeDuration,updateQuietTimeUnit);
+    }
+
+    /**
+     * Generate events to the listeners.
+     * 
+     * @param events the events captured
+     */
+    protected void notifyOnPathWatchEvents (List<PathWatchEvent> events)
+    {
+        if (events == null || events.isEmpty())
+            return;
+
+        for (EventListener listener : listeners)
+        {
+            if (listener instanceof EventListListener)
+            {
+                try
+                {
+                    ((EventListListener)listener).onPathWatchEvents(events);
+                }
+                catch (Throwable t)
+                {
+                    LOG.warn(t);
+                }
+            }
+            else
+            {
+                Listener l = (Listener)listener;
+                for (PathWatchEvent event:events)
+                {
+                    try
+                    {
+                        l.onPathWatchEvent(event);
+                    }
+                    catch (Throwable t)
+                    {
+                        LOG.warn(t);
+                    }
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Register a path (directory) with the WatchService.
+     * 
+     * @param dir the directory to register
+     * @param root the configuration root
+     * @throws IOException if unable to register the path with the watch service.
+     */
+    protected void register(Path dir, Config root) throws IOException
+    {
+       
+        LOG.debug("Registering watch on {}",dir);
+        if(watchModifiers != null) 
+        {
+            // Java Watcher
+            WatchKey key = dir.register(watchService,WATCH_EVENT_KINDS,watchModifiers);
+            keys.put(key,root.asSubConfig(dir));
+        } else 
+        {
+            // Native Watcher
+            WatchKey key = dir.register(watchService,WATCH_EVENT_KINDS);
+            keys.put(key,root.asSubConfig(dir));
+        }
+    }
+
+    
+    /**
+     * Delete a listener
+     * @param listener the listener to remove
+     * @return true if the listener existed and was removed
+     */
+    public boolean removeListener(Listener listener)
+    {
+        return listeners.remove(listener);
+    }
+
+    
+    /** 
+     * Forever loop.
+     * 
+     * Wait for the WatchService to report some filesystem events for the
+     * watched paths.
+     * 
+     * When an event for a path first occurs, it is subjected to a quiet time.
+     * Subsequent events that arrive for the same path during this quiet time are
+     * accumulated and the timer reset. Only when the quiet time has expired are
+     * the accumulated events sent. MODIFY events are handled slightly differently -
+     * multiple MODIFY events arriving within a quiet time are coalesced into a
+     * single MODIFY event. Both the accumulation of events and coalescing of MODIFY
+     * events reduce the number and frequency of event reporting for "noisy" files (ie
+     * those that are undergoing rapid change).
+     * 
+     * @see java.lang.Runnable#run()
+     */
+    @Override
+    public void run()
+    {
+
+        List<PathWatchEvent> notifiableEvents = new ArrayList<PathWatchEvent>();
+        
+        // Start the java.nio watching
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Starting java.nio file watching with {}",watchService);
+        }
+
+        while (watchService != null)
+        {
+            WatchKey key = null;
+
+            try
+            {     
+                //If no pending events, wait forever for new events
+                if (pendingEvents.isEmpty())
+                {
+                    if (NOISY_LOG.isDebugEnabled())
+                        NOISY_LOG.debug("Waiting for take()");
+                    key = watchService.take();
+                }
+                else
+                {
+                    //There are existing events that might be ready to go,
+                    //only wait as long as the quiet time for any new events
+                    if (NOISY_LOG.isDebugEnabled())
+                        NOISY_LOG.debug("Waiting for poll({}, {})",updateQuietTimeDuration,updateQuietTimeUnit);
+
+                    key = watchService.poll(updateQuietTimeDuration,updateQuietTimeUnit);
+                   
+                    //If no new events its safe to process the pendings
+                    if (key == null)
+                    {
+                        long now = System.currentTimeMillis();
+                        // no new event encountered.
+                        for (Path path : new HashSet<Path>(pendingEvents.keySet()))
+                        {
+                            PathPendingEvents pending = pendingEvents.get(path);
+                            if (pending.isQuiet(now, updateQuietTimeDuration,updateQuietTimeUnit))
+                            {
+                                //No fresh events received during quiet time for this path, 
+                                //so generate the events that were pent up
+                                for (PathWatchEvent p:pending.getEvents())
+                                {
+                                    notifiableEvents.add(p);
+                                }
+                                // remove from pending list
+                                pendingEvents.remove(path);
+                            }
+                        }
+                    }
+                }
+            }
+            catch (ClosedWatchServiceException e)
+            {
+                // Normal shutdown of watcher
+                return;
+            }
+            catch (InterruptedException e)
+            {
+                if (isRunning())
+                {
+                    LOG.warn(e);
+                }
+                else
+                {
+                    LOG.ignore(e);
+                }
+                return;
+            }
+
+            //If there was some new events to process
+            if (key != null)
+            {
+
+                Config config = keys.get(key);
+                if (config == null)
+                {
+                    if (LOG.isDebugEnabled())
+                    {
+                        LOG.debug("WatchKey not recognized: {}",key);
+                    }
+                    continue;
+                }
+
+                for (WatchEvent<?> event : key.pollEvents())
+                {
+                    @SuppressWarnings("unchecked")
+                    WatchEvent.Kind<Path> kind = (Kind<Path>)event.kind();
+                    WatchEvent<Path> ev = cast(event);
+                    Path name = ev.context();
+                    Path child = config.dir.resolve(name);
+
+                    if (kind == ENTRY_CREATE)
+                    {
+                        // handle special case for registering new directories
+                        // recursively
+                        if (Files.isDirectory(child,LinkOption.NOFOLLOW_LINKS))
+                        {
+                            try
+                            {
+                                prepareConfig(config.asSubConfig(child));
+                            }
+                            catch (IOException e)
+                            {
+                                LOG.warn(e);
+                            }
+                        }
+                        else if (config.matches(child))
+                        {
+                            addToPendingList(child, new PathWatchEvent(child,ev));
+                        }
+                    }
+                    else if (config.matches(child))
+                    {
+                        addToPendingList(child, new PathWatchEvent(child,ev));      
+                    }
+                }
+            }
+
+            //Send any notifications generated this pass
+            notifyOnPathWatchEvents(notifiableEvents);
+            notifiableEvents.clear();
+            
+            if (key != null && !key.reset())
+            {
+                keys.remove(key);
+                if (keys.isEmpty())
+                {
+                    return; // all done, no longer monitoring anything
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Add an event reported by the WatchService to list of pending events
+     * that will be sent after their quiet time has expired.
+     * 
+     * @param path the path to add to the pending list
+     * @param event the pending event
+     */
+    public void addToPendingList (Path path, PathWatchEvent event)
+    {
+        PathPendingEvents pending = pendingEvents.get(path);
+        
+        //Are there already pending events for this path?
+        if (pending == null)
+        {
+            //No existing pending events, create pending list
+            pendingEvents.put(path,new PathPendingEvents(path, event));
+        }
+        else
+        {
+            //There are already some events pending for this path
+            pending.addEvent(event);
+        }
+    }
+    
+    
+    /**
+     * Whether or not to issue notifications for directories and files that
+     * already exist when the watcher starts.
+     * 
+     * @param notify true if existing paths should be notified or not
+     */
+    public void setNotifyExistingOnStart (boolean notify)
+    {
+        _notifyExistingOnStart = notify;
+    }
+    
+    public boolean isNotifyExistingOnStart ()
+    {
+        return _notifyExistingOnStart;
+    }
+
+    /**
+     * Set the quiet time.
+     * 
+     * @param duration the quiet time duration
+     * @param unit the quite time unit
+     */
+    public void setUpdateQuietTime(long duration, TimeUnit unit)
+    {
+        long desiredMillis = unit.toMillis(duration);
+        
+        if (watchService != null && !this.nativeWatchService && (desiredMillis < 5000))
+        {
+            LOG.warn("Quiet Time is too low for non-native WatchService [{}]: {} < 5000 ms (defaulting to 5000 ms)",watchService.getClass().getName(),desiredMillis);
+            this.updateQuietTimeDuration = 5000;
+            this.updateQuietTimeUnit = TimeUnit.MILLISECONDS;
+            return;
+        }
+
+        if (IS_WINDOWS && (desiredMillis < 1000))
+        {
+            LOG.warn("Quiet Time is too low for Microsoft Windows: {} < 1000 ms (defaulting to 1000 ms)",desiredMillis);
+            this.updateQuietTimeDuration = 1000;
+            this.updateQuietTimeUnit = TimeUnit.MILLISECONDS;
+            return;
+        }
+        
+        // All other OS and watch service combinations can use desired setting
+        this.updateQuietTimeDuration = duration;
+        this.updateQuietTimeUnit = unit;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder s = new StringBuilder(this.getClass().getName());
+        appendConfigId(s);
+        return s.toString();
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java
index dd314c0..9ef985b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java
@@ -53,7 +53,7 @@
      * @param pattern the pattern
      * @param uris the uris to test the pattern against
      * @param isNullInclusive if true, an empty pattern means all names match, if false, none match
-     * @throws Exception
+     * @throws Exception if fundamental error in pattern matching
      */
     public void match (Pattern pattern, URI[] uris, boolean isNullInclusive)
     throws Exception
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Predicate.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Predicate.java
deleted file mode 100644
index 9d26fa0..0000000
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Predicate.java
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util;
-
-/**
- * Temporary implementation of Java 8's <code>java.util.function.Predicate</code>
- * <p>
- * To be removed for Java 8 only versions of Jetty.
- * 
- * @param <ITEM> the item to test
- */
-public interface Predicate<ITEM>
-{
-    boolean test(ITEM item);
-}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java
index 3ea1d8d..97dfd43 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/QuotedStringTokenizer.java
@@ -472,6 +472,7 @@
     /* ------------------------------------------------------------ */
     /** Unquote a string.
      * @param s The string to unquote.
+     * @param lenient true if unquoting should be lenient to escaped content, leaving some alone, false if string unescaping
      * @return quoted string
      */
     public static String unquote(String s, boolean lenient)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java b/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java
index 7aacf9e..5c980b9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java
@@ -23,6 +23,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.function.Predicate;
 import java.util.regex.Pattern;
 
 /**
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/RolloverFileOutputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/RolloverFileOutputStream.java
index f154f9f..e866e62 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/RolloverFileOutputStream.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/RolloverFileOutputStream.java
@@ -40,8 +40,6 @@
  * actual date when creating and rolling over the file.
  * 
  * Old files are retained for a number of days before being deleted.
- * 
- * 
  */
 public class RolloverFileOutputStream extends FilterOutputStream
 {
@@ -65,7 +63,7 @@
     /**
      * @param filename The filename must include the string "yyyy_mm_dd", 
      * which is replaced with the actual date when creating and rolling over the file.
-     * @throws IOException
+     * @throws IOException if unable to create output
      */
     public RolloverFileOutputStream(String filename)
         throws IOException
@@ -78,7 +76,7 @@
      * @param filename The filename must include the string "yyyy_mm_dd", 
      * which is replaced with the actual date when creating and rolling over the file.
      * @param append If true, existing files will be appended to.
-     * @throws IOException
+     * @throws IOException if unable to create output
      */
     public RolloverFileOutputStream(String filename, boolean append)
         throws IOException
@@ -92,7 +90,7 @@
      * which is replaced with the actual date when creating and rolling over the file.
      * @param append If true, existing files will be appended to.
      * @param retainDays The number of days to retain files before deleting them.  0 to retain forever.
-     * @throws IOException
+     * @throws IOException if unable to create output
      */
     public RolloverFileOutputStream(String filename,
                                     boolean append,
@@ -108,7 +106,8 @@
      * which is replaced with the actual date when creating and rolling over the file.
      * @param append If true, existing files will be appended to.
      * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
-     * @throws IOException
+     * @param zone the timezone for the output
+     * @throws IOException if unable to create output
      */
     public RolloverFileOutputStream(String filename,
                                     boolean append,
@@ -126,9 +125,10 @@
      * which is replaced with the actual date when creating and rolling over the file.
      * @param append If true, existing files will be appended to.
      * @param retainDays The number of days to retain files before deleting them. 0 to retain forever.
+     * @param zone the timezone for the output
      * @param dateFormat The format for the date file substitution. The default is "yyyy_MM_dd". 
      * @param backupFormat The format for the file extension of backup files. The default is "HHmmssSSS". 
-     * @throws IOException
+     * @throws IOException if unable to create output
      */
     public RolloverFileOutputStream(String filename,
                                     boolean append,
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
index 2aba5b3..5b08baa 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
@@ -221,7 +221,7 @@
     /**
      * Apply a filter to files found in the scan directory.
      * Only files matching the filter will be reported as added/changed/removed.
-     * @param filter
+     * @param filter the filename filter to use
      */
     public void setFilenameFilter (FilenameFilter filter)
     {
@@ -257,7 +257,7 @@
     
     /* ------------------------------------------------------------ */
     /** Set if found directories should be reported.
-     * @param dirs
+     * @param dirs true to report directory changes as well
      */
     public void setReportDirs(boolean dirs)
     {
@@ -273,7 +273,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Add an added/removed/changed listener
-     * @param listener
+     * @param listener the listener to add
      */
     public synchronized void addListener (Listener listener)
     {
@@ -370,6 +370,7 @@
     }
 
     /**
+     * @param path tests if the path exists
      * @return true if the path exists in one of the scandirs
      */
     public boolean exists(String path)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
index 5b4e5a3..adfc547 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java
@@ -29,32 +29,26 @@
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.thread.NonBlockingThread;
 
-
-/* ------------------------------------------------------------ */
-/** Provides a reusable BlockingCallback.
+/**
+ * Provides a reusable {@link Callback} that can block the thread
+ * while waiting to be completed.
+ * <p>
  * A typical usage pattern is:
  * <pre>
  * void someBlockingCall(Object... args) throws IOException
  * {
- *   try(Blocker blocker=sharedBlockingCallback.acquire())
- *   {
- *     someAsyncCall(args,blocker);
- *     blocker.block();
- *   }
+ *     try(Blocker blocker = sharedBlockingCallback.acquire())
+ *     {
+ *         someAsyncCall(args, blocker);
+ *         blocker.block();
+ *     }
  * }
  * </pre>
  */
 public class SharedBlockingCallback
 {
     static final Logger LOG = Log.getLogger(SharedBlockingCallback.class);
-
-    final ReentrantLock _lock = new ReentrantLock();
-    final Condition _idle = _lock.newCondition();
-    final Condition _complete = _lock.newCondition();
-
-    
     private static Throwable IDLE = new Throwable()
     {
         @Override
@@ -63,7 +57,6 @@
             return "IDLE";
         }
     };
-
     private static Throwable SUCCEEDED = new Throwable()
     {
         @Override
@@ -72,7 +65,6 @@
             return "SUCCEEDED";
         }
     };
-    
     private static Throwable FAILED = new Throwable()
     {
         @Override
@@ -82,12 +74,10 @@
         }
     };
 
-    Blocker _blocker;
-    
-    public SharedBlockingCallback()
-    {
-        _blocker=new Blocker();
-    }
+    private final ReentrantLock _lock = new ReentrantLock();
+    private final Condition _idle = _lock.newCondition();
+    private final Condition _complete = _lock.newCondition();
+    private Blocker _blocker = new Blocker();
     
     protected long getIdleTimeout()
     {
@@ -131,18 +121,21 @@
             LOG.debug(new Throwable());
     }
     
-    /* ------------------------------------------------------------ */
-    /** A Closeable Callback.
+    /**
+     * A Closeable Callback.
      * Uses the auto close mechanism to check block has been called OK.
+     * <p>Implements {@link Callback.NonBlocking} because calls to this
+     * callback do not blocak, rather they wakeup the thread that is blocked
+     * in {@link #block()}
      */
-    public class Blocker implements Callback, Closeable
+    public class Blocker implements Callback.NonBlocking, Closeable
     {
-        Throwable _state = IDLE;
+        private Throwable _state = IDLE;
         
         protected Blocker()
         {
         }
-
+        
         @Override
         public void succeeded()
         {
@@ -198,9 +191,6 @@
          */
         public void block() throws IOException
         {
-            if (NonBlockingThread.isNonBlockingThread())
-                LOG.warn("Blocking a NonBlockingThread: ",new Throwable());
-            
             _lock.lock();
             long idle = getIdleTimeout();
             try
@@ -216,7 +206,9 @@
                             _state=new BlockerTimeoutException();
                     }
                     else
+                    {
                         _complete.await();
+                    }
                 }
 
                 if (_state == SUCCEEDED)
@@ -245,12 +237,9 @@
         
         /**
          * Check the Callback has succeeded or failed and after the return leave in the state to allow reuse.
-         * 
-         * @throws IOException
-         *             if exception was caught during blocking, or callback was cancelled
          */
         @Override
-        public void close() throws IOException
+        public void close()
         {
             _lock.lock();
             try
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
index f6eff3f..fe7eead 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SocketAddressResolver.java
@@ -18,14 +18,19 @@
 
 package org.eclipse.jetty.util;
 
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import java.nio.channels.UnresolvedAddressException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.Scheduler;
@@ -38,26 +43,31 @@
     /**
      * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
      * with the default timeout.
-     *
-     * @param host the host to resolve
+     *  @param host the host to resolve
      * @param port the port of the resulting socket address
      * @param promise the callback invoked when the resolution succeeds or fails
      */
-    public void resolve(String host, int port, Promise<SocketAddress> promise);
+    public void resolve(String host, int port, Promise<List<InetSocketAddress>> promise);
 
     /**
      * <p>Creates {@link SocketAddress} instances synchronously in the caller thread.</p>
      */
+    @ManagedObject("The synchronous address resolver")
     public static class Sync implements SocketAddressResolver
     {
         @Override
-        public void resolve(String host, int port, Promise<SocketAddress> promise)
+        public void resolve(String host, int port, Promise<List<InetSocketAddress>> promise)
         {
             try
             {
-                InetSocketAddress result = new InetSocketAddress(host, port);
-                if (result.isUnresolved())
-                    promise.failed(new UnresolvedAddressException());
+                InetAddress[] addresses = InetAddress.getAllByName(host);
+
+                List<InetSocketAddress> result = new ArrayList<>(addresses.length);
+                for (InetAddress address : addresses)
+                    result.add(new InetSocketAddress(address, port));
+
+                if (result.isEmpty())
+                    promise.failed(new UnknownHostException());
                 else
                     promise.succeeded(result);
             }
@@ -91,6 +101,7 @@
      * });
      * </pre>
      */
+    @ManagedObject("The asynchronous address resolver")
     public static class Async implements SocketAddressResolver
     {
         private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
@@ -124,65 +135,61 @@
             return scheduler;
         }
 
+        @ManagedAttribute(value = "The timeout, in milliseconds, to resolve an address", readonly = true)
         public long getTimeout()
         {
             return timeout;
         }
 
         @Override
-        public void resolve(final String host, final int port, final Promise<SocketAddress> promise)
+        public void resolve(final String host, final int port, final Promise<List<InetSocketAddress>> promise)
         {
-            executor.execute(new Runnable()
+            executor.execute(() ->
             {
-                @Override
-                public void run()
+                Scheduler.Task task = null;
+                final AtomicBoolean complete = new AtomicBoolean();
+                if (timeout > 0)
                 {
-                    Scheduler.Task task = null;
-                    final AtomicBoolean complete = new AtomicBoolean();
-                    if (timeout > 0)
+                    final Thread thread = Thread.currentThread();
+                    task = scheduler.schedule(() ->
                     {
-                        final Thread thread = Thread.currentThread();
-                        task = scheduler.schedule(new Runnable()
-                        {
-                            @Override
-                            public void run()
-                            {
-                                if (complete.compareAndSet(false, true))
-                                {
-                                    promise.failed(new TimeoutException());
-                                    thread.interrupt();
-                                }
-                            }
-                        }, timeout, TimeUnit.MILLISECONDS);
-                    }
-
-                    try
-                    {
-                        long start = System.nanoTime();
-                        InetSocketAddress result = new InetSocketAddress(host, port);
-                        long elapsed = System.nanoTime() - start;
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
                         if (complete.compareAndSet(false, true))
                         {
-                            if (result.isUnresolved())
-                                promise.failed(new UnresolvedAddressException());
-                            else
-                                promise.succeeded(result);
+                            promise.failed(new TimeoutException());
+                            thread.interrupt();
                         }
-                    }
-                    catch (Throwable x)
+                    }, timeout, TimeUnit.MILLISECONDS);
+                }
+
+                try
+                {
+                    long start = System.nanoTime();
+                    InetAddress[] addresses = InetAddress.getAllByName(host);
+                    long elapsed = System.nanoTime() - start;
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
+
+                    List<InetSocketAddress> result = new ArrayList<>(addresses.length);
+                    for (InetAddress address : addresses)
+                        result.add(new InetSocketAddress(address, port));
+
+                    if (complete.compareAndSet(false, true))
                     {
-                        if (complete.compareAndSet(false, true))
-                            promise.failed(x);
+                        if (result.isEmpty())
+                            promise.failed(new UnknownHostException());
+                        else
+                            promise.succeeded(result);
                     }
-                    finally
-                    {
-                        if (task != null)
-                            task.cancel();
-                        // Reset the interrupted status before releasing the thread to the pool
-                        Thread.interrupted();
-                    }
+                }
+                catch (Throwable x)
+                {
+                    if (complete.compareAndSet(false, true))
+                        promise.failed(x);
+                }
+                finally
+                {
+                    if (task != null)
+                        task.cancel();
                 }
             });
         }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index c1b1d43..204a26d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.util;
 
 import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
@@ -50,44 +49,25 @@
     @Deprecated
     public static final String __LINE_SEPARATOR = System.lineSeparator();
        
-    public static final String __ISO_8859_1="ISO-8859-1";
-    public final static String __UTF8="UTF-8";
-    public final static String __UTF16="UTF-16";
-
-    /**
-     * @deprecated Use {@link StandardCharsets#UTF_8}
-     */
-    @Deprecated
-    public final static Charset __UTF8_CHARSET=StandardCharsets.UTF_8;
-    /**
-     * @deprecated Use {@link StandardCharsets#ISO_8859_1}
-     */
-    @Deprecated
-    public final static Charset __ISO_8859_1_CHARSET=StandardCharsets.ISO_8859_1;
-    /**
-     * @deprecated Use {@link StandardCharsets#UTF_16}
-     */
-    @Deprecated
-    public final static Charset __UTF16_CHARSET=StandardCharsets.UTF_16;
-    /**
-     * @deprecated Use {@link StandardCharsets#US_ASCII}
-     */
-    @Deprecated
-    public final static Charset __US_ASCII_CHARSET=StandardCharsets.US_ASCII;
+    public static final String __ISO_8859_1="iso-8859-1";
+    public final static String __UTF8="utf-8";
+    public final static String __UTF16="utf-16";
     
     static
     {
-        CHARSETS.put("UTF-8",__UTF8);
-        CHARSETS.put("UTF8",__UTF8);
-        CHARSETS.put("UTF-16",__UTF16);
-        CHARSETS.put("UTF16",__UTF16);
-        CHARSETS.put("ISO-8859-1",__ISO_8859_1);
-        CHARSETS.put("ISO_8859_1",__ISO_8859_1);
+        CHARSETS.put("utf-8",__UTF8);
+        CHARSETS.put("utf8",__UTF8);
+        CHARSETS.put("utf-16",__UTF16);
+        CHARSETS.put("utf16",__UTF16);
+        CHARSETS.put("iso-8859-1",__ISO_8859_1);
+        CHARSETS.put("iso_8859_1",__ISO_8859_1);
     }
     
     /* ------------------------------------------------------------ */
     /** Convert alternate charset names (eg utf8) to normalized
      * name (eg UTF-8).
+     * @param s the charset to normalize
+     * @return the normalized charset (or null if normalized version not found)
      */
     public static String normalizeCharset(String s)
     {
@@ -98,6 +78,10 @@
     /* ------------------------------------------------------------ */
     /** Convert alternate charset names (eg utf8) to normalized
      * name (eg UTF-8).
+     * @param s the charset to normalize
+     * @param offset the offset in the charset
+     * @param length the length of the charset in the input param
+     * @return the normalized charset (or null if not found)
      */
     public static String normalizeCharset(String s,int offset,int length)
     {
@@ -223,6 +207,9 @@
     /* ------------------------------------------------------------ */
     /**
      * returns the next index of a character from the chars string
+     * @param s the input string to search
+     * @param chars the chars to look for
+     * @return the index of the character in the input stream found.
      */
     public static int indexFrom(String s,String chars)
     {
@@ -235,6 +222,10 @@
     /* ------------------------------------------------------------ */
     /**
      * replace substrings within string.
+     * @param s the input string
+     * @param sub the string to look for
+     * @param with the string to replace with
+     * @return the now replaced string
      */
     public static String replace(String s, String sub, String with)
     {
@@ -262,6 +253,8 @@
 
     /* ------------------------------------------------------------ */
     /** Remove single or double quotes.
+     * @param s the input string
+     * @return the string with quotes removed
      */
     public static String unquote(String s)
     {
@@ -297,6 +290,9 @@
     /* ------------------------------------------------------------ */
     /**
      * append hex digit
+     * @param buf the buffer to append to
+     * @param b the byte to append
+     * @param base the base of the hex output (almost always 16).
      * 
      */
     public static void append(StringBuilder buf,byte b,int base)
@@ -313,6 +309,12 @@
     }
 
     /* ------------------------------------------------------------ */
+    /**
+     * Append 2 digits (zero padded) to the StringBuffer
+     * 
+     * @param buf the buffer to append to
+     * @param i the value to append
+     */
     public static void append2digits(StringBuffer buf,int i)
     {
         if (i<100)
@@ -323,6 +325,12 @@
     }
     
     /* ------------------------------------------------------------ */
+    /**
+     * Append 2 digits (zero padded) to the StringBuilder
+     * 
+     * @param buf the buffer to append to
+     * @param i the value to append
+     */
     public static void append2digits(StringBuilder buf,int i)
     {
         if (i<100)
@@ -525,6 +533,8 @@
      * http://en.wikipedia.org/wiki/Security_Identifier
      * 
      * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
+     * @param sidBytes the SID bytes to build from
+     * @return the string SID
      */
     public static String sidBytesToString(byte[] sidBytes)
     {
@@ -572,6 +582,8 @@
      * http://en.wikipedia.org/wiki/Security_Identifier
      * 
      * S-1-IdentifierAuthority-SubAuthority1-SubAuthority2-...-SubAuthorityn
+     * @param sidString the string SID
+     * @return the binary SID
      */
     public static byte[] sidStringToBytes( String sidString )
     {
@@ -626,17 +638,17 @@
     /**
      * Convert String to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
      * 
-     * @param string
-     *            A String containing an integer.
+     * @param string A String containing an integer.
+     * @param from The index to start parsing from
      * @return an int
      */
-    public static int toInt(String string)
+    public static int toInt(String string,int from)
     {
         int val = 0;
         boolean started = false;
         boolean minus = false;
 
-        for (int i = 0; i < string.length(); i++)
+        for (int i = from; i < string.length(); i++)
         {
             char b = string.charAt(i);
             if (b <= ' ')
@@ -661,7 +673,7 @@
             return minus?(-val):val;
         throw new NumberFormatException(string);
     }
-
+    
     /**
      * Convert String to an long. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown
      * 
@@ -982,5 +994,17 @@
         }
         return out.toString();
     }
+    
+    /* ------------------------------------------------------------ */
+    /** The String value of an Object
+     * <p>This method calls {@link String#valueOf(Object)} unless the object is null,
+     * in which case null is returned</p>
+     * @param object The object
+     * @return String value or null
+     */
+    public static String valueOf(Object object)
+    {
+        return object==null?null:String.valueOf(object);
+    }
 
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
index d791151..54f99a3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
@@ -20,8 +20,8 @@
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -34,13 +34,13 @@
  * <p>This Trie is stored in a Tree and is unlimited in capacity</p>
  * 
  * <p>This Trie is not Threadsafe and contains no mutual exclusion 
- * or deliberate memory barriers.  It is intended for an ArrayTrie to be
+ * or deliberate memory barriers.  It is intended for an TreeTrie to be
  * built by a single thread and then used concurrently by multiple threads
  * and not mutated during that access.  If concurrent mutations of the
  * Trie is required external locks need to be applied.
  * </p>
  * 
- * @param <V>
+ * @param <V> the entry type
  */
 public class TreeTrie<V> extends AbstractTrie<V>
 {
@@ -75,6 +75,15 @@
         _nextIndex = new TreeTrie[INDEX];
         this._c=c;
     }
+    
+    @Override
+    public void clear()
+    {
+        Arrays.fill(_nextIndex,null);
+        _nextOther.clear();
+        _key=null;
+        _value=null;
+    }
 
     @Override
     public boolean put(String s, V v)
@@ -224,9 +233,43 @@
     @Override
     public V getBest(String s, int offset, int len)
     {
-        // TODO inefficient
-        byte[] b=s.substring(offset,offset+len).getBytes(StandardCharsets.ISO_8859_1);
-        return getBest(b,0,b.length);
+        TreeTrie<V> t = this;
+        for(int i=0; i < len; i++)
+        {
+            byte c=(byte)(0xff&s.charAt(offset+i));
+            int index=c>=0&&c<0x7f?__lookup[c]:-1;
+            if (index>=0)
+            {
+                if (t._nextIndex[index] == null) 
+                    break;
+                t = t._nextIndex[index];
+            }
+            else
+            {
+                TreeTrie<V> n=null;
+                for (int j=t._nextOther.size();j-->0;)
+                {
+                    n=t._nextOther.get(j);
+                    if (n._c==c)
+                        break;
+                    n=null;
+                }
+                if (n==null)
+                    break;
+                t=n;
+            }
+            
+            // Is the next Trie is a match
+            if (t._key!=null)
+            {
+                // Recurse so we can remember this possibility
+                V best=t.getBest(s,offset+i+1,len-i-1);
+                if (best!=null)
+                    return best;
+                break;
+            }
+        }
+        return t._value;
     }
     
     @Override
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
index fd4459b..1655f55 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
@@ -24,7 +24,7 @@
 
 /* ------------------------------------------------------------ */
 /** A Trie String lookup data structure.
- * @param <V>
+ * @param <V> the Trie entry type
  */
 public interface Trie<V>
 {
@@ -49,6 +49,7 @@
     /* ------------------------------------------------------------ */
     /** Get and exact match from a String key
      * @param s The key
+     * @return the value for the string key
      */
     public V get(String s);
 
@@ -57,6 +58,7 @@
      * @param s The key
      * @param offset The offset within the string of the key
      * @param len the length of the key
+     * @return the value for the string / offset / length
      */
     public V get(String s,int offset,int len);
 
@@ -121,4 +123,7 @@
     /* ------------------------------------------------------------ */
     public boolean isCaseInsensitive();
 
+    /* ------------------------------------------------------------ */
+    public void clear();
+
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
index b71e29e..0173e55 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java
@@ -29,6 +29,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import org.eclipse.jetty.util.annotation.Name;
 import org.eclipse.jetty.util.log.Log;
@@ -173,7 +174,9 @@
     /** Array to List.
      * <p>
      * Works like {@link Arrays#asList(Object...)}, but handles null arrays.
+     * @param a the array to convert to a list
      * @return a list backed by the array.
+     * @param <T> the array and list entry type
      */
     public static <T> List<T> asList(T[] a)
     {
@@ -362,6 +365,19 @@
      * @param c An ASCII encoded character 0-9 a-f A-F
      * @return The byte value of the character 0-16.
      */
+    public static int convertHexDigit( char c )
+    {
+        int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
+        if (d<0 || d>15)
+            throw new NumberFormatException("!hex "+c);
+        return d;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param c An ASCII encoded character 0-9 a-f A-F
+     * @return The byte value of the character 0-16.
+     */
     public static int convertHexDigit( int c )
     {
         int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
@@ -483,6 +499,13 @@
     public static Object call(Class<?> oClass, String methodName, Object obj, Object[] arg)
        throws InvocationTargetException, NoSuchMethodException
     {
+        Objects.requireNonNull(oClass,"Class cannot be null");
+        Objects.requireNonNull(methodName,"Method name cannot be null");
+        if (StringUtil.isBlank(methodName))
+        {
+            throw new IllegalArgumentException("Method name cannot be blank");
+        }
+        
         // Lets just try all methods for now
         for (Method method : oClass.getMethods())
         {
@@ -539,9 +562,17 @@
 
     public static Object construct(Class<?> klass, Object[] arguments) throws InvocationTargetException, NoSuchMethodException
     {
+        Objects.requireNonNull(klass,"Class cannot be null");
+        
         for (Constructor<?> constructor : klass.getConstructors())
         {
-            if (constructor.getParameterTypes().length != arguments.length)
+            if (arguments == null)
+            {
+                // null arguments in .newInstance() is allowed
+                if (constructor.getParameterTypes().length != 0)
+                    continue;
+            }
+            else if (constructor.getParameterTypes().length != arguments.length)
                 continue;
 
             try
@@ -558,20 +589,34 @@
     
     public static Object construct(Class<?> klass, Object[] arguments, Map<String, Object> namedArgMap) throws InvocationTargetException, NoSuchMethodException
     {
+        Objects.requireNonNull(klass,"Class cannot be null");
+        Objects.requireNonNull(namedArgMap,"Named Argument Map cannot be null");
+        
         for (Constructor<?> constructor : klass.getConstructors())
         {
-            if (constructor.getParameterTypes().length != arguments.length)
+            if (arguments == null)
+            {
+                // null arguments in .newInstance() is allowed
+                if (constructor.getParameterTypes().length != 0)
+                    continue;
+            }
+            else if (constructor.getParameterTypes().length != arguments.length)
                 continue;
 
             try
             {
                 Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
                 
-                // target has no annotations
-                if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
+                if (arguments == null || arguments.length == 0)
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("Target has no parameter annotations");
+                        LOG.debug("Constructor has no arguments");
+                    return constructor.newInstance(arguments);
+                }
+                else if (parameterAnnotations == null || parameterAnnotations.length == 0)
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Constructor has no parameter annotations");
                     return constructor.newInstance(arguments);
                 }
                 else
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
index 193a118..7f91210 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java
@@ -21,22 +21,29 @@
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
+import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 
-
-/* ------------------------------------------------------------ */
-/** URI Holder.
+/** 
+ * URI Utility methods.
+ * <p>
  * This class assists with the decoding and encoding or HTTP URI's.
  * It differs from the java.net.URL class as it does not provide
  * communications ability, but it does assist with query string
  * formatting.
- * <P>UTF-8 encoding is used by default for % encoded characters. This
+ * </p>
+ * <p>
+ * UTF-8 encoding is used by default for % encoded characters. This
  * may be overridden with the org.eclipse.jetty.util.URI.charset system property.
- * @see UrlEncoded
+ * </p>
  * 
+ * @see UrlEncoded
  */
 public class URIUtil
     implements Cloneable
 {
+    private static final Logger LOG = Log.getLogger(URIUtil.class);
     public static final String SLASH="/";
     public static final String HTTP="http";
     public static final String HTTP_COLON="http:";
@@ -44,13 +51,7 @@
     public static final String HTTPS_COLON="https:";
 
     // Use UTF-8 as per http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars
-    public static final Charset __CHARSET;
-
-    static
-    {
-        String charset = System.getProperty("org.eclipse.jetty.util.URI.charset");
-        __CHARSET = charset == null ? StandardCharsets.UTF_8 : Charset.forName(charset);
-    }
+    public static final Charset __CHARSET=StandardCharsets.UTF_8 ;
 
     private URIUtil()
     {}
@@ -82,8 +83,7 @@
         byte[] bytes=null;
         if (buf==null)
         {
-        loop:
-            for (int i=0;i<path.length();i++)
+            loop: for (int i=0;i<path.length();i++)
             {
                 char c=path.charAt(i);
                 switch(c)
@@ -97,6 +97,8 @@
                     case '<':
                     case '>':
                     case ' ':
+                    case '[':
+                    case ']':
                         buf=new StringBuilder(path.length()*2);
                         break loop;
                     default:
@@ -106,103 +108,111 @@
                             buf=new StringBuilder(path.length()*2);
                             break loop;
                         }
-                       
                 }
             }
             if (buf==null)
                 return null;
         }
-        
-        synchronized(buf)
+
+        if (bytes!=null)
         {
-            if (bytes!=null)
+            for (int i=0;i<bytes.length;i++)
             {
-                for (int i=0;i<bytes.length;i++)
+                byte c=bytes[i];       
+                switch(c)
                 {
-                    byte c=bytes[i];       
-                    switch(c)
-                    {
-                      case '%':
-                          buf.append("%25");
-                          continue;
-                      case '?':
-                          buf.append("%3F");
-                          continue;
-                      case ';':
-                          buf.append("%3B");
-                          continue;
-                      case '#':
-                          buf.append("%23");
-                          continue;
-                      case '"':
-                          buf.append("%22");
-                          continue;
-                      case '\'':
-                          buf.append("%27");
-                          continue;
-                      case '<':
-                          buf.append("%3C");
-                          continue;
-                      case '>':
-                          buf.append("%3E");
-                          continue;
-                      case ' ':
-                          buf.append("%20");
-                          continue;
-                      default:
-                          if (c<0)
-                          {
-                              buf.append('%');
-                              TypeUtil.toHex(c,buf);
-                          }
-                          else
-                              buf.append((char)c);
-                          continue;
-                    }
-                }
-                
-            }
-            else
-            {
-                for (int i=0;i<path.length();i++)
-                {
-                    char c=path.charAt(i);       
-                    switch(c)
-                    {
-                        case '%':
-                            buf.append("%25");
-                            continue;
-                        case '?':
-                            buf.append("%3F");
-                            continue;
-                        case ';':
-                            buf.append("%3B");
-                            continue;
-                        case '#':
-                            buf.append("%23");
-                            continue;
-                        case '"':
-                            buf.append("%22");
-                            continue;
-                        case '\'':
-                            buf.append("%27");
-                            continue;
-                        case '<':
-                            buf.append("%3C");
-                            continue;
-                        case '>':
-                            buf.append("%3E");
-                            continue;
-                        case ' ':
-                            buf.append("%20");
-                            continue;
-                        default:
-                            buf.append(c);
-                            continue;
-                    }
+                    case '%':
+                        buf.append("%25");
+                        continue;
+                    case '?':
+                        buf.append("%3F");
+                        continue;
+                    case ';':
+                        buf.append("%3B");
+                        continue;
+                    case '#':
+                        buf.append("%23");
+                        continue;
+                    case '"':
+                        buf.append("%22");
+                        continue;
+                    case '\'':
+                        buf.append("%27");
+                        continue;
+                    case '<':
+                        buf.append("%3C");
+                        continue;
+                    case '>':
+                        buf.append("%3E");
+                        continue;
+                    case ' ':
+                        buf.append("%20");
+                        continue;
+                    case '[':
+                        buf.append("%5B");
+                        continue;
+                    case ']':
+                        buf.append("%5D");
+                        continue;
+                    default:
+                        if (c<0)
+                        {
+                            buf.append('%');
+                            TypeUtil.toHex(c,buf);
+                        }
+                        else
+                            buf.append((char)c);
+                        continue;
                 }
             }
         }
+        else
+        {
+            for (int i=0;i<path.length();i++)
+            {
+                char c=path.charAt(i);       
+                switch(c)
+                {
+                    case '%':
+                        buf.append("%25");
+                        continue;
+                    case '?':
+                        buf.append("%3F");
+                        continue;
+                    case ';':
+                        buf.append("%3B");
+                        continue;
+                    case '#':
+                        buf.append("%23");
+                        continue;
+                    case '"':
+                        buf.append("%22");
+                        continue;
+                    case '\'':
+                        buf.append("%27");
+                        continue;
+                    case '<':
+                        buf.append("%3C");
+                        continue;
+                    case '>':
+                        buf.append("%3E");
+                        continue;
+                    case ' ':
+                        buf.append("%20");
+                        continue;
+                    case '[':
+                        buf.append("%5B");
+                        continue;
+                    case ']':
+                        buf.append("%5D");
+                        continue;
+                    default:
+                        buf.append(c);
+                        continue;
+                }
+            }
+        }
+
 
         return buf;
     }
@@ -254,123 +264,163 @@
     
     /* ------------------------------------------------------------ */
     /* Decode a URI path and strip parameters
-     * @param path The path the encode
-     * @param buf StringBuilder to encode path into
      */
     public static String decodePath(String path)
     {
-        if (path==null)
-            return null;
-        // Array to hold all converted characters
-        char[] chars=null;
-        int n=0;
-        // Array to hold a sequence of %encodings
-        byte[] bytes=null;
-        int b=0;
-        
-        int len=path.length();
-        
-        for (int i=0;i<len;i++)
-        {
-            char c = path.charAt(i);
-
-            if (c=='%' && (i+2)<len)
-            {
-                if (chars==null)
-                {
-                    chars=new char[len];
-                    bytes=new byte[len];
-                    path.getChars(0,i,chars,0);
-                }
-                bytes[b++]=(byte)(0xff&TypeUtil.parseInt(path,i+1,2,16));
-                i+=2;
-                continue;
-            }
-            else if (c==';')
-            {
-                if (chars==null)
-                {
-                    chars=new char[len];
-                    path.getChars(0,i,chars,0);
-                    n=i;
-                }
-                break;
-            }
-            else if (bytes==null)
-            {
-                n++;
-                continue;
-            }
-            
-            // Do we have some bytes to convert?
-            if (b>0)
-            {
-                String s=new String(bytes,0,b,__CHARSET);
-                s.getChars(0,s.length(),chars,n);
-                n+=s.length();
-                b=0;
-            }
-            
-            chars[n++]=c;
-        }
-
-        if (chars==null)
-            return path;
-
-        // if we have a remaining sequence of bytes
-        if (b>0)
-        {
-            String s=new String(bytes,0,b,__CHARSET);
-            s.getChars(0,s.length(),chars,n);
-            n+=s.length();
-        }
-        
-        return new String(chars,0,n);
+        return decodePath(path,0,path.length());
     }
+
+    /* ------------------------------------------------------------ */
+    /* Decode a URI path and strip parameters of UTF-8 path
+     */
+    public static String decodePath(String path, int offset, int length)
+    {
+        try
+        {
+            Utf8StringBuilder builder=null;
+            int end=offset+length;
+            for (int i=offset;i<end;i++)
+            {
+                char c = path.charAt(i);
+                switch(c)
+                {
+                    case '%':
+                        if (builder==null)
+                        {
+                            builder=new Utf8StringBuilder(path.length());
+                            builder.append(path,offset,i-offset);
+                        }
+                        if ((i+2)<end)
+                        {
+                            char u=path.charAt(i+1);
+                            if (u=='u')
+                            {
+                                // TODO this is wrong. This is a codepoint not a char
+                                builder.append((char)(0xffff&TypeUtil.parseInt(path,i+2,4,16)));
+                                i+=5;
+                            }
+                            else
+                            {
+                                builder.append((byte)(0xff&(TypeUtil.convertHexDigit(u)*16+TypeUtil.convertHexDigit(path.charAt(i+2)))));
+                                i+=2;
+                            }
+                        }
+                        else
+                        {
+                            throw new IllegalArgumentException("Bad URI % encoding");
+                        }
+
+                        break;
+
+                    case ';':
+                        if (builder==null)
+                        {
+                            builder=new Utf8StringBuilder(path.length());
+                            builder.append(path,offset,i-offset);
+                        }
+                        
+                        while(++i<end)
+                        {
+                            if (path.charAt(i)=='/')
+                            {
+                                builder.append('/');
+                                break;
+                            }
+                        }
+                        
+                        break;
+
+                    default:
+                        if (builder!=null)
+                            builder.append(c);
+                        break;
+                }
+            }
+
+            if (builder!=null)
+                return builder.toString();
+            if (offset==0 && length==path.length())
+                return path;
+            return path.substring(offset,end);   
+        }
+        catch(NotUtf8Exception e)
+        {
+            LOG.warn(path.substring(offset,offset+length)+" "+e);
+            LOG.debug(e);
+            return decodeISO88591Path(path,offset,length);
+        }
+    }
+
     
     /* ------------------------------------------------------------ */
-    /* Decode a URI path and strip parameters.
-     * @param path The path the encode
-     * @param buf StringBuilder to encode path into
+    /* Decode a URI path and strip parameters of ISO-8859-1 path
      */
-    public static String decodePath(byte[] buf, int offset, int length)
+    private static String decodeISO88591Path(String path, int offset, int length)
     {
-        byte[] bytes=null;
-        int n=0;
-        
-        for (int i=0;i<length;i++)
+        StringBuilder builder=null;
+        int end=offset+length;
+        for (int i=offset;i<end;i++)
         {
-            byte b = buf[i + offset];
-            
-            if (b=='%' && (i+2)<length)
+            char c = path.charAt(i);
+            switch(c)
             {
-                b=(byte)(0xff&TypeUtil.parseInt(buf,i+offset+1,2,16));
-                i+=2;
+                case '%':
+                    if (builder==null)
+                    {
+                        builder=new StringBuilder(path.length());
+                        builder.append(path,offset,i-offset);
+                    }
+                    if ((i+2)<end)
+                    {
+                        char u=path.charAt(i+1);
+                        if (u=='u')
+                        {
+                            // TODO this is wrong. This is a codepoint not a char
+                            builder.append((char)(0xffff&TypeUtil.parseInt(path,i+2,4,16)));
+                            i+=5;
+                        }
+                        else
+                        {
+                            builder.append((byte)(0xff&(TypeUtil.convertHexDigit(u)*16+TypeUtil.convertHexDigit(path.charAt(i+2)))));
+                            i+=2;
+                        }
+                    }
+                    else
+                    {
+                        throw new IllegalArgumentException();
+                    }
+                    
+                    break;
+                    
+                case ';':
+                    if (builder==null)
+                    {
+                        builder=new StringBuilder(path.length());
+                        builder.append(path,offset,i-offset);
+                    }
+                    while(++i<end)
+                    {
+                        if (path.charAt(i)=='/')
+                        {
+                            builder.append('/');
+                            break;
+                        }
+                    }
+                    break;
+                    
+                    
+                default:
+                    if (builder!=null)
+                        builder.append(c);
+                    break;
             }
-            else if (b==';')
-            {
-                length=i;
-                break;
-            }
-            else if (bytes==null)
-            {
-                n++;
-                continue;
-            }
-            
-            if (bytes==null)
-            {
-                bytes=new byte[length];
-                for (int j=0;j<n;j++)
-                    bytes[j]=buf[j + offset];
-            }
-            
-            bytes[n++]=b;
         }
 
-        if (bytes==null)
-            return new String(buf,offset,length,__CHARSET);
-        return new String(bytes,0,n,__CHARSET);
+        if (builder!=null)
+            return builder.toString();
+        if (offset==0 && length==path.length())
+            return path;
+        return path.substring(offset,end);        
     }
 
     
@@ -431,6 +481,8 @@
     /* ------------------------------------------------------------ */
     /** Return the parent Path.
      * Treat a URI like a directory path and return the parent directory.
+     * @param p the path to return a parent reference to
+     * @return the parent path of the URI
      */
     public static String parentPath(String p)
     {
@@ -446,7 +498,7 @@
     /** Convert a path to a cananonical form.
      * All instances of "." and ".." are factored out.  Null is returned
      * if the path tries to .. above its root.
-     * @param path 
+     * @param path the path to convert
      * @return path or null.
      */
     public static String canonicalPath(String path)
@@ -580,8 +632,8 @@
     /* ------------------------------------------------------------ */
     /** Convert a path to a compact form.
      * All instances of "//" and "///" etc. are factored out to single "/" 
-     * @param path 
-     * @return path
+     * @param path the path to compact 
+     * @return the compacted path 
      */
     public static String compactPath(String path)
     {
@@ -667,11 +719,11 @@
     /* ------------------------------------------------------------ */
     /**
      * Create a new URI from the arguments, handling IPv6 host encoding and default ports
-     * @param scheme
-     * @param server
-     * @param port
-     * @param path
-     * @param query
+     * @param scheme the URI scheme
+     * @param server the URI server
+     * @param port the URI port
+     * @param path the URI path
+     * @param query the URI query
      * @return A String URI
      */
     public static String newURI(String scheme,String server, int port,String path,String query)
@@ -686,9 +738,9 @@
     /* ------------------------------------------------------------ */
     /**
      * Create a new URI StringBuilder from the arguments, handling IPv6 host encoding and default ports
-     * @param scheme
-     * @param server
-     * @param port
+     * @param scheme the URI scheme
+     * @param server the URI server
+     * @param port the URI port
      * @return a StringBuilder containing URI prefix
      */
     public static StringBuilder newURIBuilder(String scheme,String server, int port)
@@ -700,11 +752,11 @@
 
     /* ------------------------------------------------------------ */
     /** 
-     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports</p>
+     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports
      * @param url StringBuilder to append to
-     * @param scheme
-     * @param server
-     * @param port
+     * @param scheme the URI scheme
+     * @param server the URI server
+     * @param port the URI port
      */
     public static void appendSchemeHostPort(StringBuilder url,String scheme,String server, int port)
     {
@@ -735,11 +787,11 @@
     
     /* ------------------------------------------------------------ */
     /** 
-     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports</p>
+     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports
      * @param url StringBuffer to append to
-     * @param scheme
-     * @param server
-     * @param port
+     * @param scheme the URI scheme
+     * @param server the URI server
+     * @param port the URI port
      */
     public static void appendSchemeHostPort(StringBuffer url,String scheme,String server, int port)
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
index a893fc9..6ba8bf4 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java
@@ -33,22 +33,26 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
-/* ------------------------------------------------------------ */
-/** Handles coding of MIME  "x-www-form-urlencoded".
+/** 
+ * Handles coding of MIME  "x-www-form-urlencoded".
  * <p>
  * This class handles the encoding and decoding for either
  * the query string of a URL or the _content of a POST HTTP request.
- *
- * <h4>Notes</h4>
+ * </p>
+ * <b>Notes</b>
+ * <p>
  * The UTF-8 charset is assumed, unless otherwise defined by either
  * passing a parameter or setting the "org.eclipse.jetty.util.UrlEncoding.charset"
  * System property.
+ * </p>
  * <p>
  * The hashtable either contains String single values, vectors
  * of String or arrays of Strings.
+ * </p>
  * <p>
  * This class is only partially synchronised.  In particular, simple
  * get operations are not protected from concurrent updates.
+ * </p>
  *
  * @see java.net.URLEncoder
  */
@@ -87,23 +91,24 @@
     
     public UrlEncoded(String query)
     {
-        decodeTo(query,this,ENCODING,-1);
+        decodeTo(query,this,ENCODING);
     }
 
     /* ----------------------------------------------------------------- */
     public void decode(String query)
     {
-        decodeTo(query,this,ENCODING,-1);
+        decodeTo(query,this,ENCODING);
     }
     
     /* ----------------------------------------------------------------- */
     public void decode(String query,Charset charset)
     {
-        decodeTo(query,this,charset,-1);
+        decodeTo(query,this,charset);
     }
     
     /* -------------------------------------------------------------- */
-    /** Encode Hashtable with % encoding.
+    /** Encode MultiMap with % encoding for UTF8 sequences.
+     * @return the MultiMap as a string with % encoding
      */
     public String encode()
     {
@@ -111,7 +116,9 @@
     }
     
     /* -------------------------------------------------------------- */
-    /** Encode Hashtable with % encoding.
+    /** Encode MultiMap with % encoding for arbitrary Charset sequences.
+     * @param charset the charset to use for encoding
+     * @return the MultiMap as a string encoded with % encodings
      */
     public String encode(Charset charset)
     {
@@ -119,9 +126,12 @@
     }
     
     /* -------------------------------------------------------------- */
-    /** Encode Hashtable with % encoding.
+    /** 
+     * Encode MultiMap with % encoding.
+     * @param charset the charset to encode with
      * @param equalsForNullValue if True, then an '=' is always used, even
-     * for parameters without a value. e.g. "blah?a=&b=&c=".
+     * for parameters without a value. e.g. <code>"blah?a=&amp;b=&amp;c="</code>.
+     * @return the MultiMap as a string encoded with % encodings
      */
     public synchronized String encode(Charset charset, boolean equalsForNullValue)
     {
@@ -129,9 +139,12 @@
     }
     
     /* -------------------------------------------------------------- */
-    /** Encode Hashtable with % encoding.
+    /** Encode MultiMap with % encoding.
+     * @param map the map to encode
+     * @param charset the charset to use for encoding (uses default encoding if null)
      * @param equalsForNullValue if True, then an '=' is always used, even
-     * for parameters without a value. e.g. "blah?a=&b=&c=".
+     * for parameters without a value. e.g. <code>"blah?a=&amp;b=&amp;c="</code>.
+     * @return the MultiMap as a string encoded with % encodings. 
      */
     public static String encode(MultiMap<String> map, Charset charset, boolean equalsForNullValue)
     {
@@ -190,21 +203,31 @@
     /* -------------------------------------------------------------- */
     /** Decoded parameters to Map.
      * @param content the string containing the encoded parameters
+     * @param map the MultiMap to put parsed query parameters into
+     * @param charset the charset to use for decoding
      */
-    public static void decodeTo(String content, MultiMap<String> map, String charset, int maxKeys)
+    public static void decodeTo(String content, MultiMap<String> map, String charset)
     {
-        decodeTo(content,map,charset==null?null:Charset.forName(charset),maxKeys);
+        decodeTo(content,map,charset==null?null:Charset.forName(charset));
     }
     
     /* -------------------------------------------------------------- */
     /** Decoded parameters to Map.
      * @param content the string containing the encoded parameters
+     * @param map the MultiMap to put parsed query parameters into
+     * @param charset the charset to use for decoding
      */
-    public static void decodeTo(String content, MultiMap<String> map, Charset charset, int maxKeys)
+    public static void decodeTo(String content, MultiMap<String> map, Charset charset)
     {
         if (charset==null)
             charset=ENCODING;
 
+        if (charset==StandardCharsets.UTF_8)
+        {
+            decodeUtf8To(content,0,content.length(),map);
+            return;
+        }
+        
         synchronized(map)
         {
             String key = null;
@@ -232,8 +255,6 @@
                       }
                       key = null;
                       value=null;
-                      if (maxKeys>0 && map.size()>maxKeys)
-                          throw new IllegalStateException("Form too many keys");
                       break;
                   case '=':
                       if (key!=null)
@@ -271,13 +292,19 @@
     }
 
     /* -------------------------------------------------------------- */
+    public static void decodeUtf8To(String query, MultiMap<String> map)
+    {
+        decodeUtf8To(query,0,query.length(),map);
+    }
+    
+    /* -------------------------------------------------------------- */
     /** Decoded parameters to Map.
-     * @param raw the byte[] containing the encoded parameters
+     * @param query the string containing the encoded parameters
      * @param offset the offset within raw to decode from
      * @param length the length of the section to decode
      * @param map the {@link MultiMap} to populate
      */
-    public static void decodeUtf8To(byte[] raw,int offset, int length, MultiMap<String> map)
+    public static void decodeUtf8To(String query,int offset, int length, MultiMap<String> map)
     {
         Utf8StringBuilder buffer = new Utf8StringBuilder();
         synchronized(map)
@@ -288,10 +315,10 @@
             int end=offset+length;
             for (int i=offset;i<end;i++)
             {
-                byte b=raw[i];
+                char c=query.charAt(i);
                 try
                 {
-                    switch ((char)(0xff&b))
+                    switch (c)
                     {
                         case '&':
                             value = buffer.toReplacedString();
@@ -311,7 +338,7 @@
                         case '=':
                             if (key!=null)
                             {
-                                buffer.append(b);
+                                buffer.append(c);
                                 break;
                             }
                             key = buffer.toReplacedString();
@@ -325,15 +352,15 @@
                         case '%':
                             if (i+2<end)
                             {
-                                if ('u'==raw[i+1])
+                                if ('u'==query.charAt(i+1))
                                 {
                                     i++;
                                     if (i+4<end)
                                     {
-                                        byte top=raw[++i];
-                                        byte hi=raw[++i];
-                                        byte lo=raw[++i];
-                                        byte bot=raw[++i];
+                                        char top=query.charAt(++i);
+                                        char hi=query.charAt(++i);
+                                        char lo=query.charAt(++i);
+                                        char bot=query.charAt(++i);
                                         buffer.getStringBuilder().append(Character.toChars((convertHexDigit(top)<<12) +(convertHexDigit(hi)<<8) + (convertHexDigit(lo)<<4) +convertHexDigit(bot)));
                                     }
                                     else
@@ -344,8 +371,8 @@
                                 }
                                 else
                                 {
-                                    byte hi=raw[++i];
-                                    byte lo=raw[++i];
+                                    char hi=query.charAt(++i);
+                                    char lo=query.charAt(++i);
                                     buffer.append((byte)((convertHexDigit(hi)<<4) + convertHexDigit(lo)));
                                 }
                             }
@@ -357,7 +384,7 @@
                             break;
                             
                         default:
-                            buffer.append(b);
+                            buffer.append(c);
                             break;
                     }
                 }
@@ -388,10 +415,13 @@
     }
 
     /* -------------------------------------------------------------- */
-    /** Decoded parameters to Map.
+    /** Decoded parameters to MultiMap, using ISO8859-1 encodings.
+     * 
      * @param in InputSteam to read
      * @param map MultiMap to add parameters to
-     * @param maxLength maximum number of keys to read or -1 for no limit
+     * @param maxLength maximum length of form to read
+     * @param maxKeys maximum number of keys to read or -1 for no limit
+     * @throws IOException if unable to decode inputstream as ISO8859-1
      */
     public static void decode88591To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
     throws IOException
@@ -489,7 +519,9 @@
     /** Decoded parameters to Map.
      * @param in InputSteam to read
      * @param map MultiMap to add parameters to
-     * @param maxLength maximum number of keys to read or -1 for no limit
+     * @param maxLength maximum form length to decode
+     * @param maxKeys the maximum number of keys to read or -1 for no limit 
+     * @throws IOException if unable to decode input stream
      */
     public static void decodeUtf8To(InputStream in, MultiMap<String> map, int maxLength, int maxKeys)
     throws IOException
@@ -620,12 +652,18 @@
         StringWriter buf = new StringWriter(8192);
         IO.copy(input,buf,maxLength);
         
-        decodeTo(buf.getBuffer().toString(),map,StandardCharsets.UTF_16,maxKeys);
+        // TODO implement maxKeys
+        decodeTo(buf.getBuffer().toString(),map,StandardCharsets.UTF_16);
     }
 
     /* -------------------------------------------------------------- */
     /** Decoded parameters to Map.
      * @param in the stream containing the encoded parameters
+     * @param map the MultiMap to decode into
+     * @param charset the charset to use for decoding
+     * @param maxLength the maximum length of the form to decode
+     * @param maxKeys the maximum number of keys to decode
+     * @throws IOException if unable to decode input stream
      */
     public static void decodeTo(InputStream in, MultiMap<String> map, String charset, int maxLength, int maxKeys)
     throws IOException
@@ -650,6 +688,11 @@
     /* -------------------------------------------------------------- */
     /** Decoded parameters to Map.
      * @param in the stream containing the encoded parameters
+     * @param map the MultiMap to decode into
+     * @param charset the charset to use for decoding
+     * @param maxLength the maximum length of the form to decode
+     * @param maxKeys the maximum number of keys to decode
+     * @throws IOException if unable to decode input stream
      */
     public static void decodeTo(InputStream in, MultiMap<String> map, Charset charset, int maxLength, int maxKeys)
     throws IOException
@@ -769,11 +812,28 @@
             }
         }
     }
+
+    /* -------------------------------------------------------------- */
+    /** Decode String with % encoding.
+     * This method makes the assumption that the majority of calls
+     * will need no decoding.
+     * @param encoded the encoded string to decode
+     * @return the decoded string
+     */
+    public static String decodeString(String encoded)
+    {
+        return decodeString(encoded,0,encoded.length(),ENCODING);
+    }
     
     /* -------------------------------------------------------------- */
     /** Decode String with % encoding.
      * This method makes the assumption that the majority of calls
      * will need no decoding.
+     * @param encoded the encoded string to decode
+     * @param offset the offset in the encoded string to decode from
+     * @param length the length of characters in the encoded string to decode
+     * @param charset the charset to use for decoding
+     * @return the decoded string
      */
     public static String decodeString(String encoded,int offset,int length,Charset charset)
     {
@@ -991,7 +1051,7 @@
     
     /* ------------------------------------------------------------ */
     /** Perform URL encoding.
-     * @param string 
+     * @param string the string to encode
      * @return encoded string.
      */
     public static String encodeString(String string)
@@ -1001,7 +1061,8 @@
     
     /* ------------------------------------------------------------ */
     /** Perform URL encoding.
-     * @param string 
+     * @param string the string to encode
+     * @param charset the charset to use for encoding
      * @return encoded string.
      */
     public static String encodeString(String string,Charset charset)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
index d713698..4dc45ee 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8Appendable.java
@@ -37,7 +37,7 @@
  *
  * License information for Bjoern Hoehrmann's code:
  *
- * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+ * Copyright (c) 2008-2009 Bjoern Hoehrmann &lt;bjoern@hoehrmann.de&gt;
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -98,6 +98,58 @@
         _state = UTF8_ACCEPT;
     }
 
+    
+    private void checkCharAppend() throws IOException
+    {
+        if (_state != UTF8_ACCEPT)
+        {
+            _appendable.append(REPLACEMENT);
+            int state=_state;
+            _state=UTF8_ACCEPT;
+            throw new NotUtf8Exception("char appended in state "+state);
+        }
+    }
+    
+    public void append(char c)
+    {
+        try
+        {
+            checkCharAppend();
+            _appendable.append(c); 
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void append(String s)
+    {
+        try
+        {
+            checkCharAppend();
+            _appendable.append(s); 
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    public void append(String s,int offset,int length)
+    {
+        try
+        {
+            checkCharAppend();
+            _appendable.append(s,offset,offset+length); 
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    
     public void append(byte b)
     {
         try
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
index 0332d98..3347e04 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Utf8LineParser.java
@@ -20,6 +20,8 @@
 
 import java.nio.ByteBuffer;
 
+import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
+
 /**
  * Stateful parser for lines of UTF8 formatted text, looking for <code>"\n"</code> as a line termination character.
  * <p>
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedAttribute.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedAttribute.java
index a113c30..1f753dc 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedAttribute.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedAttribute.java
@@ -25,14 +25,13 @@
 import java.lang.annotation.Target;
 
 /**
- * The @ManagedAttribute annotation is used to indicate that a given method 
+ * The <code>&#064;ManagedAttribute</code> annotation is used to indicate that a given method 
  * exposes a JMX attribute. This annotation is placed always on the reader 
  * method of a given attribute. Unless it is marked as read-only in the 
  * configuration of the annotation a corresponding setter is looked for 
  * following normal naming conventions. For example if this annotation is 
  * on a method called getFoo() then a method called setFoo() would be looked 
  * for and if found wired automatically into the jmx attribute.
- *
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
@@ -42,7 +41,7 @@
     /**
      * Description of the Managed Attribute
      * 
-     * @returngit checkout
+     * @return value
      */
     String value() default "Not Specified";
     
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java
index e2e7d1d..46975ba 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedObject.java
@@ -25,12 +25,11 @@
 import java.lang.annotation.Target;
 
 /**
- * The @ManagedObject annotation is used on a class at the top level to 
+ * The <code>&#064;ManagedObject</code> annotation is used on a class at the top level to 
  * indicate that it should be exposed as an mbean. It has only one attribute 
  * to it which is used as the description of the MBean. Should multiple 
- * @ManagedObject annotations be found in the chain of influence then the 
+ * <code>&#064;ManagedObject</code> annotations be found in the chain of influence then the 
  * first description is used.
- *
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
@@ -39,6 +38,7 @@
 {
     /**
      * Description of the Managed Object
+     * @return value
      */
     String value() default "Not Specified";
   
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java
index 1dd9791..048d6ed 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/ManagedOperation.java
@@ -25,9 +25,8 @@
 import java.lang.annotation.Target;
 
 /**
- * The @ManagedOperation annotation is used to indicate that a given method 
+ * The <code>&#064;ManagedOperation</code> annotation is used to indicate that a given method 
  * should be considered a JMX operation.
- *
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
@@ -36,6 +35,7 @@
 {
     /**
      * Description of the Managed Object
+     * @return value
      */
     String value() default "Not Specified";
     
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Name.java b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Name.java
index c690599..7875f16 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Name.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/annotation/Name.java
@@ -39,11 +39,13 @@
 {
     /**
      * the name of the parameter
+     * @return the value
      */
     String value();
     
     /**
      * the description of the parameter
+     * @return the description
      */
     String description() default "";
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
index 4aef341..c0bedc5 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java
@@ -209,7 +209,8 @@
     private void setFailed(Throwable th)
     {
         _state = __FAILED;
-        LOG.warn(FAILED+" " + this+": "+th,th);
+        if (LOG.isDebugEnabled())
+            LOG.warn(FAILED+" " + this+": "+th,th);
         for (Listener listener : _listeners)
             listener.lifeCycleFailure(this,th);
     }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
index 8788004..b5fdaae 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Container.java
@@ -20,6 +20,9 @@
 
 import java.util.Collection;
 
+/**
+ * A Container
+ */
 public interface Container
 {
     /* ------------------------------------------------------------ */
@@ -39,6 +42,7 @@
     /**
      * @param clazz the class of the beans
      * @return the list of beans of the given class (or subclass)
+     * @param <T> the Bean type
      * @see #getBeans()
      */
     public <T> Collection<T> getBeans(Class<T> clazz);
@@ -46,12 +50,14 @@
     /**
      * @param clazz the class of the bean
      * @return the first bean of a specific class (or subclass), or null if no such bean exist
+     * @param <T> the Bean type 
      */
     public <T> T getBean(Class<T> clazz);
 
     /**
      * Removes the given bean.
      * If the bean is-a {@link Listener}, then also do an implicit {@link #removeEventListener(Listener)}.
+     * @param o the bean to remove
      * @return whether the bean was removed
      */
     public boolean removeBean(Object o);
@@ -59,14 +65,14 @@
     /**
      * Add an event listener. 
      * @see Container#addBean(Object)
-     * @param listener
+     * @param listener the listener to add
      */
     public void addEventListener(Listener listener);
     
     /**
      * Remove an event listener. 
      * @see Container#removeBean(Object)
-     * @param listener
+     * @param listener the listener to remove
      */
     public void removeEventListener(Listener listener);
 
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
index 4756bc1..2457a90 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java
@@ -124,8 +124,8 @@
     /**
      * Starts the given lifecycle.
      *
-     * @param l
-     * @throws Exception
+     * @param l the lifecycle to start
+     * @throws Exception if unable to start lifecycle
      */
     protected void start(LifeCycle l) throws Exception
     {
@@ -135,8 +135,8 @@
     /**
      * Stops the given lifecycle.
      *
-     * @param l
-     * @throws Exception
+     * @param l the lifecycle to stop
+     * @throws Exception if unable to stop the lifecycle
      */
     protected void stop(LifeCycle l) throws Exception
     {
@@ -158,8 +158,7 @@
             if (b._managed==Managed.MANAGED && b._bean instanceof LifeCycle)
             {
                 LifeCycle l = (LifeCycle)b._bean;
-                if (l.isRunning())
-                    stop(l);
+                stop(l);
             }
         }
     }
@@ -329,11 +328,11 @@
     
     /* ------------------------------------------------------------ */
     /** Add a managed lifecycle.
-     * <p>This is a conveniance method that uses addBean(lifecycle,true)
+     * <p>This is a convenience method that uses addBean(lifecycle,true)
      * and then ensures that the added bean is started iff this container
      * is running.  Exception from nested calls to start are caught and 
      * wrapped as RuntimeExceptions
-     * @param lifecycle
+     * @param lifecycle the managed lifecycle to add
      */
     public void addManaged(LifeCycle lifecycle)
     {
@@ -777,6 +776,17 @@
                 addBean(newBean);
         }
     }
+    
+    public void updateBean(Object oldBean, final Object newBean, boolean managed)
+    {
+        if (newBean!=oldBean)
+        {
+            if (oldBean!=null)
+                removeBean(oldBean);
+            if (newBean!=null)
+                addBean(newBean,managed);
+        }
+    }
 
     public void updateBeans(Object[] oldBeans, final Object[] newBeans)
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableCollection.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableCollection.java
new file mode 100644
index 0000000..b504ed9
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableCollection.java
@@ -0,0 +1,51 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.component;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
+
+public class DumpableCollection implements Dumpable
+{
+    private final String _name;
+    private final Collection<?> _collection;
+
+    public DumpableCollection(String name,Collection<?> collection)
+    {
+        _name=name;
+        _collection=collection;
+    }
+
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        out.append(_name).append("\n");
+        if (_collection!=null)
+            ContainerLifeCycle.dump(out,indent,_collection);
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
index b064d54..364f257 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/LifeCycle.java
@@ -26,7 +26,7 @@
 /* ------------------------------------------------------------ */
 /**
  * The lifecycle interface for generic components.
- * <br />
+ * <br>
  * Classes implementing this interface have a defined life cycle
  * defined by the methods of this interface.
  *
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
index e061ae7..8dc4792 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/AbstractLogger.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.util.log;
 
+import java.util.Properties;
 
 /* ------------------------------------------------------------ */
 /** Abstract Logger.
@@ -25,6 +26,13 @@
  */
 public abstract class AbstractLogger implements Logger
 {
+    public static final int LEVEL_DEFAULT = -1;
+    public static final int LEVEL_ALL = 0;
+    public static final int LEVEL_DEBUG = 1;
+    public static final int LEVEL_INFO = 2;
+    public static final int LEVEL_WARN = 3;
+    public static final int LEVEL_OFF = 10;
+        
     @Override
     public final Logger getLogger(String name)
     {
@@ -76,6 +84,137 @@
         return true;
     }
     
+    /**
+     * Get the Logging Level for the provided log name. Using the FQCN first, then each package segment from longest to
+     * shortest.
+     *
+     * @param props
+     *            the properties to check
+     * @param name
+     *            the name to get log for
+     * @return the logging level
+     */
+    public static int lookupLoggingLevel(Properties props, final String name)
+    {
+        if ((props == null) || (props.isEmpty()) || name==null )
+            return LEVEL_DEFAULT;
+        
+        // Calculate the level this named logger should operate under.
+        // Checking with FQCN first, then each package segment from longest to shortest.
+        String nameSegment = name;
+    
+        while ((nameSegment != null) && (nameSegment.length() > 0))
+        {
+            String levelStr = props.getProperty(nameSegment + ".LEVEL");
+            // System.err.printf("[StdErrLog.CONFIG] Checking for property [%s.LEVEL] = %s%n",nameSegment,levelStr);
+            int level = getLevelId(nameSegment + ".LEVEL",levelStr);
+            if (level != (-1))
+            {
+                return level;
+            }
+    
+            // Trim and try again.
+            int idx = nameSegment.lastIndexOf('.');
+            if (idx >= 0)
+            {
+                nameSegment = nameSegment.substring(0,idx);
+            }
+            else
+            {
+                nameSegment = null;
+            }
+        }
+    
+        // Default Logging Level
+        return LEVEL_DEFAULT;
+    }
+
+
+    public static String getLoggingProperty(Properties props, String name, String property)
+    {
+        // Calculate the level this named logger should operate under.
+        // Checking with FQCN first, then each package segment from longest to shortest.
+        String nameSegment = name;
+    
+        while ((nameSegment != null) && (nameSegment.length() > 0))
+        {
+            String s = props.getProperty(nameSegment+"."+property);
+            if (s!=null)
+                return s;
+    
+            // Trim and try again.
+            int idx = nameSegment.lastIndexOf('.');
+            nameSegment = (idx >= 0)?nameSegment.substring(0,idx):null;
+        }
+    
+        return null;
+    }
+
+
+    protected static int getLevelId(String levelSegment, String levelName)
+    {
+        if (levelName == null)
+        {
+            return -1;
+        }
+        String levelStr = levelName.trim();
+        if ("ALL".equalsIgnoreCase(levelStr))
+        {
+            return LEVEL_ALL;
+        }
+        else if ("DEBUG".equalsIgnoreCase(levelStr))
+        {
+            return LEVEL_DEBUG;
+        }
+        else if ("INFO".equalsIgnoreCase(levelStr))
+        {
+            return LEVEL_INFO;
+        }
+        else if ("WARN".equalsIgnoreCase(levelStr))
+        {
+            return LEVEL_WARN;
+        }
+        else if ("OFF".equalsIgnoreCase(levelStr))
+        {
+            return LEVEL_OFF;
+        }
+    
+        System.err.println("Unknown StdErrLog level [" + levelSegment + "]=[" + levelStr + "], expecting only [ALL, DEBUG, INFO, WARN, OFF] as values.");
+        return -1;
+    }
+
+
+    /**
+     * Condenses a classname by stripping down the package name to just the first character of each package name
+     * segment.Configured
+     *
+     * <pre>
+     * Examples:
+     * "org.eclipse.jetty.test.FooTest"           = "oejt.FooTest"
+     * "org.eclipse.jetty.server.logging.LogTest" = "orjsl.LogTest"
+     * </pre>
+     *
+     * @param classname
+     *            the fully qualified class name
+     * @return the condensed name
+     */
+    protected static String condensePackageString(String classname)
+    {
+        String parts[] = classname.split("\\.");
+        StringBuilder dense = new StringBuilder();
+        for (int i = 0; i < (parts.length - 1); i++)
+        {
+            dense.append(parts[i].charAt(0));
+        }
+        if (dense.length() > 0)
+        {
+            dense.append('.');
+        }
+        dense.append(parts[parts.length - 1]);
+        return dense.toString();
+    }
+
+
     public void debug(String msg, long arg)
     {
         if (isDebugEnabled())
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java
index 70498e4..9261600 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java
@@ -18,7 +18,14 @@
 
 package org.eclipse.jetty.util.log;
 
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+
+import org.eclipse.jetty.util.Loader;
 
 /**
  * <p>
@@ -26,27 +33,109 @@
  * </p>
  *
  * <p>
- * You can also set the logger level using <a href="http://java.sun.com/j2se/1.5.0/docs/guide/logging/overview.html">
+ * You can also set the logger level using <a href="http://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html">
  * standard java.util.logging configuration</a>.
  * </p>
+ * 
+ * Configuration Properties:
+ * <dl>
+ *   <dt>${name|hierarchy}.LEVEL=(ALL|DEBUG|INFO|WARN|OFF)</dt>
+ *   <dd>
+ *   Sets the level that the Logger should log at.<br>
+ *   Names can be a package name, or a fully qualified class name.<br>
+ *   Default: The default from the java.util.logging mechanism/configuration
+ *   <br>
+ *   <dt>org.eclipse.jetty.util.log.javautil.PROPERTIES=&lt;property-resource-name&gt;</dt>
+ *   <dd>If set, it is used as a classpath resource name to find a java.util.logging 
+ *   property file.
+ *   <br>
+ *   Default: null
+ *   </dd>
+ *   <dt>org.eclipse.jetty.util.log.javautil.SOURCE=(true|false)</dt>
+ *   <dd>Set the LogRecord source class and method for JavaUtilLog.<br>
+ *   Default: true
+ *   </dd>
+ *   <dt>org.eclipse.jetty.util.log.SOURCE=(true|false)</dt>
+ *   <dd>Set the LogRecord source class and method for all Loggers.<br>
+ *   Default: depends on Logger class
+ *   </dd>
+ * </dl>
  */
 public class JavaUtilLog extends AbstractLogger
 {
+    private final static String THIS_CLASS= JavaUtilLog.class.getName();
+    private final static boolean __source = 
+            Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.SOURCE",
+            Log.__props.getProperty("org.eclipse.jetty.util.log.javautil.SOURCE","true")));
+    
+    private static boolean _initialized=false;
+    
     private Level configuredLevel;
     private java.util.logging.Logger _logger;
 
     public JavaUtilLog()
     {
-        this("org.eclipse.jetty.util.log");
+        this("org.eclipse.jetty.util.log.javautil");
     }
 
     public JavaUtilLog(String name)
     {
-        _logger = java.util.logging.Logger.getLogger(name);
-        if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.DEBUG", "false")))
+        synchronized (JavaUtilLog.class)
         {
-            _logger.setLevel(Level.FINE);
+            if (!_initialized)
+            {
+                _initialized=true;
+
+                final String properties=Log.__props.getProperty("org.eclipse.jetty.util.log.javautil.PROPERTIES",null);
+                if (properties!=null)
+                {
+                    AccessController.doPrivileged(new PrivilegedAction<Object>()
+                    {
+                        public Object run()
+                        {
+                            try
+                            {
+                                URL props = Loader.getResource(JavaUtilLog.class,properties);
+                                if (props != null)
+                                    LogManager.getLogManager().readConfiguration(props.openStream());
+                            }
+                            catch(Throwable e)
+                            {
+                                System.err.println("[WARN] Error loading logging config: " + properties);
+                                e.printStackTrace(System.err);
+                            }
+                            
+                            return null;
+                        }
+                    });
+                }
+            }
         }
+        
+        _logger = java.util.logging.Logger.getLogger(name);
+        
+        switch(lookupLoggingLevel(Log.__props,name))
+        {
+            case LEVEL_ALL:
+                _logger.setLevel(Level.ALL);
+                break;
+            case LEVEL_DEBUG:
+                _logger.setLevel(Level.FINE);
+                break;
+            case LEVEL_INFO:
+                _logger.setLevel(Level.INFO);
+                break;
+            case LEVEL_WARN:
+                _logger.setLevel(Level.WARNING);
+                break;
+            case LEVEL_OFF:
+                _logger.setLevel(Level.OFF);
+                break;
+            case LEVEL_DEFAULT:
+            default:
+                break;
+        }
+        
         configuredLevel = _logger.getLevel();
     }
 
@@ -55,36 +144,63 @@
         return _logger.getName();
     }
 
+    protected void log(Level level,String msg,Throwable thrown)
+    {
+        LogRecord record = new LogRecord(level,msg);
+        if (thrown!=null)
+            record.setThrown(thrown);
+        record.setLoggerName(_logger.getName());
+        if (__source)
+        {
+            StackTraceElement[] stack = new Throwable().getStackTrace();
+            for (int i=0;i<stack.length;i++)
+            {
+                StackTraceElement e=stack[i];
+                if (!e.getClassName().equals(THIS_CLASS))
+                {
+                    record.setSourceClassName(e.getClassName());
+                    record.setSourceMethodName(e.getMethodName());
+                    break;
+                }
+            }
+        }
+        _logger.log(record);
+    }
+    
     public void warn(String msg, Object... args)
     {
         if (_logger.isLoggable(Level.WARNING))
-            _logger.log(Level.WARNING,format(msg,args));
+            log(Level.WARNING,format(msg,args),null);
     }
 
     public void warn(Throwable thrown)
     {
-        warn("", thrown);
+        if (_logger.isLoggable(Level.WARNING))
+            log(Level.WARNING,"",thrown);
     }
 
     public void warn(String msg, Throwable thrown)
     {
-        _logger.log(Level.WARNING, msg, thrown);
+        if (_logger.isLoggable(Level.WARNING))
+            log(Level.WARNING,msg,thrown);
     }
 
     public void info(String msg, Object... args)
     {
         if (_logger.isLoggable(Level.INFO))
-            _logger.log(Level.INFO, format(msg, args));
+            log(Level.INFO, format(msg, args),null);
     }
 
     public void info(Throwable thrown)
     {
-        info("", thrown);
+        if (_logger.isLoggable(Level.INFO))
+            log(Level.INFO, "",thrown);
     }
 
     public void info(String msg, Throwable thrown)
     {
-        _logger.log(Level.INFO, msg, thrown);
+        if (_logger.isLoggable(Level.INFO))
+            log(Level.INFO,msg,thrown);
     }
 
     public boolean isDebugEnabled()
@@ -108,23 +224,25 @@
     public void debug(String msg, Object... args)
     {
         if (_logger.isLoggable(Level.FINE))
-            _logger.log(Level.FINE,format(msg, args));
+            log(Level.FINE,format(msg, args),null);
     }
 
     public void debug(String msg, long arg)
     {
         if (_logger.isLoggable(Level.FINE))
-            _logger.log(Level.FINE,format(msg, arg));
+            log(Level.FINE,format(msg, arg),null);
     }
 
     public void debug(Throwable thrown)
     {
-        debug("", thrown);
+        if (_logger.isLoggable(Level.FINE))
+            log(Level.FINE,"",thrown);
     }
 
     public void debug(String msg, Throwable thrown)
     {
-        _logger.log(Level.FINE, msg, thrown);
+        if (_logger.isLoggable(Level.FINE))
+            log(Level.FINE,msg,thrown);
     }
 
     /**
@@ -137,10 +255,8 @@
 
     public void ignore(Throwable ignored)
     {
-        if (Log.isIgnored())
-        {
-            warn(Log.IGNORED, ignored);
-        }
+        if (_logger.isLoggable(Level.ALL))
+            log(Level.WARNING,Log.IGNORED,ignored);
     }
 
     private String format(String msg, Object... args)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java
new file mode 100644
index 0000000..ffdc89c
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/JettyLogHandler.java
@@ -0,0 +1,198 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.regex.Pattern;
+
+/**
+ * Redirect java.util.logging events to Jetty Log
+ */
+public class JettyLogHandler extends java.util.logging.Handler
+{
+    public static void config()
+    {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        URL url = cl.getResource("logging.properties");
+        if (url != null)
+        {
+            System.err.printf("Initializing java.util.logging from %s%n",url);
+            try (InputStream in = url.openStream())
+            {
+                LogManager.getLogManager().readConfiguration(in);
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace(System.err);
+            }
+        } 
+        else 
+        {
+            System.err.printf("WARNING: java.util.logging failed to initialize: logging.properties not found%n");
+        }
+
+        System.setProperty("org.apache.commons.logging.Log","org.apache.commons.logging.impl.Jdk14Logger");
+    }
+
+    public JettyLogHandler()
+    {
+        if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.DEBUG","false")))
+        {
+            setLevel(Level.FINEST);
+        }
+
+        if (Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.IGNORED","false")))
+        {
+            setLevel(Level.ALL);
+        }
+        
+        System.err.printf("%s Initialized at level [%s]%n",this.getClass().getName(),getLevel().getName());
+    }
+
+    private synchronized String formatMessage(LogRecord record)
+    {
+        String msg = getMessage(record);
+
+        try
+        {
+            Object params[] = record.getParameters();
+            if ((params == null) || (params.length == 0))
+            {
+                return msg;
+            }
+
+            if (Pattern.compile("\\{\\d+\\}").matcher(msg).find())
+            {
+                return MessageFormat.format(msg,params);
+            }
+
+            return msg;
+        }
+        catch (Exception ex)
+        {
+            return msg;
+        }
+    }
+
+    private String getMessage(LogRecord record)
+    {
+        ResourceBundle bundle = record.getResourceBundle();
+        if (bundle != null)
+        {
+            try
+            {
+                return bundle.getString(record.getMessage());
+            }
+            catch (java.util.MissingResourceException ex)
+            {
+            }
+        }
+
+        return record.getMessage();
+    }
+
+    @Override
+    public void publish(LogRecord record)
+    {
+        org.eclipse.jetty.util.log.Logger JLOG = getJettyLogger(record.getLoggerName());
+
+        int level = record.getLevel().intValue();
+        if (level >= Level.OFF.intValue())
+        {
+            // nothing to log, skip it.
+            return;
+        }
+
+        Throwable cause = record.getThrown();
+        String msg = formatMessage(record);
+
+        if (level >= Level.WARNING.intValue())
+        {
+            // log at warn
+            if (cause != null)
+            {
+                JLOG.warn(msg,cause);
+            }
+            else
+            {
+                JLOG.warn(msg);
+            }
+            return;
+        }
+
+        if (level >= Level.INFO.intValue())
+        {
+            // log at info
+            if (cause != null)
+            {
+                JLOG.info(msg,cause);
+            }
+            else
+            {
+                JLOG.info(msg);
+            }
+            return;
+        }
+
+        if (level >= Level.FINEST.intValue())
+        {
+            // log at debug
+            if (cause != null)
+            {
+                JLOG.debug(msg,cause);
+            }
+            else
+            {
+                JLOG.debug(msg);
+            }
+            return;
+        }
+
+        if (level >= Level.ALL.intValue())
+        {
+            // only corresponds with ignore (in jetty speak)
+            JLOG.ignore(cause);
+            return;
+        }
+    }
+
+    private Logger getJettyLogger(String loggerName)
+    {
+        return org.eclipse.jetty.util.log.Log.getLogger(loggerName);
+    }
+
+    @Override
+    public void flush()
+    {
+        // ignore
+    }
+
+    @Override
+    public void close() throws SecurityException
+    {
+        // ignore
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java
index b33b5f2b..6d10772 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Log.java
@@ -130,7 +130,7 @@
         });
     }
     
-    private static void loadProperties(String resourceName, Properties props)
+    static void loadProperties(String resourceName, Properties props)
     {
         URL testProps = Loader.getResource(Log.class,resourceName);
         if (testProps != null)
@@ -169,8 +169,8 @@
 
             try
             {
-                Class<?> log_class = Loader.loadClass(Log.class, __logClass);
-                if (LOG == null || !LOG.getClass().equals(log_class))
+                Class<?> log_class = __logClass==null?null:Loader.loadClass(Log.class, __logClass);
+                if (LOG == null || (log_class!=null && !LOG.getClass().equals(log_class)))
                 {
                     LOG = (Logger)log_class.newInstance();
                     LOG.debug("Logging to {} via {}", LOG, log_class.getName());
@@ -209,9 +209,19 @@
         return LOG;
     }
 
+    /**
+     * Set the root logger.
+     * <p>
+     * Note that if any classes have statically obtained their logger instance prior to this call, their Logger will not
+     * be affected by this call.
+     * 
+     * @param log
+     *            the root logger implementation to set
+     */
     public static void setLog(Logger log)
     {
         Log.LOG = log;
+        __logClass=null;
     }
 
     /**
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java
index e02acc4..7806eed 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/Logger.java
@@ -117,6 +117,7 @@
     /**
      * Ignore an exception.
      * <p>This should be used rather than an empty catch block.
+     * @param ignored the throwable to log as ignored
      */
     public void ignore(Throwable ignored); 
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
index b8bf5aa..c3765a1 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/log/StdErrLog.java
@@ -21,6 +21,7 @@
 import java.io.PrintStream;
 import java.security.AccessControlException;
 import java.util.Properties;
+import java.util.logging.Level;
 
 import org.eclipse.jetty.util.DateCache;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
@@ -37,10 +38,10 @@
  * <dl>
  *   <dt>${name|hierarchy}.LEVEL=(ALL|DEBUG|INFO|WARN|OFF)</dt>
  *   <dd>
- *   Sets the level that the Logger should log at.<br/>
- *   Names can be a package name, or a fully qualified class name.<br/>
- *   Default: INFO<br/>
- *   <br/>
+ *   Sets the level that the Logger should log at.<br>
+ *   Names can be a package name, or a fully qualified class name.<br>
+ *   Default: INFO<br>
+ *   <br>
  *   Examples:
  *   <dl>
  *   <dt>org.eclipse.jetty.LEVEL=WARN</dt>
@@ -56,35 +57,35 @@
  *   <dt>${name}.SOURCE=(true|false)</dt>
  *   <dd>
  *   Logger specific, attempt to print the java source file name and line number
- *   where the logging event originated from.<br/>
+ *   where the logging event originated from.<br>
  *   Name must be a fully qualified class name (package name hierarchy is not supported
- *   by this configurable)<br/>
- *   Warning: this is a slow operation and will have an impact on performance!<br/>
+ *   by this configurable)<br>
+ *   Warning: this is a slow operation and will have an impact on performance!<br>
  *   Default: false
  *   </dd>
  *   
  *   <dt>${name}.STACKS=(true|false)</dt>
  *   <dd>
- *   Logger specific, control the display of stacktraces.<br/>
+ *   Logger specific, control the display of stacktraces.<br>
  *   Name must be a fully qualified class name (package name hierarchy is not supported
- *   by this configurable)<br/>
+ *   by this configurable)<br>
  *   Default: true
  *   </dd>
  *   
  *   <dt>org.eclipse.jetty.util.log.stderr.SOURCE=(true|false)</dt>
  *   <dd>Special Global Configuration, attempt to print the java source file name and line number
- *   where the logging event originated from.<br/>
+ *   where the logging event originated from.<br>
  *   Default: false
  *   </dd>
  *   
  *   <dt>org.eclipse.jetty.util.log.stderr.LONG=(true|false)</dt>
  *   <dd>Special Global Configuration, when true, output logging events to STDERR using
- *   long form, fully qualified class names.  when false, use abbreviated package names<br/>
+ *   long form, fully qualified class names.  when false, use abbreviated package names<br>
  *   Default: false
  *   </dd>
  *   <dt>org.eclipse.jetty.util.log.stderr.ESCAPE=(true|false)</dt>
  *   <dd>Global Configuration, when true output logging events to STDERR are always
- *   escaped so that control characters are replaced with '?";  '\r' with '<' and '\n' replaced '|'<br/>
+ *   escaped so that control characters are replaced with '?";  '\r' with '&lt;' and '\n' replaced '|'<br>
  *   Default: true
  *   </dd>
  * </dl>
@@ -93,18 +94,17 @@
 public class StdErrLog extends AbstractLogger
 {
     private static final String EOL = System.getProperty("line.separator");
+    // Do not change output format lightly, people rely on this output format now.
+    private static int __tagpad = Integer.parseInt(Log.__props.getProperty("org.eclipse.jetty.util.log.StdErrLog.TAG_PAD","0"));
     private static DateCache _dateCache;
-    private static final Properties __props = new Properties();
 
     private final static boolean __source = Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.SOURCE",
             Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.SOURCE","false")));
     private final static boolean __long = Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.LONG","false"));
     private final static boolean __escape = Boolean.parseBoolean(Log.__props.getProperty("org.eclipse.jetty.util.log.stderr.ESCAPE","true"));
-
+    
     static
     {
-        __props.putAll(Log.__props);
-
         String deprecatedProperties[] =
         { "DEBUG", "org.eclipse.jetty.util.log.DEBUG", "org.eclipse.jetty.util.log.stderr.DEBUG" };
 
@@ -127,11 +127,11 @@
         }
     }
 
-    public static final int LEVEL_ALL = 0;
-    public static final int LEVEL_DEBUG = 1;
-    public static final int LEVEL_INFO = 2;
-    public static final int LEVEL_WARN = 3;
-    public static final int LEVEL_OFF = 10;
+    public static void setTagPad(int pad)
+    {
+        __tagpad=pad;
+    }
+    
 
     private int _level = LEVEL_INFO;
     // Level that this Logger was configured as (remembered in special case of .setDebugEnabled())
@@ -146,6 +146,20 @@
     private final String _abbrevname;
     private boolean _hideStacks = false;
 
+    
+    public static int getLoggingLevel(Properties props,String name)
+    {
+        int level = lookupLoggingLevel(props,name);
+        if (level==LEVEL_DEFAULT)
+        {
+            level = lookupLoggingLevel(props,"log");
+            if (level==LEVEL_DEFAULT)
+                level=LEVEL_INFO;
+        }
+        return level;
+    }
+    
+    
     /**
      * Obtain a StdErrLog reference for the specified class, a convenience method used most often during testing to allow for control over a specific logger.
      * <p>
@@ -185,7 +199,7 @@
      */
     public StdErrLog(String name)
     {
-        this(name,__props);
+        this(name,null);
     }
 
     /**
@@ -198,16 +212,16 @@
      */
     public StdErrLog(String name, Properties props)
     {
-        if (props!=null && props!=__props)
-            __props.putAll(props);
-        this._name = name == null?"":name;
-        this._abbrevname = condensePackageString(this._name);
-        this._level = getLoggingLevel(props,this._name);
-        this._configuredLevel = this._level;
+        if (props!=null && props!=Log.__props)
+            Log.__props.putAll(props);
+        _name = name == null?"":name;
+        _abbrevname = condensePackageString(this._name);
+        _level = getLoggingLevel(Log.__props,this._name);
+        _configuredLevel = _level;
 
         try
         {
-            String source = getLoggingProperty(props,_name,"SOURCE");
+            String source = getLoggingProperty(Log.__props,_name,"SOURCE");
             _source = source==null?__source:Boolean.parseBoolean(source);
         }
         catch (AccessControlException ace)
@@ -218,7 +232,7 @@
         try
         {
             // allow stacktrace display to be controlled by properties as well
-            String stacks = getLoggingProperty(props,_name,"STACKS");
+            String stacks = getLoggingProperty(Log.__props,_name,"STACKS");
             _hideStacks = stacks==null?false:!Boolean.parseBoolean(stacks);
         }
         catch (AccessControlException ignore)
@@ -227,137 +241,6 @@
         }        
     }
 
-    /**
-     * Get the Logging Level for the provided log name. Using the FQCN first, then each package segment from longest to
-     * shortest.
-     *
-     * @param props
-     *            the properties to check
-     * @param name
-     *            the name to get log for
-     * @return the logging level
-     */
-    public static int getLoggingLevel(Properties props, final String name)
-    {
-        if ((props == null) || (props.isEmpty()))
-        {
-            // Default Logging Level
-            return getLevelId("log.LEVEL","INFO");
-        }
-        
-        // Calculate the level this named logger should operate under.
-        // Checking with FQCN first, then each package segment from longest to shortest.
-        String nameSegment = name;
-
-        while ((nameSegment != null) && (nameSegment.length() > 0))
-        {
-            String levelStr = props.getProperty(nameSegment + ".LEVEL");
-            // System.err.printf("[StdErrLog.CONFIG] Checking for property [%s.LEVEL] = %s%n",nameSegment,levelStr);
-            int level = getLevelId(nameSegment + ".LEVEL",levelStr);
-            if (level != (-1))
-            {
-                return level;
-            }
-
-            // Trim and try again.
-            int idx = nameSegment.lastIndexOf('.');
-            if (idx >= 0)
-            {
-                nameSegment = nameSegment.substring(0,idx);
-            }
-            else
-            {
-                nameSegment = null;
-            }
-        }
-
-        // Default Logging Level
-        return getLevelId("log.LEVEL",props.getProperty("log.LEVEL","INFO"));
-    }
-    
-    public static String getLoggingProperty(Properties props, String name, String property)
-    {
-        // Calculate the level this named logger should operate under.
-        // Checking with FQCN first, then each package segment from longest to shortest.
-        String nameSegment = name;
-
-        while ((nameSegment != null) && (nameSegment.length() > 0))
-        {
-            String s = props.getProperty(nameSegment+"."+property);
-            if (s!=null)
-                return s;
-
-            // Trim and try again.
-            int idx = nameSegment.lastIndexOf('.');
-            nameSegment = (idx >= 0)?nameSegment.substring(0,idx):null;
-        }
-
-        return null;
-    }
-
-    protected static int getLevelId(String levelSegment, String levelName)
-    {
-        if (levelName == null)
-        {
-            return -1;
-        }
-        String levelStr = levelName.trim();
-        if ("ALL".equalsIgnoreCase(levelStr))
-        {
-            return LEVEL_ALL;
-        }
-        else if ("DEBUG".equalsIgnoreCase(levelStr))
-        {
-            return LEVEL_DEBUG;
-        }
-        else if ("INFO".equalsIgnoreCase(levelStr))
-        {
-            return LEVEL_INFO;
-        }
-        else if ("WARN".equalsIgnoreCase(levelStr))
-        {
-            return LEVEL_WARN;
-        }
-        else if ("OFF".equalsIgnoreCase(levelStr))
-        {
-            return LEVEL_OFF;
-        }
-
-        System.err.println("Unknown StdErrLog level [" + levelSegment + "]=[" + levelStr + "], expecting only [ALL, DEBUG, INFO, WARN, OFF] as values.");
-        return -1;
-    }
-
-    /**
-     * Condenses a classname by stripping down the package name to just the first character of each package name
-     * segment.Configured
-     * <p>
-     *
-     * <pre>
-     * Examples:
-     * "org.eclipse.jetty.test.FooTest"           = "oejt.FooTest"
-     * "org.eclipse.jetty.server.logging.LogTest" = "orjsl.LogTest"
-     * </pre>
-     *
-     * @param classname
-     *            the fully qualified class name
-     * @return the condensed name
-     */
-    protected static String condensePackageString(String classname)
-    {
-        String parts[] = classname.split("\\.");
-        StringBuilder dense = new StringBuilder();
-        for (int i = 0; i < (parts.length - 1); i++)
-        {
-            dense.append(parts[i].charAt(0));
-        }
-        if (dense.length() > 0)
-        {
-            dense.append('.');
-        }
-        dense.append(parts[parts.length - 1]);
-        return dense.toString();
-    }
-
     public String getName()
     {
         return _name;
@@ -589,16 +472,26 @@
             buffer.append(".00");
         }
         buffer.append(ms).append(tag);
-        if (_printLongNames)
+        
+        String name=_printLongNames?_name:_abbrevname;
+        String tname=Thread.currentThread().getName();
+
+        int p=__tagpad>0?(name.length()+tname.length()-__tagpad):0;
+
+        if (p<0)
         {
-            buffer.append(_name);
+            buffer
+            .append(name)
+            .append(':')
+            .append("                                                  ",0,-p)
+            .append(tname);
         }
-        else
+        else if (p==0)
         {
-            buffer.append(_abbrevname);
+            buffer.append(name).append(':').append(tname);
         }
         buffer.append(':');
-        buffer.append(Thread.currentThread().getName()).append(": ");
+        
         if (_source)
         {
             Throwable source = new Throwable();
@@ -628,6 +521,8 @@
                 break;
             }
         }
+
+        buffer.append(' ');
     }
 
     private void format(StringBuilder builder, String msg, Object... args)
@@ -778,12 +673,6 @@
         return s.toString();
     }
 
-    public static void setProperties(Properties props)
-    {
-        __props.clear();
-        __props.putAll(props);
-    }
-
     public void ignore(Throwable ignored)
     {
         if (_level <= LEVEL_ALL)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
index d2f07c9..b5c7bac 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/FileResource.java
@@ -46,7 +46,9 @@
  * insensitivity).  By default this is turned on, or it can be controlled 
  * by calling the static method @see FileResource#setCheckAliases(boolean)
  * 
+ * @deprecated Use {@link PathResource}
  */
+@Deprecated
 public class FileResource extends Resource
 {
     private static final Logger LOG = Log.getLogger(FileResource.class);
@@ -117,7 +119,7 @@
     }
 
     /* -------------------------------------------------------- */
-    FileResource(File file)
+    public FileResource(File file)
     {
         _file=file;
         _uri=normalizeURI(_file,_file.toURI());
@@ -153,7 +155,8 @@
 
                 URI alias=new File(can).toURI();
                 // Have to encode the path as File.toURI does not!
-                return new URI("file://"+URIUtil.encodePath(alias.getPath()));  
+                String uri="file://"+URIUtil.encodePath(alias.getPath());
+                return new URI(uri);
             }
         }
         catch(Exception e)
@@ -177,7 +180,7 @@
     /* -------------------------------------------------------- */
     @Override
     public Resource addPath(String path)
-        throws IOException,MalformedURLException
+        throws IOException, MalformedURLException
     {
         path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
 
@@ -202,9 +205,14 @@
                 uri=new URI(_uri+path);
             }
         }
-        catch(final URISyntaxException e)
+        catch (final URISyntaxException e)
         {
-            throw new MalformedURLException(){{initCause(e);}};
+            throw new MalformedURLException(e.getMessage())
+            {
+                {
+                    initCause(e);
+                }
+            };
         }
 
         return new FileResource(uri);
@@ -343,7 +351,7 @@
     
     /* ------------------------------------------------------------ */
     /** 
-     * @param o
+     * @param o the object to compare against this instance
      * @return <code>true</code> of the object <code>o</code> is a {@link FileResource} pointing to the same file as this resource. 
      */
     @Override
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
index ccb15ae..45aaba9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java
@@ -55,13 +55,13 @@
     protected JarFileResource(URL url, boolean useCaches)
     {
         super(url, useCaches);
-    }
-   
+    }   
 
     /* ------------------------------------------------------------ */
     @Override
     public synchronized void close()
     {
+        _exists=false;
         _list=null;
         _entry=null;
         _file=null;
@@ -144,7 +144,6 @@
 
         if (_urlString.endsWith("!/"))
         {
-            
             String file_url=_urlString.substring(4,_urlString.length()-2);
             try{return newResource(file_url).exists();}
             catch(Exception e) {LOG.ignore(e); return false;}
@@ -179,40 +178,39 @@
                 }
                 catch(Exception e)
                 {
-                       LOG.ignore(e);
+                    LOG.ignore(e);
                 }
             }
 
             // Do we need to look more closely?
             if (jar_file!=null && _entry==null && !_directory)
             {
-                // OK - we have a JarFile, lets look at the entries for our path
-                Enumeration<JarEntry> e=jar_file.entries();
-                while(e.hasMoreElements())
+                // OK - we have a JarFile, lets look for the entry
+                JarEntry entry = jar_file.getJarEntry(_path);
+                if (entry == null) 
                 {
-                    JarEntry entry = e.nextElement();
-                    String name=entry.getName().replace('\\','/');
-                    
-                    // Do we have a match
-                    if (name.equals(_path))
+                    // the entry does not exist
+                    _exists = false;
+                } 
+                else if (entry.isDirectory()) 
+                {
+                    _directory = true;
+                    _entry = entry;
+                } 
+                else 
+                {
+                    // Let's confirm is a file
+                    JarEntry directory = jar_file.getJarEntry(_path + '/');
+                    if (directory != null) 
                     {
-                        _entry=entry;
-                        // Is the match a directory
-                        _directory=_path.endsWith("/");
-                        break;
-                    }
-                    else if (_path.endsWith("/"))
+                        _directory = true;
+                        _entry = directory;
+                    } 
+                    else 
                     {
-                        if (name.startsWith(_path))
-                        {
-                            _directory=true;
-                            break;
-                        }
-                    }
-                    else if (name.startsWith(_path) && name.length()>_path.length() && name.charAt(_path.length())=='/')
-                    {
-                        _directory=true;
-                        break;
+                        // OK is a file
+                      _directory = false;
+                      _entry = entry;
                     }
                 }
             }
@@ -228,7 +226,7 @@
                     LOG.ignore(ioe);
                 }
             }
-        }    
+        }
         
         _exists= ( _directory || _entry!=null);
         return _exists;
@@ -284,7 +282,7 @@
                 //So, do one retry to drop a connection and get a fresh JarFile
                 LOG.warn("Retrying list:"+e);
                 LOG.debug(e);
-                release();
+                close();
                 list = listEntries();
             }
 
@@ -382,7 +380,7 @@
     /**
      * Take a Resource that possibly might use URLConnection caching
      * and turn it into one that doesn't.
-     * @param resource
+     * @param resource the JarFileResource to obtain without URLConnection caching. 
      * @return the non-caching resource
      */
     public static Resource getNonCachingResource (Resource resource)
@@ -400,9 +398,9 @@
     /**
      * Check if this jar:file: resource is contained in the
      * named resource. Eg <code>jar:file:///a/b/c/foo.jar!/x.html</code> isContainedIn <code>file:///a/b/c/foo.jar</code>
-     * @param resource
+     * @param resource the resource to test for
      * @return true if resource is contained in the named resource
-     * @throws MalformedURLException
+     * @throws MalformedURLException if unable to process is contained due to invalid URL format
      */
     @Override
     public boolean isContainedIn (Resource resource) 
@@ -418,11 +416,3 @@
         return url.sameFile(resource.getURL());     
     }
 }
-
-
-
-
-
-
-
-
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java
index 47eb108..b1347ec 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java
@@ -26,6 +26,7 @@
 import java.io.OutputStream;
 import java.net.JarURLConnection;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
@@ -156,9 +157,10 @@
       
         if (LOG.isDebugEnabled()) 
             LOG.debug("Extracting entry = "+subEntryName+" from jar "+jarFileURL);
-        
-        try (InputStream is = jarFileURL.openConnection().getInputStream();
-                JarInputStream jin = new JarInputStream(is))
+        URLConnection c = jarFileURL.openConnection();
+        c.setUseCaches(false);
+        try (InputStream is = c.getInputStream();
+             JarInputStream jin = new JarInputStream(is))
         {
             JarEntry entry;
             boolean shouldExtract;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
index 5d0c7bc..7044923 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
@@ -33,12 +33,13 @@
 import java.nio.file.InvalidPathException;
 import java.nio.file.LinkOption;
 import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
 import java.nio.file.StandardOpenOption;
 import java.nio.file.attribute.FileTime;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
@@ -48,22 +49,134 @@
 public class PathResource extends Resource
 {
     private static final Logger LOG = Log.getLogger(PathResource.class);
-
+    private final static LinkOption NO_FOLLOW_LINKS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+    private final static LinkOption FOLLOW_LINKS[] = new LinkOption[] {};
+    
     private final Path path;
+    private final Path alias;
     private final URI uri;
-    private LinkOption linkOptions[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+    
+    private static final Path checkAliasPath(final Path path)
+    {
+        Path abs = path;
+        if (!abs.isAbsolute())
+        {
+            abs = path.toAbsolutePath();
+        }
 
+        try
+        {
+            if (Files.isSymbolicLink(path))
+                return Files.readSymbolicLink(path);
+            if (Files.exists(path))
+            {
+                Path real = abs.toRealPath(FOLLOW_LINKS);
+                
+                /*
+                 * If the real path is not the same as the absolute path
+                 * then we know that the real path is the alias for the
+                 * provided path.
+                 *
+                 * For OS's that are case insensitive, this should
+                 * return the real (on-disk / case correct) version
+                 * of the path.
+                 *
+                 * We have to be careful on Windows and OSX.
+                 * 
+                 * Assume we have the following scenario
+                 *   Path a = new File("foo").toPath();
+                 *   Files.createFile(a);
+                 *   Path b = new File("FOO").toPath();
+                 * 
+                 * There now exists a file called "foo" on disk.
+                 * Using Windows or OSX, with a Path reference of
+                 * "FOO", "Foo", "fOO", etc.. means the following
+                 * 
+                 *                        |  OSX    |  Windows   |  Linux
+                 * -----------------------+---------+------------+---------
+                 * Files.exists(a)        |  True   |  True      |  True
+                 * Files.exists(b)        |  True   |  True      |  False
+                 * Files.isSameFile(a,b)  |  True   |  True      |  False
+                 * a.equals(b)            |  False  |  True      |  False
+                 * 
+                 * See the javadoc for Path.equals() for details about this FileSystem
+                 * behavior difference
+                 * 
+                 * We also cannot rely on a.compareTo(b) as this is roughly equivalent
+                 * in implementation to a.equals(b)
+                 */
+                
+                int absCount = abs.getNameCount();
+                int realCount = real.getNameCount();
+                if (absCount != realCount)
+                {
+                    // different number of segments
+                    return real;
+                }
+                
+                // compare each segment of path, backwards
+                for (int i = realCount-1; i >= 0; i--)
+                {
+                    if (!abs.getName(i).toString().equals(real.getName(i).toString()))
+                    {
+                        return real;
+                    }
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            LOG.ignore(e);
+        }
+        catch (Exception e)
+        {
+            LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(),path);
+        }
+        return null;
+    }
+
+    /**
+     * Construct a new PathResource from a File object.
+     * <p>
+     * An invocation of this convenience constructor of the form.
+     * </p>
+     * <pre>
+     * new PathResource(file);
+     * </pre>
+     * <p>
+     * behaves in exactly the same way as the expression
+     * </p>
+     * <pre>
+     * new PathResource(file.toPath());
+     * </pre>
+
+     * @param file the file to use
+     */
     public PathResource(File file)
     {
         this(file.toPath());
     }
 
+    /**
+     * Construct a new PathResource from a Path object.
+     * 
+     * @param path the path to use
+     */
     public PathResource(Path path)
     {
-        this.path = path;
+        this.path = path.toAbsolutePath();
         this.uri = this.path.toUri();
+        this.alias = checkAliasPath(path);
     }
 
+    /**
+     * Construct a new PathResource from a URI object.
+     * <p>
+     * Must be an absolute URI using the <code>file</code> scheme.
+     * 
+     * @param uri the URI to build this PathResource from.
+     * @throws IOException if unable to construct the PathResource from the URI.
+     */
     public PathResource(URI uri) throws IOException
     {
         if (!uri.isAbsolute())
@@ -95,19 +208,51 @@
             throw new IOException("Unable to build Path from: " + uri,e);
         }
 
-        this.path = path;
+        this.path = path.toAbsolutePath();
         this.uri = path.toUri();
+        this.alias = checkAliasPath(path);
     }
 
+    /**
+     * Create a new PathResource from a provided URL object.
+     * <p>
+     * An invocation of this convenience constructor of the form.
+     * </p>
+     * <pre>
+     * new PathResource(url);
+     * </pre>
+     * <p>
+     * behaves in exactly the same way as the expression
+     * </p>
+     * <pre>
+     * new PathResource(url.toURI());
+     * </pre>
+     * 
+     * @param url the url to attempt to create PathResource from
+     * @throws IOException if URL doesn't point to a location that can be transformed to a PathResource
+     * @throws URISyntaxException if the provided URL was malformed
+     */
     public PathResource(URL url) throws IOException, URISyntaxException
     {
         this(url.toURI());
     }
 
     @Override
-    public Resource addPath(String apath) throws IOException, MalformedURLException
+    public Resource addPath(final String subpath) throws IOException, MalformedURLException
     {
-        return new PathResource(this.path.getFileSystem().getPath(path.toString(), apath));
+        String cpath = URIUtil.canonicalPath(subpath);
+
+        if ((cpath == null) || (cpath.length() == 0))
+            throw new MalformedURLException();
+
+        if ("/".equals(cpath))
+            return this;
+
+        // subpaths are always under PathResource
+        // compensate for input subpaths like "/subdir"
+        // where default resolve behavior would be
+        // to treat that like an absolute path
+        return new PathResource(this.path.getFileSystem().getPath(path.toString(), subpath));
     }
 
     @Override
@@ -163,7 +308,7 @@
     @Override
     public boolean exists()
     {
-        return Files.exists(path,linkOptions);
+        return Files.exists(path,NO_FOLLOW_LINKS);
     }
 
     @Override
@@ -172,9 +317,12 @@
         return path.toFile();
     }
 
-    public boolean getFollowLinks()
+    /**
+     * @return the {@link Path} of the resource
+     */
+    public Path getPath()
     {
-        return (linkOptions != null) && (linkOptions.length > 0) && (linkOptions[0] == LinkOption.NOFOLLOW_LINKS);
+        return path;
     }
 
     @Override
@@ -233,7 +381,7 @@
     @Override
     public boolean isDirectory()
     {
-        return Files.isDirectory(path,linkOptions);
+        return Files.isDirectory(path,FOLLOW_LINKS);
     }
 
     @Override
@@ -241,7 +389,7 @@
     {
         try
         {
-            FileTime ft = Files.getLastModifiedTime(path,linkOptions);
+            FileTime ft = Files.getLastModifiedTime(path,FOLLOW_LINKS);
             return ft.toMillis();
         }
         catch (IOException e)
@@ -266,24 +414,25 @@
     }
 
     @Override
+    public boolean isAlias()
+    {
+        return this.alias!=null;
+    }
+    
+    /**
+     * The Alias as a Path.
+     * 
+     * @return the alias as a path.
+     */
+    public Path getAliasPath()
+    {
+        return this.alias;
+    }
+    
+    @Override
     public URI getAlias()
     {
-        if (Files.isSymbolicLink(path))
-        {
-            try
-            {
-                return path.toRealPath().toUri();
-            }
-            catch (IOException e)
-            {
-                LOG.debug(e);
-                return null;
-            }
-        }
-        else
-        {
-            return null;
-        }
+        return this.alias==null?null:this.alias.toUri();
     }
 
     @Override
@@ -325,8 +474,8 @@
             PathResource destRes = (PathResource)dest;
             try
             {
-                Path result = Files.move(path,destRes.path,StandardCopyOption.ATOMIC_MOVE);
-                return Files.exists(result,linkOptions);
+                Path result = Files.move(path,destRes.path);
+                return Files.exists(result,NO_FOLLOW_LINKS);
             }
             catch (IOException e)
             {
@@ -340,15 +489,22 @@
         }
     }
 
-    public void setFollowLinks(boolean followLinks)
+    @Override
+    public void copyTo(File destination) throws IOException
     {
-        if (followLinks)
+        if (isDirectory())
         {
-            linkOptions = new LinkOption[0];
+            IO.copyDir(this.path.toFile(),destination);
         }
         else
         {
-            linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+            Files.copy(this.path,destination.toPath());
         }
     }
+
+    @Override
+    public String toString()
+    {
+        return this.uri.toASCIIString();
+    }
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index 7c9c8ec..df68961 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -39,6 +39,7 @@
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.UrlEncoded;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
@@ -61,7 +62,7 @@
     /**
      * Change the default setting for url connection caches.
      * Subsequent URLConnections will use this default.
-     * @param useCaches
+     * @param useCaches true to enable URL connection caches, false otherwise.
      */
     public static void setDefaultUseCaches (boolean useCaches)
     {
@@ -113,8 +114,7 @@
         {
             try
             {
-                FileResource fileResource= new FileResource(url);
-                return fileResource;
+                return new PathResource(url);
             }
             catch(Exception e)
             {
@@ -178,7 +178,7 @@
                         resource=resource.substring(2);
                     
                     File file=new File(resource).getCanonicalFile();
-                    return new FileResource(file);
+                    return new PathResource(file.toPath());
                 }
                 catch(Exception e2)
                 {
@@ -199,7 +199,7 @@
     /* ------------------------------------------------------------ */
     public static Resource newResource(File file)
     {
-        return new FileResource(file);
+        return new PathResource(file.toPath());
     }
 
     /* ------------------------------------------------------------ */
@@ -258,6 +258,8 @@
 
     /* ------------------------------------------------------------ */
     /** Find a classpath resource.
+     * @param resource the relative name of the resource
+     * @return Resource or null
      */
     public static Resource newClassPathResource(String resource)
     {
@@ -321,43 +323,52 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns true if the respresened resource exists.
+     * @return true if the represented resource exists.
      */
     public abstract boolean exists();
     
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns true if the respresenetd resource is a container/directory.
-     * If the resource is not a file, resources ending with "/" are
+     * @return true if the represented resource is a container/directory.
+     * if the resource is not a file, resources ending with "/" are
      * considered directories.
      */
     public abstract boolean isDirectory();
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns the last modified time
+     * Time resource was last modified.
+     * 
+     * @return the last modified time as milliseconds since unix epoch
      */
     public abstract long lastModified();
 
 
     /* ------------------------------------------------------------ */
     /**
-     * Return the length of the resource
+     * Length of the resource.
+     * 
+     * @return the length of the resource
      */
     public abstract long length();
     
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns an URL representing the given resource
+     * URL representing the resource.
+     * 
+     * @return an URL representing the given resource
+     * @deprecated use {{@link #getURI()}.toURL() instead.
      */
-    // TODO: should deprecate this one and only use getURI()
+    @Deprecated
     public abstract URL getURL();
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns an URI representing the given resource
+     * URI representing the resource.
+     * 
+     * @return an URI representing the given resource
      */
     public URI getURI()
     {
@@ -374,8 +385,11 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns an File representing the given resource or NULL if this
+     * File representing the given resource.
+     * 
+     * @return an File representing the given resource or NULL if this
      * is not possible.
+     * @throws IOException if unable to get the resource due to permissions 
      */
     public abstract File getFile()
         throws IOException;
@@ -383,47 +397,60 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns the name of the resource
+     * The name of the resource.
+     * 
+     * @return the name of the resource
      */
     public abstract String getName();
     
 
     /* ------------------------------------------------------------ */
     /**
-     * Returns an input stream to the resource
+     * Input stream to the resource
+     * 
+     * @return an input stream to the resource
+     * @throws IOException if unable to open the input stream
      */
     public abstract InputStream getInputStream()
-        throws java.io.IOException;
+        throws IOException;
     
     /* ------------------------------------------------------------ */
     /**
-     * Returns an readable bytechannel to the resource or null if one is not available.
+     * Readable ByteChannel for the resource.
+     * 
+     * @return an readable bytechannel to the resource or null if one is not available.
+     * @throws IOException if unable to open the readable bytechannel for the resource.
      */
     public abstract ReadableByteChannel getReadableByteChannel()
-        throws java.io.IOException;
+        throws IOException;
 
     /* ------------------------------------------------------------ */
     /**
      * Deletes the given resource
+     * @return true if resource was found and successfully deleted, false if resource didn't exist or was unable to
+     * be deleted.
+     * @throws SecurityException if unable to delete due to permissions 
      */
-    // TODO: can throw IOException
     public abstract boolean delete()
         throws SecurityException;
     
     /* ------------------------------------------------------------ */
     /**
      * Rename the given resource
+     * @param dest the destination name for the resource
+     * @return true if the resource was renamed, false if the resource didn't exist or was unable to be renamed.
+     * @throws SecurityException if unable to rename due to permissions
      */
-    // TODO: can throw IOException
-    public abstract boolean renameTo( Resource dest)
+    public abstract boolean renameTo(Resource dest)
         throws SecurityException;
     
     /* ------------------------------------------------------------ */
     /**
-     * Returns a list of resource names contained in the given resource
-     * The resource names are not URL encoded.
+     * list of resource names contained in the given resource.
+     * 
+     * @return a list of resource names contained in the given resource.
+     * Note: The resource names are not URL encoded.
      */
-    // TODO: can throw IOException
     public abstract String[] list();
 
     /* ------------------------------------------------------------ */
@@ -431,6 +458,9 @@
      * Returns the resource contained inside the current resource with the
      * given name.
      * @param path The path segment to add, which is not encoded
+     * @return the Resource for the resolved path within this Resource.
+     * @throws IOException if unable to resolve the path
+     * @throws MalformedURLException if the resolution of the path fails because the input path parameter is malformed.
      */
     public abstract Resource addPath(String path)
         throws IOException,MalformedURLException;
@@ -458,24 +488,40 @@
 
     /* ------------------------------------------------------------ */
     /** 
-     * @deprecated
+     * @param uri the uri to encode
+     * @return null (this is deprecated)
+     * @deprecated use {@link URIUtil} or {@link UrlEncoded} instead
      */
+    @Deprecated
     public String encode(String uri)
     {
         return null;
     }
         
     /* ------------------------------------------------------------ */
+    // FIXME: this appears to not be used
+    @SuppressWarnings("javadoc")
     public Object getAssociate()
     {
         return _associate;
     }
 
     /* ------------------------------------------------------------ */
+    // FIXME: this appear to not be used
+    @SuppressWarnings("javadoc")
     public void setAssociate(Object o)
     {
         _associate=o;
     }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return true if this Resource is an alias to another real Resource
+     */
+    public boolean isAlias()
+    {
+        return getAlias()!=null;
+    }
     
     /* ------------------------------------------------------------ */
     /**
@@ -491,6 +537,7 @@
      * @param base The base URL
      * @param parent True if the parent directory should be included
      * @return String of HTML
+     * @throws IOException if unable to get the list of resources as HTML
      */
     public String getListHTML(String base,boolean parent)
         throws IOException
@@ -618,9 +665,10 @@
     
     /* ------------------------------------------------------------ */
     /** 
-     * @param out 
+     * @param out the output stream to write to 
      * @param start First byte to write
      * @param count Bytes to write or -1 for all of them.
+     * @throws IOException if unable to copy the Resource to the output
      */
     public void writeTo(OutputStream out,long start,long count)
         throws IOException
@@ -636,11 +684,20 @@
     }    
     
     /* ------------------------------------------------------------ */
+    /**
+     * Copy the Resource to the new destination file.
+     * <p>
+     * Will not replace existing destination file.
+     * 
+     * @param destination the destination file to create
+     * @throws IOException if unable to copy the resource
+     */
     public void copyTo(File destination)
         throws IOException
     {
         if (destination.exists())
-            throw new IllegalArgumentException(destination+" exists");
+            throw new IllegalArgumentException(destination + " exists");
+        
         try (OutputStream out = new FileOutputStream(destination))
         {
             writeTo(out,0,-1);
@@ -648,8 +705,18 @@
     }
 
     /* ------------------------------------------------------------ */
+    /**
+     * Generate a weak ETag reference for this Resource.
+     * 
+     * @return the weak ETag reference for this resource.
+     */
     public String getWeakETag()
     {
+        return getWeakETag("");
+    }
+    
+    public String getWeakETag(String suffix)
+    {
         try
         {
             StringBuilder b = new StringBuilder(32);
@@ -663,6 +730,7 @@
             
             B64Code.encode(lastModified()^lhash,b);
             B64Code.encode(length()^lhash,b);
+            b.append(suffix);
             b.append('"');
             return b.toString();
         } 
@@ -704,7 +772,7 @@
     /** Generate a properly encoded URL from a {@link File} instance.
      * @param file Target file. 
      * @return URL of the target file.
-     * @throws MalformedURLException 
+     * @throws MalformedURLException if unable to convert File to URL
      */
     public static URL toURL(File file) throws MalformedURLException
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java
index 178b156..f2d31d9 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/ResourceCollection.java
@@ -248,10 +248,10 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @param path
+     * @param path the path to look for
      * @return the resource(file) if found, returns a list of resource dirs if its a dir, else null.
-     * @throws IOException
-     * @throws MalformedURLException
+     * @throws IOException if unable to look for path
+     * @throws MalformedURLException if failed to look for path due to url issue
      */
     protected Object findResource(String path) throws IOException, MalformedURLException
     {        
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
index 5bba2c4..4b84495 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
@@ -221,9 +221,11 @@
      * the url protocol. Eg JarURLConnection does not reuse inputstreams.
      * 
      * @param resetConnection if true the connection field is set to null
+     * @return the inputstream for this resource
+     * @throws IOException if unable to open the input stream
      */
     protected synchronized InputStream getInputStream(boolean resetConnection)
-        throws java.io.IOException
+        throws IOException
     {
         if (!checkConnection())
             throw new IOException( "Invalid resource");
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateUtils.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateUtils.java
index 86a4f9e..f7a8afe 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateUtils.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateUtils.java
@@ -29,37 +29,27 @@
 public class CertificateUtils
 {
     /* ------------------------------------------------------------ */
-    public static KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
+    public static KeyStore getKeyStore(Resource store, String storeType, String storeProvider, String storePassword) throws Exception
     {
         KeyStore keystore = null;
 
-        if (storeStream != null || storePath != null)
+        if (store != null)
         {
-            InputStream inStream = storeStream;
-            try
+            if (storeProvider != null)
             {
-                if (inStream == null)
-                {
-                    inStream = Resource.newResource(storePath).getInputStream();
-                }
-                
-                if (storeProvider != null)
-                {
-                    keystore = KeyStore.getInstance(storeType, storeProvider);
-                }
-                else
-                {
-                    keystore = KeyStore.getInstance(storeType);
-                }
-    
-                keystore.load(inStream, storePassword == null ? null : storePassword.toCharArray());
+                keystore = KeyStore.getInstance(storeType, storeProvider);
             }
-            finally
+            else
             {
-                if (inStream != null)
-                {
-                    inStream.close();
-                }
+                keystore = KeyStore.getInstance(storeType);
+            }
+            
+            if (!store.exists())
+                throw new IllegalStateException("no valid keystore");
+            
+            try (InputStream inStream = store.getInputStream())
+            {
+                keystore.load(inStream, storePassword == null ? null : storePassword.toCharArray());
             }
         }
         
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateValidator.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateValidator.java
index 0093b20..3e0095a 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateValidator.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/CertificateValidator.java
@@ -72,8 +72,8 @@
     /**
      * creates an instance of the certificate validator 
      *
-     * @param trustStore 
-     * @param crls
+     * @param trustStore the truststore to use 
+     * @param crls the Certificate Revocation List to use 
      */
     public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
     {
@@ -89,8 +89,8 @@
     /**
      * validates all aliases inside of a given keystore
      * 
-     * @param keyStore
-     * @throws CertificateException
+     * @param keyStore the keystore to validate
+     * @throws CertificateException if keystore error and unable to validate 
      */
     public void validate( KeyStore keyStore ) throws CertificateException
     {
@@ -116,10 +116,10 @@
     /**
      * validates a specific alias inside of the keystore being passed in
      * 
-     * @param keyStore
-     * @param keyAlias
+     * @param keyStore the keystore to validate
+     * @param keyAlias the keyalias in the keystore to valid with
      * @return the keyAlias if valid
-     * @throws CertificateException
+     * @throws CertificateException if keystore error and unable to validate
      */
     public String validate(KeyStore keyStore, String keyAlias) throws CertificateException
     {
@@ -146,9 +146,9 @@
     /**
      * validates a specific certificate inside of the keystore being passed in
      * 
-     * @param keyStore
-     * @param cert
-     * @throws CertificateException
+     * @param keyStore the keystore to validate against
+     * @param cert the certificate to validate
+     * @throws CertificateException if keystore error and unable to validate
      */
     public void validate(KeyStore keyStore, Certificate cert) throws CertificateException
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Constraint.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Constraint.java
index daf3433..6328a6f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Constraint.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Constraint.java
@@ -21,13 +21,10 @@
 import java.io.Serializable;
 import java.util.Arrays;
 
-/* ------------------------------------------------------------ */
 /**
  * Constraint
  * 
  * Describe an auth and/or data constraint.
- * 
- * 
  */
 public class Constraint implements Cloneable, Serializable
 {
@@ -93,10 +90,10 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * Conveniance Constructor.
+     * Convenience Constructor.
      * 
-     * @param name
-     * @param role
+     * @param name the name
+     * @param role the role
      */
     public Constraint(String name, String role)
     {
@@ -113,7 +110,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param name
+     * @param name the name
      */
     public void setName(String name)
     {
@@ -172,7 +169,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param role
+     * @param role the role
      * @return True if the constraint contains the role.
      */
     public boolean hasRole(String role)
@@ -212,7 +209,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @param c Data constrain indicator: 0=DC+NONE, 1=DC_INTEGRAL &
+     * @param c Data constrain indicator: 0=DC+NONE, 1=DC_INTEGRAL &amp;
      *                2=DC_CONFIDENTIAL
      */
     public void setDataConstraint(int c)
@@ -223,7 +220,7 @@
 
     /* ------------------------------------------------------------ */
     /**
-     * @return Data constrain indicator: 0=DC+NONE, 1=DC_INTEGRAL &
+     * @return Data constrain indicator: 0=DC+NONE, 1=DC_INTEGRAL &amp;
      *         2=DC_CONFIDENTIAL
      */
     public int getDataConstraint()
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Password.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Password.java
index 3bd237b..9b4174e 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Password.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Password.java
@@ -245,15 +245,11 @@
         return new Password(passwd);
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @param arg
-     */
     public static void main(String[] arg)
     {
         if (arg.length != 1 && arg.length != 2)
         {
-            System.err.println("Usage - java org.eclipse.jetty.security.Password [<user>] <password>");
+            System.err.println("Usage - java " + Password.class.getName() + " [<user>] <password>");
             System.err.println("If the password is ?, the user will be prompted for the password");
             System.exit(1);
         }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java
index 53c7ca0..8e8f677 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java
@@ -25,106 +25,123 @@
 
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.X509ExtendedKeyManager;
-import javax.net.ssl.X509KeyManager;
 
-
-/* ------------------------------------------------------------ */
 /**
- * KeyManager to select a key with desired alias
- * while delegating processing to specified KeyManager
- * Can be used both with server and client sockets
+ * <p>An {@link X509ExtendedKeyManager} that select a key with desired alias,
+ * delegating other processing to a nested X509ExtendedKeyManager.</p>
+ * <p>Can be used both with server and client sockets.</p>
  */
 public class AliasedX509ExtendedKeyManager extends X509ExtendedKeyManager
 {
-    private String _keyAlias;
-    private X509KeyManager _keyManager;
+    private final String _alias;
+    private final X509ExtendedKeyManager _delegate;
 
-    /* ------------------------------------------------------------ */
-    /**
-     * Construct KeyManager instance
-     * @param keyAlias Alias of the key to be selected
-     * @param keyManager Instance of KeyManager to be wrapped
-     * @throws Exception
-     */
-    public AliasedX509ExtendedKeyManager(String keyAlias, X509KeyManager keyManager) throws Exception
+    public AliasedX509ExtendedKeyManager(X509ExtendedKeyManager keyManager, String keyAlias)
     {
-        _keyAlias = keyAlias;
-        _keyManager = keyManager;
+        _alias = keyAlias;
+        _delegate = keyManager;
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket)
-     */
+    public X509ExtendedKeyManager getDelegate()
+    {
+        return _delegate;
+    }
+
+    @Override
     public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
     {
-        return _keyAlias == null ? _keyManager.chooseClientAlias(keyType, issuers, socket) : _keyAlias;
+        if (_alias==null)
+            return _delegate.chooseClientAlias(keyType,issuers,socket);
+
+        for (String kt : keyType)
+        {
+            String[] aliases = _delegate.getClientAliases(kt,issuers);
+            if (aliases!=null)
+            {
+                for (String a:aliases)
+                    if (_alias.equals(a))
+                        return _alias;
+            }
+        }
+
+        return null;
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket)
-     */
+    @Override
     public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
     {
-        return _keyAlias == null ? _keyManager.chooseServerAlias(keyType, issuers, socket) : _keyAlias;
+        if (_alias==null)
+            return _delegate.chooseServerAlias(keyType,issuers,socket);
+
+        String[] aliases = _delegate.getServerAliases(keyType,issuers);
+        if (aliases!=null)
+        {
+            for (String a:aliases)
+                if (_alias.equals(a))
+                    return _alias;
+        }
+
+        return null;
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getClientAliases(java.lang.String, java.security.Principal[])
-     */
+    @Override
     public String[] getClientAliases(String keyType, Principal[] issuers)
     {
-        return _keyManager.getClientAliases(keyType, issuers);
+        return _delegate.getClientAliases(keyType, issuers);
     }
 
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getServerAliases(java.lang.String, java.security.Principal[])
-     */
+    @Override
     public String[] getServerAliases(String keyType, Principal[] issuers)
     {
-        return _keyManager.getServerAliases(keyType, issuers);
+        return _delegate.getServerAliases(keyType, issuers);
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getCertificateChain(java.lang.String)
-     */
+    @Override
     public X509Certificate[] getCertificateChain(String alias)
     {
-        return _keyManager.getCertificateChain(alias);
+        return _delegate.getCertificateChain(alias);
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getPrivateKey(java.lang.String)
-     */
+    @Override
     public PrivateKey getPrivateKey(String alias)
     {
-        return _keyManager.getPrivateKey(alias);
+        return _delegate.getPrivateKey(alias);
     }
 
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509ExtendedKeyManager#chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine)
-     */
     @Override
     public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
     {
-        return _keyAlias == null ? super.chooseEngineServerAlias(keyType,issuers,engine) : _keyAlias;
+        if (_alias==null)
+            return _delegate.chooseEngineServerAlias(keyType,issuers,engine);
+
+        String[] aliases = _delegate.getServerAliases(keyType,issuers);
+        if (aliases!=null)
+        {
+            for (String a:aliases)
+                if (_alias.equals(a))
+                    return _alias;
+        }
+
+        return null;
     }
 
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509ExtendedKeyManager#chooseEngineClientAlias(String[], Principal[], SSLEngine)
-     */
     @Override
     public String chooseEngineClientAlias(String keyType[], Principal[] issuers, SSLEngine engine)
     {
-        return _keyAlias == null ? super.chooseEngineClientAlias(keyType,issuers,engine) : _keyAlias;
+        if (_alias==null)
+            return _delegate.chooseEngineClientAlias(keyType,issuers,engine);
+
+        for (String kt : keyType)
+        {
+            String[] aliases = _delegate.getClientAliases(kt,issuers);
+            if (aliases!=null)
+            {
+                for (String a:aliases)
+                    if (_alias.equals(a))
+                        return _alias;
+            }
+        }
+
+        return null;
     }
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java
deleted file mode 100644
index 8da8f68..0000000
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.ssl;
-
-import java.net.Socket;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.X509KeyManager;
-
-
-/* ------------------------------------------------------------ */
-/**
- * KeyManager to select a key with desired alias
- * while delegating processing to specified KeyManager
- * Can be used both with server and client sockets
- */
-public class AliasedX509KeyManager implements X509KeyManager
-{
-    private String _keyAlias;
-    private X509KeyManager _keyManager;
-
-    /* ------------------------------------------------------------ */
-    /**
-     * Construct KeyManager instance
-     * @param keyAlias Alias of the key to be selected
-     * @param keyManager Instance of KeyManager to be wrapped
-     * @throws Exception
-     */
-    public AliasedX509KeyManager(String keyAlias, X509KeyManager keyManager) throws Exception
-    {
-        _keyAlias = keyAlias;
-        _keyManager = keyManager;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket)
-     */
-    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
-    {
-        return _keyAlias == null ? _keyManager.chooseClientAlias(keyType, issuers, socket) : _keyAlias;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket)
-     */
-    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
-    {
-        return _keyAlias == null ?_keyManager.chooseServerAlias(keyType, issuers, socket) : _keyAlias;
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getClientAliases(java.lang.String, java.security.Principal[])
-     */
-    public String[] getClientAliases(String keyType, Principal[] issuers)
-    {
-        return _keyManager.getClientAliases(keyType, issuers);
-    }
-
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getServerAliases(java.lang.String, java.security.Principal[])
-     */
-    public String[] getServerAliases(String keyType, Principal[] issuers)
-    {
-        return _keyManager.getServerAliases(keyType, issuers);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getCertificateChain(java.lang.String)
-     */
-    public X509Certificate[] getCertificateChain(String alias)
-    {
-        return _keyManager.getCertificateChain(alias);
-    }
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @see javax.net.ssl.X509KeyManager#getPrivateKey(java.lang.String)
-     */
-    public PrivateKey getPrivateKey(String alias)
-    {
-        return _keyManager.getPrivateKey(alias);
-    }
-}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SniX509ExtendedKeyManager.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SniX509ExtendedKeyManager.java
new file mode 100644
index 0000000..a4f5563
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SniX509ExtendedKeyManager.java
@@ -0,0 +1,157 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.ssl;
+
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedKeyManager;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>A {@link X509ExtendedKeyManager} that selects a key with an alias
+ * retrieved from SNI information, delegating other processing to a nested X509ExtendedKeyManager.</p>
+ * <p>Can only be used on server side.</p>
+ */
+public class SniX509ExtendedKeyManager extends X509ExtendedKeyManager
+{
+    public static final String SNI_X509 = "org.eclipse.jetty.util.ssl.snix509";
+    private static final String NO_MATCHERS = "no_matchers";
+    private static final Logger LOG = Log.getLogger(SniX509ExtendedKeyManager.class);
+
+    private final X509ExtendedKeyManager _delegate;
+
+    public SniX509ExtendedKeyManager(X509ExtendedKeyManager keyManager)
+    {
+        _delegate = keyManager;
+    }
+
+    @Override
+    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
+    {
+        return _delegate.chooseClientAlias(keyType,issuers,socket);
+    }
+
+    @Override
+    public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
+    {
+        return _delegate.chooseEngineClientAlias(keyType,issuers,engine);
+    }
+
+    protected String chooseServerAlias(String keyType, Principal[] issuers, Collection<SNIMatcher> matchers, SSLSession session)
+    {
+        // Look for the aliases that are suitable for the keytype and issuers
+        String[] aliases = _delegate.getServerAliases(keyType,issuers);
+        if (aliases==null || aliases.length==0)
+            return null;
+
+        // Look for the SNI information.
+        String host=null;
+        X509 x509=null;
+        if (matchers!=null)
+        {
+            for (SNIMatcher m : matchers)
+            {
+                if (m instanceof SslContextFactory.AliasSNIMatcher)
+                {
+                    SslContextFactory.AliasSNIMatcher matcher = (SslContextFactory.AliasSNIMatcher)m;
+                    host=matcher.getHost();
+                    x509=matcher.getX509();
+                    break;
+                }
+            }
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("Matched {} with {} from {}",host,x509,Arrays.asList(aliases));
+
+        // Check if the SNI selected alias is allowable
+        if (x509!=null)
+        {
+            for (String a:aliases)
+            {
+                if (a.equals(x509.getAlias()))
+                {
+                    session.putValue(SNI_X509,x509);
+                    return a;
+                }
+            }
+            return null;
+        }
+        return NO_MATCHERS;
+    }
+
+    @Override
+    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
+    {
+        SSLSocket sslSocket = (SSLSocket)socket;
+
+        String alias = chooseServerAlias(keyType,issuers,sslSocket.getSSLParameters().getSNIMatchers(),sslSocket.getHandshakeSession());
+        if (alias==NO_MATCHERS)
+            alias=_delegate.chooseServerAlias(keyType,issuers,socket);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Chose alias {}/{} on {}",alias,keyType,socket);
+        return alias;
+    }
+
+    @Override
+    public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
+    {
+        String alias = chooseServerAlias(keyType,issuers,engine.getSSLParameters().getSNIMatchers(),engine.getHandshakeSession());
+        if (alias==NO_MATCHERS)
+            alias=_delegate.chooseEngineServerAlias(keyType,issuers,engine);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Chose alias {}/{} on {}",alias,keyType,engine);
+        return alias;
+    }
+
+    @Override
+    public X509Certificate[] getCertificateChain(String alias)
+    {
+        return _delegate.getCertificateChain(alias);
+    }
+
+    @Override
+    public String[] getClientAliases(String keyType, Principal[] issuers)
+    {
+        return _delegate.getClientAliases(keyType,issuers);
+    }
+
+    @Override
+    public PrivateKey getPrivateKey(String alias)
+    {
+        return _delegate.getPrivateKey(alias);
+    }
+
+    @Override
+    public String[] getServerAliases(String keyType, Principal[] issuers)
+    {
+        return _delegate.getServerAliases(keyType,issuers);
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java
index edf3789..5025b2d 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java
@@ -19,12 +19,10 @@
 package org.eclipse.jetty.util.ssl;
 
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.security.InvalidParameterException;
+import java.net.MalformedURLException;
 import java.security.KeyStore;
 import java.security.SecureRandom;
 import java.security.Security;
@@ -35,19 +33,26 @@
 import java.security.cert.PKIXBuilderParameters;
 import java.security.cert.X509CertSelector;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.net.ssl.CertPathTrustManagerParameters;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLParameters;
@@ -57,12 +62,13 @@
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.StandardConstants;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509ExtendedKeyManager;
 import javax.net.ssl.X509TrustManager;
 
-import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -78,6 +84,9 @@
  * creates SSL context based on these parameters to be
  * used by the SSL connectors.
  */
+
+/**
+ */
 public class SslContextFactory extends AbstractLifeCycle
 {
     public final static TrustManager[] TRUST_ALL_CERTS = new X509TrustManager[]{new X509TrustManager()
@@ -118,32 +127,41 @@
     /** Included protocols. */
     private final Set<String> _includeProtocols = new LinkedHashSet<>();
 
+    /** Selected protocols. */
+    private String[] _selectedProtocols;
+
     /** Excluded cipher suites. */
     private final Set<String> _excludeCipherSuites = new LinkedHashSet<>();
-    
+
     /** Included cipher suites. */
-    private final Set<String> _includeCipherSuites = new LinkedHashSet<>();
+    private final List<String> _includeCipherSuites = new ArrayList<>();
+    private boolean _useCipherSuitesOrder=true;
+
+    /** Cipher comparator for ordering ciphers */
+    Comparator<String> _cipherComparator;
+
+    /** Selected cipher suites. Combination of includes, excludes, available and ordering */
+    private String[] _selectedCipherSuites;
 
     /** Keystore path. */
-    private String _keyStorePath;
+    private Resource _keyStoreResource;
     /** Keystore provider name */
     private String _keyStoreProvider;
     /** Keystore type */
     private String _keyStoreType = "JKS";
-    /** Keystore input stream */
-    private InputStream _keyStoreInputStream;
 
     /** SSL certificate alias */
     private String _certAlias;
+    private final Map<String,X509> _aliasX509 = new HashMap<>();
+    private final Map<String,X509> _certHosts = new HashMap<>();
+    private final Map<String,X509> _certWilds = new HashMap<>();
 
     /** Truststore path */
-    private String _trustStorePath;
+    private Resource _trustStoreResource;
     /** Truststore provider name */
     private String _trustStoreProvider;
     /** Truststore type */
     private String _trustStoreType = "JKS";
-    /** Truststore input stream */
-    private InputStream _trustStoreInputStream;
 
     /** Set to true if client certificate authentication is required */
     private boolean _needClientAuth = false;
@@ -151,11 +169,11 @@
     private boolean _wantClientAuth = false;
 
     /** Keystore password */
-    private transient Password _keyStorePassword;
+    private Password _keyStorePassword;
     /** Key manager password */
-    private transient Password _keyManagerPassword;
+    private Password _keyManagerPassword;
     /** Truststore password */
-    private transient Password _trustStorePassword;
+    private Password _trustStorePassword;
 
     /** SSL provider name */
     private String _sslProvider;
@@ -185,9 +203,9 @@
     private String _ocspResponderURL;
 
     /** SSL keystore */
-    private KeyStore _keyStore;
+    private KeyStore _setKeyStore;
     /** SSL truststore */
-    private KeyStore _trustStore;
+    private KeyStore _setTrustStore;
     /** Set to true to enable SSL Session caching */
     private boolean _sessionCachingEnabled = true;
     /** SSL session cache size */
@@ -196,7 +214,7 @@
     private int _sslSessionTimeout;
 
     /** SSL context */
-    private SSLContext _context;
+    private SSLContext _setContext;
 
     /** EndpointIdentificationAlgorithm - when set to "HTTPS" hostname verification will be enabled */
     private String _endpointIdentificationAlgorithm = null;
@@ -207,6 +225,11 @@
     /** Whether TLS renegotiation is allowed */
     private boolean _renegotiationAllowed = true;
 
+    protected Factory _factory;
+
+
+
+
     /**
      * Construct an instance of SslContextFactory
      * Default constructor for use in XmlConfiguration files
@@ -226,7 +249,15 @@
     {
         setTrustAll(trustAll);
         addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3");
-    }
+        setExcludeCipherSuites(
+                "SSL_RSA_WITH_DES_CBC_SHA",
+                "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+                "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+                "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+                "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+}
 
     /**
      * Construct an instance of SslContextFactory
@@ -234,7 +265,39 @@
      */
     public SslContextFactory(String keyStorePath)
     {
-        _keyStorePath = keyStorePath;
+        setKeyStorePath(keyStorePath);
+    }
+
+    public String[] getSelectedProtocols()
+    {
+        return Arrays.copyOf(_selectedProtocols,_selectedProtocols.length);
+    }
+
+    public String[] getSelectedCipherSuites()
+    {
+        return Arrays.copyOf(_selectedCipherSuites,_selectedCipherSuites.length);
+    }
+
+    public Comparator<String> getCipherComparator()
+    {
+        return _cipherComparator;
+    }
+
+    public void setCipherComparator(Comparator<String> cipherComparator)
+    {
+        if (cipherComparator!=null)
+            setUseCipherSuitesOrder(true);
+        _cipherComparator = cipherComparator;
+    }
+
+    public Set<String> getAliases()
+    {
+        return Collections.unmodifiableSet(_aliasX509.keySet());
+    }
+
+    public X509 getX509(String alias)
+    {
+        return _aliasX509.get(alias);
     }
 
     /**
@@ -244,10 +307,14 @@
     @Override
     protected void doStart() throws Exception
     {
-        if (_context == null)
+        SSLContext context = _setContext;
+        KeyStore keyStore = _setKeyStore;
+        KeyStore trustStore = _setTrustStore;
+
+        if (context == null)
         {
-            if (_keyStore==null && _keyStoreInputStream == null && _keyStorePath == null &&
-                _trustStore==null && _trustStoreInputStream == null && _trustStorePath == null )
+            // Is this an empty factory?
+            if (keyStore==null && _keyStoreResource == null && trustStore==null && _trustStoreResource == null )
             {
                 TrustManager[] trust_managers=null;
 
@@ -260,66 +327,93 @@
                 }
 
                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
-                SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
+                context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
                 context.init(null, trust_managers, secureRandom);
-                _context = context;
             }
             else
             {
-                // verify that keystore and truststore
-                // parameters are set up correctly
-                checkKeyStore();
-
-                KeyStore keyStore = loadKeyStore();
-                KeyStore trustStore = loadTrustStore();
+                if (keyStore==null)
+                    keyStore=loadKeyStore(_keyStoreResource);
+                if (trustStore==null)
+                    trustStore=loadTrustStore(_trustStoreResource);
 
                 Collection<? extends CRL> crls = loadCRL(_crlPath);
 
-                if (_validateCerts && keyStore != null)
+                // Look for X.509 certificates to create alias map
+                _certHosts.clear();
+                if (keyStore!=null)
                 {
-                    if (_certAlias == null)
+                    for (String alias : Collections.list(keyStore.aliases()))
                     {
-                        List<String> aliases = Collections.list(keyStore.aliases());
-                        _certAlias = aliases.size() == 1 ? aliases.get(0) : null;
-                    }
+                        Certificate certificate = keyStore.getCertificate(alias);
+                        if (certificate!=null && "X.509".equals(certificate.getType()))
+                        {
+                            X509Certificate x509C = (X509Certificate)certificate;
 
-                    Certificate cert = _certAlias == null?null:keyStore.getCertificate(_certAlias);
-                    if (cert == null)
-                    {
-                        throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
-                    }
+                            // Exclude certificates with special uses
+                            if (X509.isCertSign(x509C))
+                            {
+                                if (LOG.isDebugEnabled())
+                                    LOG.debug("Skipping "+x509C);
+                                continue;
+                            }
+                            X509 x509 = new X509(alias,x509C);
+                            _aliasX509.put(alias,x509);
 
-                    CertificateValidator validator = new CertificateValidator(trustStore, crls);
-                    validator.setMaxCertPathLength(_maxCertPathLength);
-                    validator.setEnableCRLDP(_enableCRLDP);
-                    validator.setEnableOCSP(_enableOCSP);
-                    validator.setOcspResponderURL(_ocspResponderURL);
-                    validator.validate(keyStore, cert);
+                            if (_validateCerts)
+                            {
+                                CertificateValidator validator = new CertificateValidator(trustStore, crls);
+                                validator.setMaxCertPathLength(_maxCertPathLength);
+                                validator.setEnableCRLDP(_enableCRLDP);
+                                validator.setEnableOCSP(_enableOCSP);
+                                validator.setOcspResponderURL(_ocspResponderURL);
+                                validator.validate(keyStore, x509C); // TODO what about truststore?
+                            }
+
+                            LOG.info("x509={} for {}",x509,this);
+
+                            for (String h:x509.getHosts())
+                                _certHosts.put(h,x509);
+                            for (String w:x509.getWilds())
+                                _certWilds.put(w,x509);
+                        }
+                    }
                 }
 
+                // Instantiate key and trust managers
                 KeyManager[] keyManagers = getKeyManagers(keyStore);
                 TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
 
+                // Initialize context
                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
-                SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
+                context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
                 context.init(keyManagers,trustManagers,secureRandom);
-                _context = context;
             }
+        }
 
-            SSLEngine engine = newSSLEngine();
-            if (LOG.isDebugEnabled())
-            {
-                LOG.debug("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
-                LOG.debug("Enabled Ciphers   {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
-            }
+        // select the protocols and ciphers
+        SSLEngine sslEngine=context.createSSLEngine();
+        selectCipherSuites(
+                sslEngine.getEnabledCipherSuites(),
+                sslEngine.getSupportedCipherSuites());
+        selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols());
+
+        _factory = new Factory(keyStore,trustStore,context);
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Selected Protocols {} of {}",Arrays.asList(_selectedProtocols),Arrays.asList(sslEngine.getSupportedProtocols()));
+            LOG.debug("Selected Ciphers   {} of {}",Arrays.asList(_selectedCipherSuites),Arrays.asList(sslEngine.getSupportedCipherSuites()));
         }
     }
 
     @Override
     protected void doStop() throws Exception
     {
-        _context = null;
+        _factory = null;
         super.doStop();
+        _certHosts.clear();
+        _certWilds.clear();
+        _aliasX509.clear();
     }
 
     /**
@@ -426,12 +520,22 @@
         _includeCipherSuites.addAll(Arrays.asList(cipherSuites));
     }
 
+    public boolean isUseCipherSuitesOrder()
+    {
+        return _useCipherSuitesOrder;
+    }
+
+    public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder)
+    {
+        _useCipherSuitesOrder = useCipherSuitesOrder;
+    }
+
     /**
      * @return The file or URL of the SSL Key store.
      */
     public String getKeyStorePath()
     {
-        return _keyStorePath;
+        return _keyStoreResource.toString();
     }
 
     /**
@@ -441,7 +545,14 @@
     public void setKeyStorePath(String keyStorePath)
     {
         checkNotStarted();
-        _keyStorePath = keyStorePath;
+        try
+        {
+            _keyStoreResource = Resource.newResource(keyStorePath);
+        }
+        catch (MalformedURLException e)
+        {
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**
@@ -489,6 +600,11 @@
     }
 
     /**
+     * Set the default certificate Alias.
+     * <p>This can be used if there are multiple non-SNI certificates
+     * to specify the certificate that should be used, or with SNI
+     * certificates to set a certificate to try if no others match
+     * </p>
      * @param certAlias
      *            Alias of SSL certificate for the connector
      */
@@ -499,21 +615,20 @@
     }
 
     /**
-     * @return The file name or URL of the trust store location
-     */
-    public String getTrustStore()
-    {
-        return _trustStorePath;
-    }
-
-    /**
      * @param trustStorePath
      *            The file name or URL of the trust store location
      */
     public void setTrustStorePath(String trustStorePath)
     {
         checkNotStarted();
-        _trustStorePath = trustStorePath;
+        try
+        {
+            _trustStoreResource = Resource.newResource(trustStorePath);
+        }
+        catch (MalformedURLException e)
+        {
+            throw new IllegalArgumentException(e);
+        }
     }
 
     /**
@@ -628,35 +743,70 @@
         _validatePeerCerts = validatePeerCerts;
     }
 
-
     /**
      * @param password
-     *            The password for the key store
+     *            The password for the key store.  If null is passed and
+     *            a keystore is set, then
+     *            the {@link Password#getPassword(String, String, String)} is used to
+     *            obtain a password either from the {@value #PASSWORD_PROPERTY}
+     *            System property or by prompting for manual entry.
      */
     public void setKeyStorePassword(String password)
     {
         checkNotStarted();
-        _keyStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        if (password==null)
+        {
+            if (_keyStoreResource!=null)
+                _keyStorePassword=Password.getPassword(PASSWORD_PROPERTY,null,null);
+            else
+                _keyStorePassword=null;
+        }
+        else
+            _keyStorePassword = new Password(password);
     }
 
     /**
      * @param password
-     *            The password (if any) for the specific key within the key store
+     *            The password (if any) for the specific key within the key store.
+     *            If null is passed and the {@value #KEYPASSWORD_PROPERTY} system property is set,
+     *            then the {@link Password#getPassword(String, String, String)} is used to
+     *            obtain a password from the {@value #KEYPASSWORD_PROPERTY}  system property.
      */
     public void setKeyManagerPassword(String password)
     {
         checkNotStarted();
-        _keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
+        if (password==null)
+        {
+            if (System.getProperty(KEYPASSWORD_PROPERTY)!=null)
+                _keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,null,null);
+            else
+                _keyManagerPassword = null;
+        }
+        else
+            _keyManagerPassword = new Password(password);
     }
 
     /**
      * @param password
-     *            The password for the trust store
+     *            The password for the trust store. If null is passed and a truststore is set
+     *            that is different from the keystore, then
+     *            the {@link Password#getPassword(String, String, String)} is used to
+     *            obtain a password either from the {@value #PASSWORD_PROPERTY}
+     *            System property or by prompting for manual entry.
      */
     public void setTrustStorePassword(String password)
     {
         checkNotStarted();
-        _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
+        if (password==null)
+        {
+            // Do we need a truststore password?
+            if (_trustStoreResource!=null && !_trustStoreResource.equals(_keyStoreResource))
+                _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,null,null);
+            else
+                _trustStorePassword = null;
+        }
+        else
+            _trustStorePassword=new Password(password);
     }
 
     /**
@@ -835,9 +985,7 @@
      */
     public SSLContext getSslContext()
     {
-        if (!isStarted())
-            throw new IllegalStateException(getState());
-        return _context;
+        return isStarted()?_factory._context:_setContext;
     }
 
     /**
@@ -847,7 +995,7 @@
     public void setSslContext(SSLContext sslContext)
     {
         checkNotStarted();
-        _context = sslContext;
+        _setContext = sslContext;
     }
 
     /**
@@ -863,27 +1011,39 @@
     /**
      * Override this method to provide alternate way to load a keystore.
      *
+     * @param resource the resource to load the keystore from
      * @return the key store instance
      * @throws Exception if the keystore cannot be loaded
      */
-    protected KeyStore loadKeyStore() throws Exception
+    protected KeyStore loadKeyStore(Resource resource) throws Exception
     {
-        return _keyStore != null ? _keyStore : CertificateUtils.getKeyStore(_keyStoreInputStream,
-                _keyStorePath, _keyStoreType, _keyStoreProvider,
-                _keyStorePassword==null? null: _keyStorePassword.toString());
+        return CertificateUtils.getKeyStore(resource, _keyStoreType, _keyStoreProvider,_keyStorePassword==null? null:_keyStorePassword.toString());
     }
 
     /**
      * Override this method to provide alternate way to load a truststore.
      *
+     * @param resource the resource to load the truststore from
      * @return the key store instance
      * @throws Exception if the truststore cannot be loaded
      */
-    protected KeyStore loadTrustStore() throws Exception
+    protected KeyStore loadTrustStore(Resource resource) throws Exception
     {
-        return _trustStore != null ? _trustStore : CertificateUtils.getKeyStore(_trustStoreInputStream,
-                _trustStorePath, _trustStoreType,  _trustStoreProvider,
-                _trustStorePassword==null? null: _trustStorePassword.toString());
+        String type=_trustStoreType;
+        String provider= _trustStoreProvider;
+        String passwd=_trustStorePassword==null? null:_trustStorePassword.toString();
+        if (resource==null || resource.equals(_keyStoreResource))
+        {
+            resource=_keyStoreResource;
+            if (type==null)
+                type=_keyStoreType;
+            if (provider==null)
+                provider= _keyStoreProvider;
+            if (passwd==null)
+                passwd=_keyStorePassword==null? null:_keyStorePassword.toString();
+        }
+
+        return CertificateUtils.getKeyStore(resource,type,provider,passwd);
     }
 
     /**
@@ -911,18 +1071,30 @@
             keyManagerFactory.init(keyStore,_keyManagerPassword == null?(_keyStorePassword == null?null:_keyStorePassword.toString().toCharArray()):_keyManagerPassword.toString().toCharArray());
             managers = keyManagerFactory.getKeyManagers();
 
-            if (_certAlias != null)
+            if (managers!=null)
             {
-                for (int idx = 0; idx < managers.length; idx++)
+                if (_certAlias != null)
                 {
-                    if (managers[idx] instanceof X509KeyManager)
+                    for (int idx = 0; idx < managers.length; idx++)
                     {
-                        managers[idx] = new AliasedX509ExtendedKeyManager(_certAlias,(X509KeyManager)managers[idx]);
+                        if (managers[idx] instanceof X509ExtendedKeyManager)
+                            managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],_certAlias);
+                    }
+                }
+
+                if (!_certHosts.isEmpty() || !_certWilds.isEmpty())
+                {
+                    for (int idx = 0; idx < managers.length; idx++)
+                    {
+                        if (managers[idx] instanceof X509ExtendedKeyManager)
+                            managers[idx]=new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]);
                     }
                 }
             }
         }
 
+        LOG.debug("managers={} for {}",managers,this);
+
         return managers;
     }
 
@@ -983,60 +1155,13 @@
     }
 
     /**
-     * Check KeyStore Configuration. Ensures that if keystore has been
-     * configured but there's no truststore, that keystore is
-     * used as truststore.
-     * @throws IllegalStateException if SslContextFactory configuration can't be used.
-     */
-    public void checkKeyStore()
-    {
-        if (_context != null)
-            return;
-
-        if (_keyStore == null && _keyStoreInputStream == null && _keyStorePath == null)
-            throw new IllegalStateException("SSL doesn't have a valid keystore");
-
-        // if the keystore has been configured but there is no
-        // truststore configured, use the keystore as the truststore
-        if (_trustStore == null && _trustStoreInputStream == null && _trustStorePath == null)
-        {
-            _trustStore = _keyStore;
-            _trustStorePath = _keyStorePath;
-            _trustStoreInputStream = _keyStoreInputStream;
-            _trustStoreType = _keyStoreType;
-            _trustStoreProvider = _keyStoreProvider;
-            _trustStorePassword = _keyStorePassword;
-            _trustManagerFactoryAlgorithm = _keyManagerFactoryAlgorithm;
-        }
-
-        // It's the same stream we cannot read it twice, so read it once in memory
-        if (_keyStoreInputStream != null && _keyStoreInputStream == _trustStoreInputStream)
-        {
-            try
-            {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                IO.copy(_keyStoreInputStream, baos);
-                _keyStoreInputStream.close();
-
-                _keyStoreInputStream = new ByteArrayInputStream(baos.toByteArray());
-                _trustStoreInputStream = new ByteArrayInputStream(baos.toByteArray());
-            }
-            catch (Exception ex)
-            {
-                throw new IllegalStateException(ex);
-            }
-        }
-    }
-
-    /**
      * Select protocols to be used by the connector
      * based on configured inclusion and exclusion lists
      * as well as enabled and supported protocols.
      * @param enabledProtocols Array of enabled protocols
      * @param supportedProtocols Array of supported protocols
-     * @return Array of protocols to enable
      */
-    public String[] selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
+    public void selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
     {
         Set<String> selected_protocols = new LinkedHashSet<>();
 
@@ -1045,8 +1170,12 @@
         {
             // Use only the supported included protocols
             for (String protocol : _includeProtocols)
+            {
                 if(Arrays.asList(supportedProtocols).contains(protocol))
                     selected_protocols.add(protocol);
+                else
+                    LOG.info("Protocol {} not supported in {}",protocol,Arrays.asList(supportedProtocols));
+            }
         }
         else
             selected_protocols.addAll(Arrays.asList(enabledProtocols));
@@ -1055,7 +1184,14 @@
         // Remove any excluded protocols
         selected_protocols.removeAll(_excludeProtocols);
 
-        return selected_protocols.toArray(new String[selected_protocols.size()]);
+
+        if (selected_protocols.isEmpty())
+            LOG.warn("No selected protocols from {}",Arrays.asList(supportedProtocols));
+
+        _selectedProtocols = selected_protocols.toArray(new String[selected_protocols.size()]);
+
+
+
     }
 
     /**
@@ -1064,11 +1200,10 @@
      * as well as enabled and supported cipher suite lists.
      * @param enabledCipherSuites Array of enabled cipher suites
      * @param supportedCipherSuites Array of supported cipher suites
-     * @return Array of cipher suites to enable
      */
-    public String[] selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
+    protected void selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
     {
-        Set<String> selected_ciphers = new CopyOnWriteArraySet<>();
+        List<String> selected_ciphers = new ArrayList<>();
 
         // Set the starting ciphers - either from the included or enabled list
         if (_includeCipherSuites.isEmpty())
@@ -1078,33 +1213,51 @@
 
         removeExcludedCipherSuites(selected_ciphers);
 
-        return selected_ciphers.toArray(new String[selected_ciphers.size()]);
+        if (selected_ciphers.isEmpty())
+            LOG.warn("No supported ciphers from {}",Arrays.asList(supportedCipherSuites));
+
+        if (_cipherComparator!=null)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Sorting selected ciphers with {}",_cipherComparator);
+            Collections.sort(selected_ciphers,_cipherComparator);
+        }
+
+        _selectedCipherSuites=selected_ciphers.toArray(new String[selected_ciphers.size()]);
     }
 
-    protected void processIncludeCipherSuites(String[] supportedCipherSuites, Set<String> selected_ciphers)
+    protected void processIncludeCipherSuites(String[] supportedCipherSuites, List<String> selected_ciphers)
     {
         for (String cipherSuite : _includeCipherSuites)
         {
             Pattern p = Pattern.compile(cipherSuite);
+            boolean added=false;
             for (String supportedCipherSuite : supportedCipherSuites)
             {
                 Matcher m = p.matcher(supportedCipherSuite);
                 if (m.matches())
+                {
+                    added=true;
                     selected_ciphers.add(supportedCipherSuite);
+                }
+
             }
+            if (!added)
+                LOG.info("No Cipher matching '{}' is supported",cipherSuite);
         }
     }
 
-    protected void removeExcludedCipherSuites(Set<String> selected_ciphers)
+    protected void removeExcludedCipherSuites(List<String> selected_ciphers)
     {
         for (String excludeCipherSuite : _excludeCipherSuites)
         {
             Pattern excludeCipherPattern = Pattern.compile(excludeCipherSuite);
-            for (String selectedCipherSuite : selected_ciphers)
+            for (Iterator<String> i=selected_ciphers.iterator();i.hasNext();)
             {
+                String selectedCipherSuite = i.next();
                 Matcher m = excludeCipherPattern.matcher(selectedCipherSuite);
                 if (m.matches())
-                    selected_ciphers.remove(selectedCipherSuite);
+                    i.remove();
             }
         }
     }
@@ -1119,6 +1272,24 @@
     }
 
     /**
+     * Check if the lifecycle has been started and throw runtime exception
+     */
+    protected void checkIsStarted()
+    {
+        if (!isStarted())
+            throw new IllegalStateException("!STARTED: "+this);
+    }
+
+    /**
+     * Check if the lifecycle has been started and throw runtime exception
+     */
+    protected void checkIsRunning()
+    {
+        if (!isRunning())
+            throw new IllegalStateException("!RUNNING: "+this);
+    }
+
+    /**
      * @return true if CRL Distribution Points support is enabled
      */
     public boolean isEnableCRLDP()
@@ -1175,7 +1346,12 @@
     public void setKeyStore(KeyStore keyStore)
     {
         checkNotStarted();
-        _keyStore = keyStore;
+        _setKeyStore = keyStore;
+    }
+
+    public KeyStore getKeyStore()
+    {
+        return isStarted()?_factory._keyStore:_setKeyStore;
     }
 
     /** Set the trust store.
@@ -1184,7 +1360,12 @@
     public void setTrustStore(KeyStore trustStore)
     {
         checkNotStarted();
-        _trustStore = trustStore;
+        _setTrustStore = trustStore;
+    }
+
+    public KeyStore getTrustStore()
+    {
+        return isStarted()?_factory._trustStore:_setTrustStore;
     }
 
     /** Set the key store resource.
@@ -1193,15 +1374,12 @@
     public void setKeyStoreResource(Resource resource)
     {
         checkNotStarted();
-        try
-        {
-            _keyStoreInputStream = resource.getInputStream();
-        }
-        catch (IOException e)
-        {
-             throw new InvalidParameterException("Unable to get resource "+
-                     "input stream for resource "+resource.toString());
-        }
+        _keyStoreResource=resource;
+    }
+
+    public Resource getKeyStoreResource()
+    {
+        return _keyStoreResource;
     }
 
     /** Set the trust store resource.
@@ -1210,15 +1388,12 @@
     public void setTrustStoreResource(Resource resource)
     {
         checkNotStarted();
-        try
-        {
-            _trustStoreInputStream = resource.getInputStream();
-        }
-        catch (IOException e)
-        {
-             throw new InvalidParameterException("Unable to get resource "+
-                     "input stream for resource "+resource.toString());
-        }
+        _trustStoreResource=resource;
+    }
+
+    public Resource getTrustStoreResource()
+    {
+        return _trustStoreResource;
     }
 
     /**
@@ -1272,7 +1447,9 @@
 
     public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException
     {
-        SSLServerSocketFactory factory = _context.getServerSocketFactory();
+        checkIsStarted();
+
+        SSLServerSocketFactory factory = _factory._context.getServerSocketFactory();
 
         SSLServerSocket socket =
             (SSLServerSocket) (host==null ?
@@ -1284,17 +1461,17 @@
         if (getNeedClientAuth())
             socket.setNeedClientAuth(getNeedClientAuth());
 
-        socket.setEnabledCipherSuites(selectCipherSuites(
-                                            socket.getEnabledCipherSuites(),
-                                            socket.getSupportedCipherSuites()));
-        socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
+        socket.setEnabledCipherSuites(_selectedCipherSuites);
+        socket.setEnabledProtocols(_selectedProtocols);
 
         return socket;
     }
 
     public SSLSocket newSslSocket() throws IOException
     {
-        SSLSocketFactory factory = _context.getSocketFactory();
+        checkIsStarted();
+
+        SSLSocketFactory factory = _factory._context.getSocketFactory();
 
         SSLSocket socket = (SSLSocket)factory.createSocket();
 
@@ -1303,10 +1480,8 @@
         if (getNeedClientAuth())
             socket.setNeedClientAuth(getNeedClientAuth());
 
-        socket.setEnabledCipherSuites(selectCipherSuites(
-                                            socket.getEnabledCipherSuites(),
-                                            socket.getSupportedCipherSuites()));
-        socket.setEnabledProtocols(selectProtocols(socket.getEnabledProtocols(),socket.getSupportedProtocols()));
+        socket.setEnabledCipherSuites(_selectedCipherSuites);
+        socket.setEnabledProtocols(_selectedProtocols);
 
         return socket;
     }
@@ -1314,7 +1489,7 @@
     /**
      * Factory method for "scratch" {@link SSLEngine}s, usually only used for retrieving configuration
      * information such as the application buffer size or the list of protocols/ciphers.
-     * <p />
+     * <p>
      * This method should not be used for creating {@link SSLEngine}s that are used in actual socket
      * communication.
      *
@@ -1322,9 +1497,8 @@
      */
     public SSLEngine newSSLEngine()
     {
-        if (!isRunning())
-            throw new IllegalStateException("!STARTED");
-        SSLEngine sslEngine=_context.createSSLEngine();
+        checkIsRunning();
+        SSLEngine sslEngine=_factory._context.createSSLEngine();
         customize(sslEngine);
         return sslEngine;
     }
@@ -1339,28 +1513,27 @@
      */
     public SSLEngine newSSLEngine(String host, int port)
     {
-        if (!isRunning())
-            throw new IllegalStateException("!STARTED");
+        checkIsStarted();
         SSLEngine sslEngine=isSessionCachingEnabled()
-            ? _context.createSSLEngine(host, port)
-            : _context.createSSLEngine();
+            ? _factory._context.createSSLEngine(host, port)
+            : _factory._context.createSSLEngine();
         customize(sslEngine);
         return sslEngine;
     }
 
     /**
      * Server-side only factory method for creating {@link SSLEngine}s.
-     * <p />
+     * <p>
      * If the given {@code address} is null, it is equivalent to {@link #newSSLEngine()}, otherwise
      * {@link #newSSLEngine(String, int)} is called.
-     * <p />
+     * <p>
      * If {@link #getNeedClientAuth()} is {@code true}, then the host name is passed to
      * {@link #newSSLEngine(String, int)}, possibly incurring in a reverse DNS lookup, which takes time
      * and may hang the selector (since this method is usually called by the selector thread).
-     * <p />
+     * <p>
      * Otherwise, the host address is passed to {@link #newSSLEngine(String, int)} without DNS lookup
      * penalties.
-     * <p />
+     * <p>
      * Clients that wish to create {@link SSLEngine} instances must use {@link #newSSLEngine(String, int)}.
      *
      * @param address the remote peer address
@@ -1378,20 +1551,27 @@
 
     public void customize(SSLEngine sslEngine)
     {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Customize {}",sslEngine);
+
         SSLParameters sslParams = sslEngine.getSSLParameters();
         sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm);
-        sslEngine.setSSLParameters(sslParams);
+        sslParams.setUseCipherSuitesOrder(_useCipherSuitesOrder);
+        if (!_certHosts.isEmpty() || !_certWilds.isEmpty())
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Enable SNI matching {}",sslEngine);
+            sslParams.setSNIMatchers(Collections.singletonList((SNIMatcher)new AliasSNIMatcher()));
+        }
+        sslParams.setCipherSuites(_selectedCipherSuites);
+        sslParams.setProtocols(_selectedProtocols);
 
         if (getWantClientAuth())
-            sslEngine.setWantClientAuth(getWantClientAuth());
+            sslParams.setWantClientAuth(true);
         if (getNeedClientAuth())
-            sslEngine.setNeedClientAuth(getNeedClientAuth());
+            sslParams.setNeedClientAuth(true);
 
-        sslEngine.setEnabledCipherSuites(selectCipherSuites(
-                sslEngine.getEnabledCipherSuites(),
-                sslEngine.getSupportedCipherSuites()));
-
-        sslEngine.setEnabledProtocols(selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols()));
+        sslEngine.setSSLParameters(sslParams);
     }
 
     public static X509Certificate[] getCertChain(SSLSession sslSession)
@@ -1485,7 +1665,95 @@
         return String.format("%s@%x(%s,%s)",
                 getClass().getSimpleName(),
                 hashCode(),
-                _keyStorePath,
-                _trustStorePath);
+                _keyStoreResource,
+                _trustStoreResource);
+    }
+
+    protected class Factory
+    {
+        final KeyStore _keyStore;
+        final KeyStore _trustStore;
+        final SSLContext _context;
+
+        public Factory(KeyStore keyStore, KeyStore trustStore, SSLContext context)
+        {
+            super();
+            _keyStore = keyStore;
+            _trustStore = trustStore;
+            _context = context;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("SslFactory@%x{%s}",System.identityHashCode(this),SslContextFactory.this);
+        }
+    }
+
+    class AliasSNIMatcher extends SNIMatcher
+    {
+        private String _host;
+        private X509 _x509;
+
+        AliasSNIMatcher()
+        {
+            super(StandardConstants.SNI_HOST_NAME);
+        }
+
+        @Override
+        public boolean matches(SNIServerName serverName)
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("SNI matching for {}",serverName);
+
+            if (serverName instanceof SNIHostName)
+            {
+                String host = _host = ((SNIHostName)serverName).getAsciiName();
+                host=StringUtil.asciiToLowerCase(host);
+
+                // Try an exact match
+                _x509 = _certHosts.get(host);
+
+                // Else try an exact wild match
+                if (_x509==null)
+                {
+                    _x509 = _certWilds.get(host);
+
+                    // Else try an 1 deep wild match
+                    if (_x509==null)
+                    {
+                        int dot=host.indexOf('.');
+                        if (dot>=0)
+                        {
+                            String domain=host.substring(dot+1);
+                            _x509 = _certWilds.get(domain);
+                        }
+                    }
+                }
+
+                if (LOG.isDebugEnabled())
+                    LOG.debug("SNI matched {}->{}",host,_x509);
+            }
+            else
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("SNI no match for {}", serverName);
+            }
+
+            // Return true and allow the KeyManager to accept or reject when choosing a certificate.
+            // If we don't have a SNI host, or didn't see any certificate aliases,
+            // just say true as it will either somehow work or fail elsewhere.
+            return true;
+        }
+
+        public String getHost()
+        {
+            return _host;
+        }
+
+        public X509 getX509()
+        {
+            return _x509;
+        }
     }
 }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/X509.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/X509.java
new file mode 100644
index 0000000..29a5f12
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/X509.java
@@ -0,0 +1,163 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.ssl;
+
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.security.auth.x500.X500Principal;
+
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class X509
+{
+    private static final Logger LOG = Log.getLogger(X509.class);
+
+    /*
+     * @see {@link X509Certificate#getKeyUsage()}
+     */
+    private static final int KEY_USAGE__KEY_CERT_SIGN=5;
+
+    /*
+     *
+     * @see {@link X509Certificate#getSubjectAlternativeNames()}
+     */
+    private static final int SUBJECT_ALTERNATIVE_NAMES__DNS_NAME=2;
+
+    public static boolean isCertSign(X509Certificate x509)
+    {
+        boolean[] key_usage=x509.getKeyUsage();
+        return key_usage!=null && key_usage[KEY_USAGE__KEY_CERT_SIGN];
+    }
+
+    private final X509Certificate _x509;
+    private final String _alias;
+    private final List<String> _hosts=new ArrayList<>();
+    private final List<String> _wilds=new ArrayList<>();
+
+    public X509(String alias,X509Certificate x509) throws CertificateParsingException, InvalidNameException
+    {
+        _alias=alias;
+        _x509 = x509;
+
+        // Look for alternative name extensions
+        boolean named=false;
+        Collection<List<?>> altNames = x509.getSubjectAlternativeNames();
+        if (altNames!=null)
+        {
+            for (List<?> list : altNames)
+            {
+                if (((Number)list.get(0)).intValue() == SUBJECT_ALTERNATIVE_NAMES__DNS_NAME)
+                {
+                    String cn = list.get(1).toString();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Certificate SAN alias={} CN={} in {}",alias,cn,this);
+                    if (cn!=null)
+                    {
+                        named=true;
+                        addName(cn);
+                    }
+                }
+            }
+        }
+
+        // If no names found, look up the CN from the subject
+        if (!named)
+        {
+            LdapName name=new LdapName(x509.getSubjectX500Principal().getName(X500Principal.RFC2253));
+            for (Rdn rdn : name.getRdns())
+            {
+                if (rdn.getType().equalsIgnoreCase("CN"))
+                {
+                    String cn = rdn.getValue().toString();
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Certificate CN alias={} CN={} in {}",alias,cn,this);
+                    if (cn!=null && cn.contains(".") && !cn.contains(" "))
+                        addName(cn);
+                }
+            }
+        }
+    }
+
+    protected void addName(String cn)
+    {
+        cn=StringUtil.asciiToLowerCase(cn);
+        if (cn.startsWith("*."))
+            _wilds.add(cn.substring(2));
+        else
+            _hosts.add(cn);
+    }
+
+    public String getAlias()
+    {
+        return _alias;
+    }
+
+    public X509Certificate getCertificate()
+    {
+        return _x509;
+    }
+
+    public Set<String> getHosts()
+    {
+        return new HashSet<>(_hosts);
+    }
+
+    public Set<String> getWilds()
+    {
+        return new HashSet<>(_wilds);
+    }
+
+    public boolean matches(String host)
+    {
+        host=StringUtil.asciiToLowerCase(host);
+        if (_hosts.contains(host) || _wilds.contains(host))
+            return true;
+
+        int dot = host.indexOf('.');
+        if (dot>=0)
+        {
+            String domain=host.substring(dot+1);
+            if (_wilds.contains(domain))
+                return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x(%s,h=%s,w=%s)",
+                getClass().getSimpleName(),
+                hashCode(),
+                _alias,
+                _hosts,
+                _wilds);
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
index a57f045..f9a0bf3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/CounterStatistic.java
@@ -40,20 +40,30 @@
     /* ------------------------------------------------------------ */
     public void reset()
     {
-        reset(0);
+        _total.set(0);
+        _max.set(0);
+        long current=_curr.get();
+        _total.addAndGet(current);
+        Atomics.updateMax(_max,current);
     }
 
     /* ------------------------------------------------------------ */
     public void reset(final long value)
     {
-        _max.set(value);
+        _total.set(0);
+        _max.set(0);
         _curr.set(value);
-        _total.set(0); // total always set to 0 to properly calculate cumulative total
+        if (value>0)
+        {
+            _total.addAndGet(value);
+            Atomics.updateMax(_max,value);
+        }
     }
 
     /* ------------------------------------------------------------ */
     /**
      * @param delta the amount to add to the count
+     * @return the new value
      */
     public long add(final long delta)
     {
@@ -68,6 +78,8 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * increment the value by one
+     * @return the new value, post increment
      */
     public long increment()
     {
@@ -76,6 +88,8 @@
 
     /* ------------------------------------------------------------ */
     /**
+     * decrement by 1
+     * @return the new value, post-decrement
      */
     public long decrement()
     {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java
index 718be6e..0b2eaa3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/statistic/SampleStatistic.java
@@ -23,23 +23,20 @@
 import org.eclipse.jetty.util.Atomics;
 
 
-/* ------------------------------------------------------------ */
 /**
  * SampledStatistics
  * <p>
- * Provides max, total, mean, count, variance, and standard
- * deviation of continuous sequence of samples.
+ * Provides max, total, mean, count, variance, and standard deviation of continuous sequence of samples.
  * <p>
- * Calculates estimates of mean, variance, and standard deviation
- * characteristics of a sample using a non synchronized
- * approximation of the on-line algorithm presented
- * in Donald Knuth's Art of Computer Programming, Volume 2,
- * Seminumerical Algorithms, 3rd edition, page 232,
- * Boston: Addison-Wesley. that cites a 1962 paper by B.P. Welford
- * that can be found by following the link http://www.jstor.org/pss/1266577
+ * Calculates estimates of mean, variance, and standard deviation characteristics of a sample using a non synchronized
+ * approximation of the on-line algorithm presented in <cite>Donald Knuth's Art of Computer Programming, Volume 2,
+ * Seminumerical Algorithms, 3rd edition, page 232, Boston: Addison-Wesley</cite>. that cites a 1962 paper by B.P. Welford that
+ * can be found by following <a href="http://www.jstor.org/pss/1266577">Note on a Method for Calculating Corrected Sums
+ * of Squares and Products</a>
  * <p>
- * This algorithm is also described in Wikipedia at
- * http://en.wikipedia.org/w/index.php?title=Algorithms_for_calculating_variance&section=4#On-line_algorithm
+ * This algorithm is also described in Wikipedia at <a href=
+ * "http://en.wikipedia.org/w/index.php?title=Algorithms_for_calculating_variance&amp;section=4#On-line_algorithm">
+ * Algorithms for calculating variance </a>
  */
 public class SampleStatistic
 {
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java
new file mode 100644
index 0000000..eef0910
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutionStrategy.java
@@ -0,0 +1,100 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import java.lang.reflect.Constructor;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume;
+
+/**
+ * <p>An {@link ExecutionStrategy} executes {@link Runnable} tasks produced by a {@link Producer}.
+ * The strategy to execute the task may vary depending on the implementation; the task may be
+ * run in the calling thread, or in a new thread, etc.</p>
+ * <p>The strategy delegates the production of tasks to a {@link Producer}, and continues to
+ * execute tasks until the producer continues to produce them.</p>
+ */
+public interface ExecutionStrategy
+{
+    /**
+     * <p>Initiates (or resumes) the task production and execution.</p>
+     * <p>This method guarantees that the task is never run by the
+     * thread that called this method.</p>
+     *
+     * @see #execute()
+     */
+    public void dispatch();
+
+    /**
+     * <p>Initiates (or resumes) the task production and execution.</p>
+     * <p>The produced task may be run by the same thread that called
+     * this method.</p>
+     *
+     * @see #dispatch()
+     */
+    public void execute();
+
+    /**
+     * <p>A producer of {@link Runnable} tasks to run.</p>
+     * <p>The {@link ExecutionStrategy} will repeatedly invoke {@link #produce()} until
+     * the producer returns null, indicating that it has nothing more to produce.</p>
+     * <p>When no more tasks can be produced, implementations should arrange for the
+     * {@link ExecutionStrategy} to be invoked again in case an external event resumes
+     * the tasks production.</p>
+     */
+    public interface Producer
+    {
+        /**
+         * <p>Produces a task to be executed.</p>
+         *
+         * @return a task to executed or null if there are no more tasks to execute
+         */
+        Runnable produce();
+    }
+
+    public static class Factory
+    {
+        private static final Logger LOG = Log.getLogger(Factory.class);
+
+        public static ExecutionStrategy instanceFor(Producer producer, Executor executor)
+        {
+            // TODO remove this mechanism before release
+            String strategy = System.getProperty(producer.getClass().getName()+".ExecutionStrategy");
+            if (strategy!=null)
+            {
+                try
+                {
+                    Class<? extends ExecutionStrategy> c = Loader.loadClass(producer.getClass(),strategy);
+                    Constructor<? extends ExecutionStrategy> m = c.getConstructor(Producer.class,Executor.class);
+                    LOG.info("Use {} for {}",c.getSimpleName(),producer.getClass().getName());
+                    return  m.newInstance(producer,executor);
+                }
+                catch(Exception e)
+                {
+                    LOG.warn(e);
+                }
+            }
+            
+            return new ExecuteProduceConsume(producer,executor);
+        }
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java
index 899babe..42fbf1f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ExecutorThreadPool.java
@@ -65,7 +65,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Wraps an {@link ThreadPoolExecutor}.
-     * Max pool size is 256, pool thread timeout after 60 seconds, and core pool size is 32 when queueSize >= 0.
+     * Max pool size is 256, pool thread timeout after 60 seconds, and core pool size is 32 when queueSize &gt;= 0.
      * @param queueSize can be -1 for using an unbounded {@link LinkedBlockingQueue}, 0 for using a
      * {@link SynchronousQueue}, greater than 0 for using a {@link ArrayBlockingQueue} of the given size.
      */
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java
new file mode 100644
index 0000000..fae9c8a
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java
@@ -0,0 +1,108 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * <p>This is a lock designed to protect VERY short sections of
+ * critical code.  Threads attempting to take the lock will wait
+ * until the lock is available, thus it is important that
+ * the code protected by this lock is extremely simple and non
+ * blocking.</p>
+ * <pre>
+ * try(SpinLock.Lock lock = locker.lock())
+ * {
+ *   // something very quick and non blocking
+ * }
+ * </pre>
+ */
+public class Locker
+{
+    private static final boolean SPIN = Boolean.getBoolean(Locker.class.getName() + ".spin");
+
+    private final boolean _spin;
+    private final ReentrantLock _lock = new ReentrantLock();
+    private final AtomicReference<Thread> _spinLockState = new AtomicReference<>(null);
+    private final Lock _unlock = new Lock();
+
+    public Locker()
+    {
+        this(SPIN);
+    }
+
+    public Locker(boolean spin)
+    {
+        this._spin = spin;
+    }
+
+    public Lock lock()
+    {
+        if (_spin)
+            spinLock();
+        else
+            concLock();
+        return _unlock;
+    }
+
+    private void spinLock()
+    {
+        Thread current = Thread.currentThread();
+        while (true)
+        {
+            // Using test-and-test-and-set for better performance.
+            Thread locker = _spinLockState.get();
+            if (locker != null || !_spinLockState.compareAndSet(null, current))
+            {
+                if (locker == current)
+                    throw new IllegalStateException("Locker is not reentrant");
+                continue;
+            }
+            return;
+        }
+    }
+
+    private void concLock()
+    {
+        if (_lock.isHeldByCurrentThread())
+            throw new IllegalStateException("Locker is not reentrant");
+        _lock.lock();
+    }
+
+    public boolean isLocked()
+    {
+        if (_spin)
+            return _spinLockState.get() != null;
+        else
+            return _lock.isLocked();
+    }
+
+    public class Lock implements AutoCloseable
+    {
+        @Override
+        public void close()
+        {
+            if (_spin)
+                _spinLockState.set(null);
+            else
+                _lock.unlock();
+        }
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/NonBlockingThread.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/NonBlockingThread.java
deleted file mode 100644
index db0545f..0000000
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/NonBlockingThread.java
+++ /dev/null
@@ -1,59 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.thread;
-
-/**
- * Marker that wraps a Runnable, indicating that it is running in a thread that must not be blocked.
- * <p />
- * Client code can use the thread-local {@link #isNonBlockingThread()} to detect whether they are
- * in the context of a non-blocking thread, and perform different actions if that's the case.
- */
-public class NonBlockingThread implements Runnable
-{
-    private final static ThreadLocal<Boolean> __nonBlockingThread = new ThreadLocal<>();
-
-    /**
-     * @return whether the current thread is a thread that must not block.
-     */
-    public static boolean isNonBlockingThread()
-    {
-        return Boolean.TRUE.equals(__nonBlockingThread.get());
-    }
-
-    private final Runnable delegate;
-
-    public NonBlockingThread(Runnable delegate)
-    {
-        this.delegate = delegate;
-    }
-
-    @Override
-    public void run()
-    {
-        try
-        {
-            __nonBlockingThread.set(Boolean.TRUE);
-            delegate.run();
-        }
-        finally
-        {
-            __nonBlockingThread.set(Boolean.FALSE);
-        }
-    }
-}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
old mode 100644
new mode 100755
index bb986b6..cc937ee
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
@@ -54,6 +54,7 @@
     private final ConcurrentHashSet<Thread> _threads=new ConcurrentHashSet<Thread>();
     private final Object _joinLock = new Object();
     private final BlockingQueue<Runnable> _jobs;
+    private final ThreadGroup _threadGroup;
     private String _name = "qtp" + hashCode();
     private int _idleTimeout;
     private int _maxThreads;
@@ -84,6 +85,11 @@
 
     public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("queue") BlockingQueue<Runnable> queue)
     {
+        this(maxThreads, minThreads, idleTimeout, queue, null);
+    }
+
+    public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
+    {
         setMinThreads(minThreads);
         setMaxThreads(maxThreads);
         setIdleTimeout(idleTimeout);
@@ -95,6 +101,7 @@
             queue=new BlockingArrayQueue<>(capacity, capacity);
         }
         _jobs=queue;
+        _threadGroup=threadGroup;
     }
 
     @Override
@@ -186,7 +193,10 @@
     }
 
     /**
-     * Delegated to the named or anonymous Pool.
+     * Thread Pool should use Daemon Threading. 
+     *
+     * @param daemon true to enable delegation
+     * @see Thread#setDaemon(boolean)
      */
     public void setDaemon(boolean daemon)
     {
@@ -335,7 +345,10 @@
     }
 
     /**
-     * Delegated to the named or anonymous Pool.
+     * Is thread pool using daemon threading
+     * 
+     * @return true if delegating to named or anonymous pool
+     * @see Thread#setDaemon(boolean)
      */
     @ManagedAttribute("thead pool using a daemon thread")
     public boolean isDaemon()
@@ -356,6 +369,8 @@
     @Override
     public void execute(Runnable job)
     {
+        if (LOG.isDebugEnabled())
+            LOG.debug("queue {}",job);
         if (!isRunning() || !_jobs.offer(job))
         {
             LOG.warn("{} rejected {}", this, job);
@@ -459,7 +474,7 @@
 
     protected Thread newThread(Runnable runnable)
     {
-        return new Thread(runnable);
+        return new Thread(_threadGroup, runnable);
     }
 
     @Override
@@ -552,7 +567,11 @@
                     // Job loop
                     while (job != null && isRunning())
                     {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("run {}",job);
                         runJob(job);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("ran {}",job);
                         if (Thread.interrupted())
                         {
                             ignore=true;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
old mode 100644
new mode 100755
index 70cb518..544d891
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
@@ -32,7 +32,7 @@
 
 /**
  * Implementation of {@link Scheduler} based on JDK's {@link ScheduledThreadPoolExecutor}.
- * <p />
+ * <p>
  * While use of {@link ScheduledThreadPoolExecutor} creates futures that will not be used,
  * it has the advantage of allowing to set a property to remove cancelled tasks from its
  * queue even if the task did not fire, which provides a huge benefit in the performance
@@ -43,6 +43,7 @@
     private final String name;
     private final boolean daemon;
     private final ClassLoader classloader;
+    private final ThreadGroup threadGroup;
     private volatile ScheduledThreadPoolExecutor scheduler;
     private volatile Thread thread;
 
@@ -58,9 +59,15 @@
     
     public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
     {
+        this(name, daemon, threadFactoryClassLoader, null);
+    }
+
+    public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader, ThreadGroup threadGroup)
+    {
         this.name = name == null ? "Scheduler-" + hashCode() : name;
         this.daemon = daemon;
-        this.classloader = threadFactoryClassLoader;
+        this.classloader = threadFactoryClassLoader == null ? Thread.currentThread().getContextClassLoader() : threadFactoryClassLoader;
+        this.threadGroup = threadGroup;
     }
 
     @Override
@@ -71,7 +78,7 @@
             @Override
             public Thread newThread(Runnable r)
             {
-                Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(r, name);
+                Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(threadGroup, r, name);
                 thread.setDaemon(daemon);
                 thread.setContextClassLoader(classloader);
                 return thread;
@@ -123,11 +130,11 @@
         }
     }
 
-    private class ScheduledFutureTask implements Task
+    private static class ScheduledFutureTask implements Task
     {
         private final ScheduledFuture<?> scheduledFuture;
 
-        public ScheduledFutureTask(ScheduledFuture<?> scheduledFuture)
+        ScheduledFutureTask(ScheduledFuture<?> scheduledFuture)
         {
             this.scheduledFuture = scheduledFuture;
         }
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/SpinLock.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/SpinLock.java
deleted file mode 100644
index fa199cc..0000000
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/SpinLock.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.thread;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * <p>This spin lock is a lock designed to protect VERY short sections
- * of critical code.  Threads attempting to take the lock will spin
- * forever until the lock is available, thus it is important that
- * the code protected by this lock is extremely simple and non
- * blocking. The reason for this lock is that it prevents a thread
- * from giving up a CPU core when contending for the lock.</p>
- * <pre>
- * try(SpinLock.Lock lock = spinlock.lock())
- * {
- *   // something very quick and non blocking
- * }
- * </pre>
- * <p>Further analysis however, shows that spin locks behave really
- * bad under heavy contention and where the number of threads
- * exceeds the number of cores, which are common scenarios for a
- * server, so this class was removed from usage, preferring
- * standard locks instead.</p>
- * @deprecated Do not use it anymore, prefer normal locks
- */
-@Deprecated
-public class SpinLock
-{
-    private final AtomicReference<Thread> _lock = new AtomicReference<>(null);
-    private final Lock _unlock = new Lock();
-
-    public Lock lock()
-    {
-        Thread thread = Thread.currentThread();
-        while(true)
-        {
-            if (!_lock.compareAndSet(null,thread))
-            {
-                if (_lock.get()==thread)
-                    throw new IllegalStateException("SpinLock is not reentrant");
-                continue;
-            }
-            return _unlock;
-        }
-    }
-
-    public boolean isLocked()
-    {
-        return _lock.get()!=null;
-    }
-
-    public boolean isLockedThread()
-    {
-        return _lock.get()==Thread.currentThread();
-    }
-
-    public class Lock implements AutoCloseable
-    {
-        @Override
-        public void close()
-        {
-            _lock.set(null);
-        }
-    }
-}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScope.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScope.java
new file mode 100644
index 0000000..1ff33b5
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScope.java
@@ -0,0 +1,45 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import java.io.Closeable;
+
+public class ThreadClassLoaderScope implements Closeable
+{
+    private final ClassLoader old;
+    private final ClassLoader scopedClassLoader;
+
+    public ThreadClassLoaderScope(ClassLoader cl)
+    {
+        old = Thread.currentThread().getContextClassLoader();
+        scopedClassLoader = cl;
+        Thread.currentThread().setContextClassLoader(scopedClassLoader);
+    }
+
+    @Override
+    public void close()
+    {
+        Thread.currentThread().setContextClassLoader(old);
+    }
+
+    public ClassLoader getScopedClassLoader()
+    {
+        return scopedClassLoader;
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPool.java
index 84b8390..fd16182 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPool.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadPool.java
@@ -22,6 +22,7 @@
 
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.LifeCycle;
 
 /* ------------------------------------------------------------ */
 /** ThreadPool.
@@ -36,6 +37,7 @@
     /* ------------------------------------------------------------ */
     /**
      * Blocks until the thread pool is {@link LifeCycle#stop stopped}.
+     * @throws InterruptedException if thread was interrupted
      */
     public void join() throws InterruptedException;
 
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/TimerScheduler.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/TimerScheduler.java
index c46394a..36de805 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/TimerScheduler.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/TimerScheduler.java
@@ -113,7 +113,7 @@
             }
             catch (Throwable x)
             {
-                LOG.debug("Exception while executing task " + _task, x);
+                LOG.warn("Exception while executing task " + _task, x);
             }
         }
 
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java
new file mode 100644
index 0000000..d305322
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsume.java
@@ -0,0 +1,262 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread.strategy;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ExecutionStrategy;
+import org.eclipse.jetty.util.thread.Locker;
+import org.eclipse.jetty.util.thread.Locker.Lock;
+import org.eclipse.jetty.util.thread.ThreadPool;
+
+/**
+ * <p>A strategy where the thread calls produce will always run the resulting task
+ * itself.  The strategy may dispatches another thread to continue production.
+ * </p>
+ * <p>The strategy is also known by the nickname 'eat what you kill', which comes from
+ * the hunting ethic that says a person should not kill anything he or she does not
+ * plan on eating. In this case, the phrase is used to mean that a thread should
+ * not produce a task that it does not intend to run. By making producers run the
+ * task that they have just produced avoids execution delays and avoids parallel slow
+ * down by running the task in the same core, with good chances of having a hot CPU
+ * cache. It also avoids the creation of a queue of produced tasks that the system
+ * does not yet have capacity to consume, which can save memory and exert back
+ * pressure on producers.
+ * </p>
+ */
+public class ExecuteProduceConsume implements ExecutionStrategy, Runnable
+{
+    private static final Logger LOG = Log.getLogger(ExecuteProduceConsume.class);
+    private final Locker _locker = new Locker();
+    private final Runnable _runExecute = new RunExecute();
+    private final Producer _producer;
+    private final Executor _executor;
+    private boolean _idle=true;
+    private boolean _execute;
+    private boolean _producing;
+    private boolean _pending;
+    private final ThreadPool _threadpool;
+    private final ExecutionStrategy _lowresources;
+
+    public ExecuteProduceConsume(Producer producer, Executor executor)
+    {
+        this(producer,executor,(executor instanceof ThreadPool)?new ProduceExecuteConsume(producer,executor):null);
+    }
+    
+    public ExecuteProduceConsume(Producer producer, Executor executor, ExecutionStrategy lowResourceStrategy)
+    {
+        this._producer = producer;
+        this._executor = executor;
+        _threadpool = (executor instanceof ThreadPool)?((ThreadPool)executor):null;
+        _lowresources = _threadpool==null?null:lowResourceStrategy;
+    }
+
+    @Override
+    public void execute()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} execute",this);
+        
+        boolean produce=false;
+        try (Lock locked = _locker.lock())
+        {
+            // If we are idle and a thread is not producing
+            if (_idle)
+            {
+                if (_producing)
+                    throw new IllegalStateException();
+
+                // Then this thread will do the producing
+                produce=_producing=true;
+                // and we are no longer idle
+                _idle=false;
+            }
+            else
+            {
+                // Otherwise, lets tell the producing thread
+                // that it should call produce again before going idle
+                _execute=true;
+            }
+        }
+
+        if (produce)
+            produceAndRun();
+    }
+
+    @Override
+    public void dispatch()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} spawning",this);
+        boolean dispatch=false;
+        try (Lock locked = _locker.lock())
+        {
+            if (_idle)
+                dispatch=true;
+            else
+                _execute=true;
+        }
+        if (dispatch)
+            _executor.execute(_runExecute);
+    }
+
+    @Override
+    public void run()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} run",this);
+        boolean produce=false;
+        try (Lock locked = _locker.lock())
+        {
+            _pending=false;
+            if (!_idle && !_producing)
+            {
+                produce=_producing=true;
+            }
+        }
+
+        if (produce)
+        {
+            // If we are low on resources, then switch to PEC strategy which does not
+            // suffer as badly from thread starvation
+            while (_threadpool!=null && _threadpool.isLowOnThreads())
+            {
+                LOG.debug("EWYK low resources {}",this);
+                _lowresources.execute();
+            }
+            
+            // no longer low resources so produceAndRun normally
+            produceAndRun();
+        }
+    }
+
+    private void produceAndRun()
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} produce enter",this);
+
+        while (true)
+        {
+            // If we got here, then we are the thread that is producing.
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} producing",this);
+
+            Runnable task = _producer.produce();
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} produced {}",this,task);
+
+            boolean dispatch=false;
+            try (Lock locked = _locker.lock())
+            {
+                // Finished producing
+                _producing=false;
+
+                // Did we produced a task?
+                if (task == null)
+                {
+                    // There is no task.
+                    if (_execute)
+                    {
+                        _idle=false;
+                        _producing=true;
+                        _execute=false;
+                        continue;
+                    }
+
+                    // ... and no additional calls to execute, so we are idle
+                    _idle=true;
+                    break;
+                }
+
+                // We have a task, which we will run ourselves,
+                // so if we don't have another thread pending
+                if (!_pending)
+                {
+                    // dispatch one
+                    dispatch=_pending=true;
+                }
+
+                _execute=false;
+            }
+
+            // If we became pending
+            if (dispatch)
+            {
+                // Spawn a new thread to continue production by running the produce loop.
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} dispatch",this);
+                _executor.execute(this);
+            }
+
+            // Run the task.
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} run {}",this,task);
+            task.run();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} ran {}",this,task);
+
+            // Once we have run the task, we can try producing again.
+            try (Lock locked = _locker.lock())
+            {
+                // Is another thread already producing or we are now idle?
+                if (_producing || _idle)
+                    break;
+                _producing=true;
+            }
+        }
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} produce exit",this);
+    }
+
+    public Boolean isIdle()
+    {
+        try (Lock locked = _locker.lock())
+        {
+            return _idle;
+        }
+    }
+
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append("EPR ");
+        try (Lock locked = _locker.lock())
+        {
+            builder.append(_idle?"Idle/":"");
+            builder.append(_producing?"Prod/":"");
+            builder.append(_pending?"Pend/":"");
+            builder.append(_execute?"Exec/":"");
+        }
+        builder.append(_producer);
+        return builder.toString();
+    }
+
+    private class RunExecute implements Runnable
+    {
+        @Override
+        public void run()
+        {
+            execute();
+        }
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceConsume.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceConsume.java
new file mode 100644
index 0000000..d15d6f0
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceConsume.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread.strategy;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.util.thread.ExecutionStrategy;
+
+/**
+ * <p>A strategy where the caller thread iterates over task production, submitting each
+ * task to an {@link Executor} for execution.</p>
+ */
+public class ProduceConsume implements ExecutionStrategy, Runnable
+{
+    private final Producer _producer;
+    private final Executor _executor;
+
+    public ProduceConsume(Producer producer, Executor executor)
+    {
+        this._producer = producer;
+        this._executor = executor;
+    }
+
+    @Override
+    public void execute()
+    {
+        // Iterate until we are complete.
+        while (true)
+        {
+            // Produce a task.
+            Runnable task = _producer.produce();
+
+            if (task == null)
+                break;
+
+            // run the task.
+            task.run();
+        }
+    }
+
+    @Override
+    public void dispatch()
+    {
+        _executor.execute(this);
+    }
+
+    @Override
+    public void run()
+    {
+        execute();
+    }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java
new file mode 100644
index 0000000..64903a6
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/ProduceExecuteConsume.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread.strategy;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ExecutionStrategy;
+
+/**
+ * <p>A strategy where the caller thread iterates over task production, submitting each
+ * task to an {@link Executor} for execution.</p>
+ */
+public class ProduceExecuteConsume implements ExecutionStrategy
+{
+    private static final Logger LOG = Log.getLogger(ExecutionStrategy.class);
+    private final Producer _producer;
+    private final Executor _executor;
+
+    public ProduceExecuteConsume(Producer producer, Executor executor)
+    {
+        this._producer = producer;
+        this._executor = executor;
+    }
+
+    @Override
+    public void execute()
+    {
+        // Iterate until we are complete.
+        while (true)
+        {
+            // Produce a task.
+            Runnable task = _producer.produce();
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} PER produced {}",_producer,task);
+
+            if (task == null)
+                break;
+
+            // Execute the task.
+            _executor.execute(task);
+        }
+    }
+
+    @Override
+    public void dispatch()
+    {
+        execute();
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java
index b55c54e..5df95bf 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/BufferUtilTest.java
@@ -21,13 +21,20 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.OpenOption;
 import java.util.Arrays;
 import java.util.concurrent.ThreadLocalRandom;
 
@@ -335,4 +342,39 @@
         BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out);
         assertThat("Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true));
     }
+    
+    @Test
+    public void testMappedFile() throws Exception
+    {
+        String data="Now is the time for all good men to come to the aid of the party";
+        File file = File.createTempFile("test",".txt");
+        file.deleteOnExit();
+        try(FileWriter out = new FileWriter(file);)
+        {
+            out.write(data);
+        }
+        
+        ByteBuffer mapped = BufferUtil.toMappedBuffer(file);
+        assertEquals(data,BufferUtil.toString(mapped));
+        assertTrue(BufferUtil.isMappedBuffer(mapped));
+        
+        ByteBuffer direct = BufferUtil.allocateDirect(data.length());
+        direct.clear();
+        direct.put(data.getBytes(StandardCharsets.ISO_8859_1));
+        direct.flip();
+        assertEquals(data,BufferUtil.toString(direct));
+        assertFalse(BufferUtil.isMappedBuffer(direct));
+        
+        ByteBuffer slice = direct.slice();
+        assertEquals(data,BufferUtil.toString(slice));
+        assertFalse(BufferUtil.isMappedBuffer(slice));
+        
+        ByteBuffer duplicate = direct.duplicate();
+        assertEquals(data,BufferUtil.toString(duplicate));
+        assertFalse(BufferUtil.isMappedBuffer(duplicate));
+        
+        ByteBuffer readonly = direct.asReadOnlyBuffer();
+        assertEquals(data,BufferUtil.toString(readonly));
+        assertFalse(BufferUtil.isMappedBuffer(readonly));
+    }
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java
index 2858a6a..b66e876 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java
@@ -24,40 +24,40 @@
 
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
-import org.junit.AfterClass;
+import org.junit.After;
 import org.junit.Assert;
-import org.junit.BeforeClass;
+import org.junit.Before;
 import org.junit.Test;
 
 public class IteratingCallbackTest
 {
-    static Scheduler scheduler = new ScheduledExecutorScheduler();
-   
-    @BeforeClass
-    public static void beforeClass() throws Exception
+    private Scheduler scheduler;
+
+    @Before
+    public void prepare() throws Exception
     {
+        scheduler = new ScheduledExecutorScheduler();
         scheduler.start();
     }
-    
-    @AfterClass
-    public static void afterClass() throws Exception
+
+    @After
+    public void dispose() throws Exception
     {
         scheduler.stop();
     }
-    
+
     @Test
     public void testNonWaitingProcess() throws Exception
     {
-        
-        TestCB cb=new TestCB()
+        TestCB cb = new TestCB()
         {
-            int i=10;
-            
+            int i = 10;
+
             @Override
             protected Action process() throws Exception
             {
                 processed++;
-                if (i-->1)      
+                if (i-- > 1)
                 {
                     succeeded(); // fake a completed IO operation
                     return Action.SCHEDULED;
@@ -65,61 +65,59 @@
                 return Action.SUCCEEDED;
             }
         };
-        
+
         cb.iterate();
-        Assert.assertTrue(cb.waitForComplete()); 
-        Assert.assertEquals(10,cb.processed);
+        Assert.assertTrue(cb.waitForComplete());
+        Assert.assertEquals(10, cb.processed);
     }
 
-
-
     @Test
     public void testWaitingProcess() throws Exception
     {
-        TestCB cb=new TestCB()
+        TestCB cb = new TestCB()
         {
-            int i=4;
-            
+            int i = 4;
+
             @Override
             protected Action process() throws Exception
             {
                 processed++;
-                if (i-->1)      
+                if (i-- > 1)
                 {
-                    scheduler.schedule(successTask,50,TimeUnit.MILLISECONDS);
+                    scheduler.schedule(successTask, 50, TimeUnit.MILLISECONDS);
                     return Action.SCHEDULED;
                 }
                 return Action.SUCCEEDED;
             }
         };
-        
+
         cb.iterate();
-        
+
         Assert.assertTrue(cb.waitForComplete());
-         
-        Assert.assertEquals(4,cb.processed);
+
+        Assert.assertEquals(4, cb.processed);
     }
 
     @Test
-    public void testWaitingProcessSpuriousInterate() throws Exception
+    public void testWaitingProcessSpuriousIterate() throws Exception
     {
-        final TestCB cb=new TestCB()
+        final TestCB cb = new TestCB()
         {
-            int i=4;
-            
+            int i = 4;
+
             @Override
             protected Action process() throws Exception
             {
                 processed++;
-                if (i-->1)      
+                if (i-- > 1)
                 {
-                    scheduler.schedule(successTask,50,TimeUnit.MILLISECONDS);
+                    scheduler.schedule(successTask, 50, TimeUnit.MILLISECONDS);
                     return Action.SCHEDULED;
                 }
                 return Action.SUCCEEDED;
             }
         };
-        
+
         cb.iterate();
         scheduler.schedule(new Runnable()
         {
@@ -128,29 +126,29 @@
             {
                 cb.iterate();
                 if (!cb.isSucceeded())
-                    scheduler.schedule(this,50,TimeUnit.MILLISECONDS);
+                    scheduler.schedule(this, 50, TimeUnit.MILLISECONDS);
             }
-        },49,TimeUnit.MILLISECONDS);
-        
+        }, 49, TimeUnit.MILLISECONDS);
+
         Assert.assertTrue(cb.waitForComplete());
-         
-        Assert.assertEquals(4,cb.processed);
+
+        Assert.assertEquals(4, cb.processed);
     }
 
     @Test
     public void testNonWaitingProcessFailure() throws Exception
     {
-        TestCB cb=new TestCB()
+        TestCB cb = new TestCB()
         {
-            int i=10;
-            
+            int i = 10;
+
             @Override
             protected Action process() throws Exception
             {
                 processed++;
-                if (i-->1)      
+                if (i-- > 1)
                 {
-                    if (i>5)
+                    if (i > 5)
                         succeeded(); // fake a completed IO operation
                     else
                         failed(new Exception("testing"));
@@ -159,63 +157,63 @@
                 return Action.SUCCEEDED;
             }
         };
-        
+
         cb.iterate();
-        Assert.assertFalse(cb.waitForComplete()); 
-        Assert.assertEquals(5,cb.processed);
+        Assert.assertFalse(cb.waitForComplete());
+        Assert.assertEquals(5, cb.processed);
     }
 
     @Test
     public void testWaitingProcessFailure() throws Exception
     {
-        TestCB cb=new TestCB()
+        TestCB cb = new TestCB()
         {
-            int i=4;
-            
+            int i = 4;
+
             @Override
             protected Action process() throws Exception
             {
                 processed++;
-                if (i-->1)      
+                if (i-- > 1)
                 {
-                    scheduler.schedule(i>2?successTask:failTask,50,TimeUnit.MILLISECONDS);
+                    scheduler.schedule(i > 2 ? successTask : failTask, 50, TimeUnit.MILLISECONDS);
                     return Action.SCHEDULED;
                 }
                 return Action.SUCCEEDED;
             }
         };
-        
+
         cb.iterate();
-        
+
         Assert.assertFalse(cb.waitForComplete());
-        Assert.assertEquals(2,cb.processed);
+        Assert.assertEquals(2, cb.processed);
     }
-    
+
 
     @Test
     public void testIdleWaiting() throws Exception
     {
         final CountDownLatch idle = new CountDownLatch(1);
-        
-        TestCB cb=new TestCB()
+
+        TestCB cb = new TestCB()
         {
-            int i=5;
-            
+            int i = 5;
+
             @Override
             protected Action process()
             {
                 processed++;
-                
-                switch(i--)
+
+                switch (i--)
                 {
                     case 5:
                         succeeded();
                         return Action.SCHEDULED;
-                        
+
                     case 4:
-                        scheduler.schedule(successTask,5,TimeUnit.MILLISECONDS);
+                        scheduler.schedule(successTask, 5, TimeUnit.MILLISECONDS);
                         return Action.SCHEDULED;
-                        
+
                     case 3:
                         scheduler.schedule(new Runnable()
                         {
@@ -224,49 +222,99 @@
                             {
                                 idle.countDown();
                             }
-                        },5,TimeUnit.MILLISECONDS);
+                        }, 5, TimeUnit.MILLISECONDS);
                         return Action.IDLE;
 
                     case 2:
                         succeeded();
                         return Action.SCHEDULED;
-                        
+
                     case 1:
-                        scheduler.schedule(successTask,5,TimeUnit.MILLISECONDS);
+                        scheduler.schedule(successTask, 5, TimeUnit.MILLISECONDS);
                         return Action.SCHEDULED;
-                        
+
                     case 0:
                         return Action.SUCCEEDED;
-                        
-                    default: 
+
+                    default:
                         throw new IllegalStateException();
-                    
+
                 }
             }
         };
-        
+
         cb.iterate();
-        idle.await(10,TimeUnit.SECONDS);
+        idle.await(10, TimeUnit.SECONDS);
         Assert.assertTrue(cb.isIdle());
-        
+
         cb.iterate();
         Assert.assertTrue(cb.waitForComplete());
-        Assert.assertEquals(6,cb.processed);
+        Assert.assertEquals(6, cb.processed);
     }
-    
-    
-    
+
+    @Test
+    public void testCloseDuringProcessingReturningScheduled() throws Exception
+    {
+        testCloseDuringProcessing(IteratingCallback.Action.SCHEDULED);
+    }
+
+    @Test
+    public void testCloseDuringProcessingReturningSucceeded() throws Exception
+    {
+        testCloseDuringProcessing(IteratingCallback.Action.SUCCEEDED);
+    }
+
+    private void testCloseDuringProcessing(final IteratingCallback.Action action) throws Exception
+    {
+        final CountDownLatch failureLatch = new CountDownLatch(1);
+        IteratingCallback callback = new IteratingCallback()
+        {
+            @Override
+            protected Action process() throws Exception
+            {
+                close();
+                return action;
+            }
+
+            @Override
+            protected void onCompleteFailure(Throwable cause)
+            {
+                failureLatch.countDown();
+            }
+        };
+
+        callback.iterate();
+
+        Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
+    }
+
     private abstract static class TestCB extends IteratingCallback
     {
-        CountDownLatch completed = new CountDownLatch(1);
-        int processed=0;
+        protected Runnable successTask = new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                succeeded();
+            }
+        };
+        protected Runnable failTask = new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                failed(new Exception("testing failure"));
+            }
+        };
+        protected CountDownLatch completed = new CountDownLatch(1);
+        protected int processed = 0;
 
         @Override
         protected void onCompleteSuccess()
         {
             completed.countDown();
         }
-        
+
         @Override
         public void onCompleteFailure(Throwable x)
         {
@@ -275,26 +323,8 @@
 
         boolean waitForComplete() throws InterruptedException
         {
-            completed.await(10,TimeUnit.SECONDS);
+            completed.await(10, TimeUnit.SECONDS);
             return isSucceeded();
         }
-        
-        Runnable successTask = new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                succeeded();
-            }
-        };
-        Runnable failTask = new Runnable()
-        {
-            @Override
-            public void run()
-            {
-                failed(new Exception("testing failure"));
-            }
-        };
     }
-
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherDemo.java b/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherDemo.java
new file mode 100644
index 0000000..cfaf384
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherDemo.java
@@ -0,0 +1,132 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+public class PathWatcherDemo implements PathWatcher.Listener
+{
+    private static final Logger LOG = Log.getLogger(PathWatcherDemo.class);
+
+    public static void main(String[] args)
+    {
+        List<Path> paths = new ArrayList<>();
+        for (String arg : args)
+        {
+            paths.add(new File(arg).toPath());
+        }
+
+        if (paths.isEmpty())
+        {
+            LOG.warn("No paths specified on command line");
+            System.exit(-1);
+        }
+
+        PathWatcherDemo demo = new PathWatcherDemo();
+        try
+        {
+            demo.run(paths);
+        }
+        catch (Throwable t)
+        {
+            LOG.warn(t);
+        }
+    }
+
+    public void run(List<Path> paths) throws Exception
+    {
+        PathWatcher watcher = new PathWatcher();
+        //watcher.addListener(new PathWatcherDemo());
+        watcher.addListener (new PathWatcher.EventListListener(){
+
+            @Override
+            public void onPathWatchEvents(List<PathWatchEvent> events)
+            {
+               if (events == null)
+                   LOG.warn("Null events received");
+               if (events.isEmpty())
+                   LOG.warn("Empty events received");
+               
+               LOG.info("Bulk notification received");
+               for (PathWatchEvent e:events)
+                   onPathWatchEvent(e);
+                
+            }
+            
+        });
+        
+        watcher.setNotifyExistingOnStart(false);
+
+        List<String> excludes = new ArrayList<>();
+        excludes.add("glob:*.bak"); // ignore backup files
+        excludes.add("regex:^.*/\\~[^/]*$"); // ignore scratch files
+
+        for (Path path : paths)
+        {
+            if (Files.isDirectory(path))
+            {
+                PathWatcher.Config config = new PathWatcher.Config(path);
+                config.addExcludeHidden();
+                config.addExcludes(excludes);
+                config.setRecurseDepth(4);
+                watcher.watch(config);
+            }
+            else
+            {
+                watcher.watch(path);
+            }
+        }
+        watcher.start();
+        
+        Thread.currentThread().join();
+    }
+
+    @Override
+    public void onPathWatchEvent(PathWatchEvent event)
+    {
+        StringBuilder msg = new StringBuilder();
+        msg.append("onPathWatchEvent: [");
+        msg.append(event.getType());
+        msg.append("] ");
+        msg.append(event.getPath());
+        msg.append(" (count=").append(event.getCount()).append(")");
+        if (Files.isRegularFile(event.getPath()))
+        {
+            try
+            {
+                String fsize = String.format(" (filesize=%,d)",Files.size(event.getPath()));
+                msg.append(fsize);
+            }
+            catch (IOException e)
+            {
+                LOG.warn("Unable to get filesize",e);
+            }
+        }
+        LOG.info("{}",msg.toString());
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherTest.java
new file mode 100644
index 0000000..27ee360
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/PathWatcherTest.java
@@ -0,0 +1,709 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import static org.eclipse.jetty.util.PathWatcher.PathWatchEventType.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.toolchain.test.OS;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
+import org.eclipse.jetty.util.PathWatcher.PathWatchEventType;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+@Ignore("Disabled due to behavioral differences in various FileSystems (hard to write a single testcase that works in all scenarios)")
+public class PathWatcherTest
+{
+    public static class PathWatchEventCapture implements PathWatcher.Listener
+    {
+        public final static String FINISH_TAG = "#finished#.tag";
+        private static final Logger LOG = Log.getLogger(PathWatcherTest.PathWatchEventCapture.class);
+        private final Path baseDir;
+
+        /**
+         * Map of relative paths seen, to their events seen (in order seen)
+         */
+        public Map<String, List<PathWatchEventType>> events = new HashMap<>();
+
+        public int latchCount = 1;
+        public CountDownLatch finishedLatch;
+        private PathWatchEventType triggerType;
+        private Path triggerPath;
+
+        public PathWatchEventCapture(Path baseDir)
+        {
+            this.baseDir = baseDir;
+        }
+        
+       public void reset()
+       {
+           finishedLatch = new CountDownLatch(latchCount);
+           events.clear();
+       }
+
+        @Override
+        public void onPathWatchEvent(PathWatchEvent event)
+        {
+            synchronized (events)
+            {
+                //if triggered by path
+                if (triggerPath != null)
+                {
+                   
+                    if (triggerPath.equals(event.getPath()) && (event.getType() == triggerType))
+                    {
+                        LOG.debug("Encountered finish trigger: {} on {}",event.getType(),event.getPath());
+                        finishedLatch.countDown();
+                    }
+                }
+                else if (finishedLatch != null)
+                {
+                    finishedLatch.countDown();
+                }
+                
+
+                Path relativePath = this.baseDir.relativize(event.getPath());
+                String key = relativePath.toString().replace(File.separatorChar,'/');
+
+                List<PathWatchEventType> types = this.events.get(key);
+                if (types == null)
+                {
+                    types = new ArrayList<>();
+                }
+                types.add(event.getType());
+                this.events.put(key,types);
+                LOG.debug("Captured Event: {} | {}",event.getType(),key);
+            }
+        }
+
+        /**
+         * Validate the events seen match expectations.
+         * <p>
+         * Note: order of events is only important when looking at a specific file or directory. Events for multiple
+         * files can overlap in ways that this assertion doesn't care about.
+         * 
+         * @param expectedEvents
+         *            the events expected
+         */
+        public void assertEvents(Map<String, PathWatchEventType[]> expectedEvents)
+        {
+            assertThat("Event match (file|diretory) count",this.events.size(),is(expectedEvents.size()));
+
+            for (Map.Entry<String, PathWatchEventType[]> entry : expectedEvents.entrySet())
+            {
+                String relativePath = entry.getKey();
+                PathWatchEventType[] expectedTypes = entry.getValue();
+                assertEvents(relativePath,expectedTypes);
+            }
+        }
+
+        /**
+         * Validate the events seen match expectations.
+         * <p>
+         * Note: order of events is only important when looking at a specific file or directory. Events for multiple
+         * files can overlap in ways that this assertion doesn't care about.
+         * 
+         * @param relativePath
+         *            the test relative path to look for
+         * 
+         * @param expectedEvents
+         *            the events expected
+         */
+        public void assertEvents(String relativePath, PathWatchEventType... expectedEvents)
+        {
+            synchronized (events)
+            {
+                List<PathWatchEventType> actualEvents = this.events.get(relativePath);
+                assertThat("Events for path [" + relativePath + "]",actualEvents,contains(expectedEvents));
+            }
+        }
+
+        /**
+         * Set the path and type that will trigger this capture to be finished
+         * 
+         * @param triggerPath
+         *            the trigger path we look for to know that the capture is complete
+         * @param triggerType
+         *            the trigger type we look for to know that the capture is complete
+         */
+        public void setFinishTrigger(Path triggerPath, PathWatchEventType triggerType)
+        {
+            this.triggerPath = triggerPath;
+            this.triggerType = triggerType;
+            this.latchCount = 1;
+            this.finishedLatch = new CountDownLatch(1);
+            LOG.debug("Setting finish trigger {} for path {}",triggerType,triggerPath);
+        }
+        
+        public void setFinishTrigger (int count)
+        {
+            latchCount = count;
+            finishedLatch = new CountDownLatch(latchCount);
+        }
+
+        /**
+         * Await the countdown latch on the finish trigger
+         * 
+         * @param pathWatcher
+         *            the watcher instance we are waiting on
+         * @throws IOException
+         *             if unable to create the finish tag file
+         * @throws InterruptedException
+         *             if unable to await the finish of the run
+         * @see #setFinishTrigger(Path, PathWatchEventType)
+         */
+        public void awaitFinish(PathWatcher pathWatcher) throws IOException, InterruptedException
+        {
+            //assertThat("Trigger Path must be set",triggerPath,notNullValue());
+            //assertThat("Trigger Type must be set",triggerType,notNullValue());
+            double multiplier = 25.0;
+            long awaitMillis = (long)((double)pathWatcher.getUpdateQuietTimeMillis() * multiplier);
+            LOG.debug("Waiting for finish ({} ms)",awaitMillis);
+            assertThat("Timed Out (" + awaitMillis + "ms) waiting for capture to finish",finishedLatch.await(awaitMillis,TimeUnit.MILLISECONDS),is(true));
+            LOG.debug("Finished capture");
+        }
+    }
+
+    private static void updateFile(Path path, String newContents) throws IOException
+    {
+        try (FileOutputStream out = new FileOutputStream(path.toFile()))
+        {
+            out.write(newContents.getBytes(StandardCharsets.UTF_8));
+            out.flush();
+            out.getChannel().force(true);
+            out.getFD().sync();
+        }
+    }
+
+    /**
+     * Update (optionally create) a file over time.
+     * <p>
+     * The file will be created in a slowed down fashion, over the time specified.
+     * 
+     * @param path
+     *            the file to update / create
+     * @param fileSize
+     *            the ultimate file size to create
+     * @param timeDuration
+     *            the time duration to take to create the file (approximate, not 100% accurate)
+     * @param timeUnit
+     *            the time unit to take to create the file
+     * @throws IOException
+     *             if unable to write file
+     * @throws InterruptedException
+     *             if sleep between writes was interrupted
+     */
+    private void updateFileOverTime(Path path, int fileSize, int timeDuration, TimeUnit timeUnit) throws IOException, InterruptedException
+    {
+        // how long to sleep between writes
+        int sleepMs = 100;
+
+        // how many millis to spend writing entire file size
+        long totalMs = timeUnit.toMillis(timeDuration);
+
+        // how many write chunks to write
+        int writeCount = (int)((int)totalMs / (int)sleepMs);
+
+        // average chunk buffer
+        int chunkBufLen = fileSize / writeCount;
+        byte chunkBuf[] = new byte[chunkBufLen];
+        Arrays.fill(chunkBuf,(byte)'x');
+
+        try (FileOutputStream out = new FileOutputStream(path.toFile()))
+        {
+            int left = fileSize;
+
+            while (left > 0)
+            {
+                int len = Math.min(left,chunkBufLen);
+                out.write(chunkBuf,0,len);
+                left -= chunkBufLen;
+                out.flush();
+                out.getChannel().force(true);
+                // Force file to actually write to disk.
+                // Skipping any sort of filesystem caching of the write
+                out.getFD().sync();
+                TimeUnit.MILLISECONDS.sleep(sleepMs);
+            }
+        }
+    }
+
+    /**
+     * Sleep longer than the quiet time.
+     * 
+     * @param pathWatcher
+     *            the path watcher to inspect for its quiet time
+     * @throws InterruptedException
+     *             if unable to sleep
+     */
+    private static void awaitQuietTime(PathWatcher pathWatcher) throws InterruptedException
+    {
+        double multiplier = 5.0;
+        if (OS.IS_WINDOWS)
+        {
+            // Microsoft Windows filesystem is too slow for a lower multiplier
+            multiplier = 6.0;
+        }
+        TimeUnit.MILLISECONDS.sleep((long)((double)pathWatcher.getUpdateQuietTimeMillis() * multiplier));
+    }
+
+    private static final int KB = 1024;
+    private static final int MB = KB * KB;
+
+    @Rule
+    public TestingDir testdir = new TestingDir();
+
+    @Test
+    public void testConfig_ShouldRecurse_0() throws IOException
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Create a few directories
+        Files.createDirectories(dir.resolve("a/b/c/d"));
+
+        PathWatcher.Config config = new PathWatcher.Config(dir);
+
+        config.setRecurseDepth(0);
+        assertThat("Config.recurse[0].shouldRecurse[./a/b]",config.shouldRecurseDirectory(dir.resolve("a/b")),is(false));
+        assertThat("Config.recurse[0].shouldRecurse[./a]",config.shouldRecurseDirectory(dir.resolve("a")),is(false));
+        assertThat("Config.recurse[0].shouldRecurse[./]",config.shouldRecurseDirectory(dir),is(false));
+    }
+
+    @Test
+    public void testConfig_ShouldRecurse_1() throws IOException
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Create a few directories
+        Files.createDirectories(dir.resolve("a/b/c/d"));
+
+        PathWatcher.Config config = new PathWatcher.Config(dir);
+
+        config.setRecurseDepth(1);
+        assertThat("Config.recurse[1].shouldRecurse[./a/b]",config.shouldRecurseDirectory(dir.resolve("a/b")),is(false));
+        assertThat("Config.recurse[1].shouldRecurse[./a]",config.shouldRecurseDirectory(dir.resolve("a")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./]",config.shouldRecurseDirectory(dir),is(true));
+    }
+
+    @Test
+    public void testConfig_ShouldRecurse_2() throws IOException
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Create a few directories
+        Files.createDirectories(dir.resolve("a/b/c/d"));
+
+        PathWatcher.Config config = new PathWatcher.Config(dir);
+
+        config.setRecurseDepth(2);
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c]",config.shouldRecurseDirectory(dir.resolve("a/b/c")),is(false));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b]",config.shouldRecurseDirectory(dir.resolve("a/b")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a]",config.shouldRecurseDirectory(dir.resolve("a")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./]",config.shouldRecurseDirectory(dir),is(true));
+    }
+    
+    
+    @Test
+    public void testConfig_ShouldRecurse_3() throws IOException
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+        
+        //Create some deep dirs
+        Files.createDirectories(dir.resolve("a/b/c/d/e/f/g"));
+        
+        PathWatcher.Config config = new PathWatcher.Config(dir);
+        config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c/d/g]",config.shouldRecurseDirectory(dir.resolve("a/b/c/d/g")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c/d/f]",config.shouldRecurseDirectory(dir.resolve("a/b/c/d/f")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c/d/e]",config.shouldRecurseDirectory(dir.resolve("a/b/c/d/e")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c/d]",config.shouldRecurseDirectory(dir.resolve("a/b/c/d")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b/c]",config.shouldRecurseDirectory(dir.resolve("a/b/c")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a/b]",config.shouldRecurseDirectory(dir.resolve("a/b")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./a]",config.shouldRecurseDirectory(dir.resolve("a")),is(true));
+        assertThat("Config.recurse[1].shouldRecurse[./]",config.shouldRecurseDirectory(dir),is(true));
+    }
+    
+    @Test
+    public void testRestart() throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+        Files.createDirectories(dir.resolve("b/c"));
+        Files.createFile(dir.resolve("a.txt"));
+        Files.createFile(dir.resolve("b.txt"));
+        
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setNotifyExistingOnStart(true);
+        pathWatcher.setUpdateQuietTime(500,TimeUnit.MILLISECONDS);
+        
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        capture.setFinishTrigger(2);
+        pathWatcher.addListener(capture);
+
+      
+        PathWatcher.Config config = new PathWatcher.Config(dir);
+        config.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+        config.addIncludeGlobRelative("*.txt");
+        pathWatcher.watch(config);
+        try
+        {
+            pathWatcher.start();
+
+            // Let quiet time do its thing
+            awaitQuietTime(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+            
+         
+            expected.put("a.txt",new PathWatchEventType[] {ADDED});
+            expected.put("b.txt",new PathWatchEventType[] {ADDED});
+
+         
+            capture.assertEvents(expected);
+            
+            //stop it
+            pathWatcher.stop();
+            
+            capture.reset();
+            
+            Thread.currentThread().sleep(1000);
+            
+            pathWatcher.start();
+            
+            awaitQuietTime(pathWatcher);
+            
+            capture.assertEvents(expected);
+            
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+
+    /**
+     * When starting up the PathWatcher, the events should occur
+     * indicating files that are of interest that already exist
+     * on the filesystem.
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testStartupFindFiles() throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Files we are interested in
+        Files.createFile(dir.resolve("foo.war"));
+        Files.createDirectories(dir.resolve("bar/WEB-INF"));
+        Files.createFile(dir.resolve("bar/WEB-INF/web.xml"));
+
+        // Files we don't care about
+        Files.createFile(dir.resolve("foo.war.backup"));
+        Files.createFile(dir.resolve(".hidden.war"));
+        Files.createDirectories(dir.resolve(".wat/WEB-INF"));
+        Files.createFile(dir.resolve(".wat/huh.war"));
+        Files.createFile(dir.resolve(".wat/WEB-INF/web.xml"));
+
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setUpdateQuietTime(300,TimeUnit.MILLISECONDS);
+
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        pathWatcher.addListener(capture);
+
+        // Add test dir configuration
+        PathWatcher.Config baseDirConfig = new PathWatcher.Config(dir);
+        baseDirConfig.setRecurseDepth(2);
+        baseDirConfig.addExcludeHidden();
+        baseDirConfig.addIncludeGlobRelative("*.war");
+        baseDirConfig.addIncludeGlobRelative("*/WEB-INF/web.xml");
+        pathWatcher.watch(baseDirConfig);
+
+        try
+        {
+            pathWatcher.start();
+
+            // Let quiet time do its thing
+            awaitQuietTime(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+
+            expected.put("bar/WEB-INF/web.xml",new PathWatchEventType[] { ADDED });
+            expected.put("foo.war",new PathWatchEventType[] { ADDED });
+
+            capture.assertEvents(expected);
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+    
+    @Test
+    public void testGlobPattern () throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Files we are interested in
+        Files.createFile(dir.resolve("a.txt"));
+        Files.createDirectories(dir.resolve("b/b.txt"));
+        Files.createDirectories(dir.resolve("c/d"));
+        Files.createFile(dir.resolve("c/d/d.txt"));
+        Files.createFile(dir.resolve(".foo.txt"));
+
+        // Files we don't care about
+        Files.createFile(dir.resolve("txt.foo"));
+        Files.createFile(dir.resolve("b/foo.xml"));
+    
+
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setUpdateQuietTime(300,TimeUnit.MILLISECONDS);
+
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        capture.setFinishTrigger(3);
+        pathWatcher.addListener(capture);
+
+        // Add test dir configuration
+        PathWatcher.Config baseDirConfig = new PathWatcher.Config(dir);
+        baseDirConfig.setRecurseDepth(PathWatcher.Config.UNLIMITED_DEPTH);
+        baseDirConfig.addExcludeHidden();
+        baseDirConfig.addIncludeGlobRelative("**.txt");
+        pathWatcher.watch(baseDirConfig);
+
+        try
+        {
+            pathWatcher.start();
+
+            // Let quiet time do its thing
+            awaitQuietTime(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+
+            expected.put("a.txt",new PathWatchEventType[] { ADDED });
+            expected.put("b/b.txt",new PathWatchEventType[] { ADDED });
+            expected.put("c/d/d.txt",new PathWatchEventType[] { ADDED });
+            capture.assertEvents(expected);
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+
+    @Test
+    public void testDeployFiles_Update_Delete() throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Files we are interested in
+        Files.createFile(dir.resolve("foo.war"));
+        Files.createDirectories(dir.resolve("bar/WEB-INF"));
+        Files.createFile(dir.resolve("bar/WEB-INF/web.xml"));
+
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setUpdateQuietTime(300,TimeUnit.MILLISECONDS);
+
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        capture.setFinishTrigger(5);
+        pathWatcher.addListener(capture);
+
+        // Add test dir configuration
+        PathWatcher.Config baseDirConfig = new PathWatcher.Config(dir);
+        baseDirConfig.setRecurseDepth(2);
+        baseDirConfig.addExcludeHidden();
+        baseDirConfig.addIncludeGlobRelative("*.war");
+        baseDirConfig.addIncludeGlobRelative("*/WEB-INF/web.xml");
+        pathWatcher.watch(baseDirConfig);
+
+        try
+        {
+            pathWatcher.start();
+
+            // Pretend that startup occurred
+            awaitQuietTime(pathWatcher);
+
+            // Update web.xml
+            Path webFile = dir.resolve("bar/WEB-INF/web.xml");
+            //capture.setFinishTrigger(webFile,MODIFIED);
+            updateFile(webFile,"Hello Update");
+
+            // Delete war
+            Files.delete(dir.resolve("foo.war"));
+
+            // Add a another new war
+            Files.createFile(dir.resolve("bar.war"));
+
+            // Let capture complete
+            capture.awaitFinish(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+
+            expected.put("bar/WEB-INF/web.xml",new PathWatchEventType[] { ADDED, MODIFIED });
+            expected.put("foo.war",new PathWatchEventType[] { ADDED, DELETED });
+            expected.put("bar.war",new PathWatchEventType[] { ADDED });
+
+            capture.assertEvents(expected);
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+
+    @Test
+    public void testDeployFiles_NewWar() throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Files we are interested in
+        Files.createFile(dir.resolve("foo.war"));
+        Files.createDirectories(dir.resolve("bar/WEB-INF"));
+        Files.createFile(dir.resolve("bar/WEB-INF/web.xml"));
+
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setUpdateQuietTime(300,TimeUnit.MILLISECONDS);
+
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        pathWatcher.addListener(capture);
+
+        // Add test dir configuration
+        PathWatcher.Config baseDirConfig = new PathWatcher.Config(dir);
+        baseDirConfig.setRecurseDepth(2);
+        baseDirConfig.addExcludeHidden();
+        baseDirConfig.addIncludeGlobRelative("*.war");
+        baseDirConfig.addIncludeGlobRelative("*/WEB-INF/web.xml");
+        pathWatcher.watch(baseDirConfig);
+
+        try
+        {
+            pathWatcher.start();
+
+            // Pretend that startup occurred
+            awaitQuietTime(pathWatcher);
+
+            // New war added
+            Path warFile = dir.resolve("hello.war");
+            capture.setFinishTrigger(warFile,MODIFIED);
+            updateFile(warFile,"Hello Update");
+
+            // Let capture finish
+            capture.awaitFinish(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+
+            expected.put("bar/WEB-INF/web.xml",new PathWatchEventType[] { ADDED });
+            expected.put("foo.war",new PathWatchEventType[] { ADDED });
+            expected.put("hello.war",new PathWatchEventType[] { ADDED, MODIFIED });
+
+            capture.assertEvents(expected);
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+
+    /**
+     * Pretend to add a new war file that is large, and being copied into place
+     * using some sort of technique that is slow enough that it takes a while for
+     * the entire war file to exist in place.
+     * <p>
+     * This is to test the quiet time logic to ensure that only a single MODIFIED event occurs on this new war file
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testDeployFiles_NewWar_LargeSlowCopy() throws Exception
+    {
+        Path dir = testdir.getEmptyDir().toPath();
+
+        // Files we are interested in
+        Files.createFile(dir.resolve("foo.war"));
+        Files.createDirectories(dir.resolve("bar/WEB-INF"));
+        Files.createFile(dir.resolve("bar/WEB-INF/web.xml"));
+
+        PathWatcher pathWatcher = new PathWatcher();
+        pathWatcher.setUpdateQuietTime(500,TimeUnit.MILLISECONDS);
+
+        // Add listener
+        PathWatchEventCapture capture = new PathWatchEventCapture(dir);
+        pathWatcher.addListener(capture);
+
+        // Add test dir configuration
+        PathWatcher.Config baseDirConfig = new PathWatcher.Config(dir);
+        baseDirConfig.setRecurseDepth(2);
+        baseDirConfig.addExcludeHidden();
+        baseDirConfig.addIncludeGlobRelative("*.war");
+        baseDirConfig.addIncludeGlobRelative("*/WEB-INF/web.xml");
+        pathWatcher.watch(baseDirConfig);
+
+        try
+        {
+            pathWatcher.start();
+
+            // Pretend that startup occurred
+            awaitQuietTime(pathWatcher);
+
+            // New war added (slowly)
+            Path warFile = dir.resolve("hello.war");
+            capture.setFinishTrigger(warFile,MODIFIED);
+            updateFileOverTime(warFile,50 * MB,3,TimeUnit.SECONDS);
+
+            // Let capture finish
+            capture.awaitFinish(pathWatcher);
+
+            Map<String, PathWatchEventType[]> expected = new HashMap<>();
+
+            expected.put("bar/WEB-INF/web.xml",new PathWatchEventType[] { ADDED });
+            expected.put("foo.war",new PathWatchEventType[] { ADDED });
+            expected.put("hello.war",new PathWatchEventType[] { ADDED, MODIFIED });
+
+            capture.assertEvents(expected);
+        }
+        finally
+        {
+            pathWatcher.stop();
+        }
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
index e781e25..6ffaa62 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ScannerTest.java
@@ -50,8 +50,12 @@
     @BeforeClass
     public static void setUpBeforeClass() throws Exception
     {
-        _directory = MavenTestingUtils.getTargetTestingDir(ScannerTest.class.getSimpleName());
-        FS.ensureEmpty(_directory);
+        File testDir = MavenTestingUtils.getTargetTestingDir(ScannerTest.class.getSimpleName());
+        FS.ensureEmpty(testDir);
+        
+        // Use full path, pointing to a real directory (for FileSystems that are case-insensitive, like Windows and OSX to use)
+        // This is only needed for the various comparisons below to make sense.
+        _directory = testDir.toPath().toRealPath().toFile();
 
         _scanner = new Scanner();
         _scanner.addScanDir(_directory);
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java
index 5b5ae2c..ac00964 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java
@@ -201,7 +201,7 @@
 
             blocker.succeeded();
             blocker.block();
-        };
+        }
         Assert.assertThat(System.currentTimeMillis()-start,Matchers.lessThan(600L)); 
         Assert.assertEquals(0,notComplete.get());     
     }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
index ddb9e67..ea4faf3 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java
@@ -60,8 +60,15 @@
     @Test
     public void testDecodePath()
     {
+        assertEquals("/foo/bar",URIUtil.decodePath("xx/foo/barxx",2,8));
+        assertEquals("/foo/bar",URIUtil.decodePath("/foo/bar"));
+        assertEquals("/f o/b r",URIUtil.decodePath("/f%20o/b%20r"));
+        assertEquals("/foo/bar",URIUtil.decodePath("/foo;ignore/bar;ignore"));
+        assertEquals("/fää/bar",URIUtil.decodePath("/fää;ignore/bar;ignore"));
+        assertEquals("/f\u0629\u0629%23/bar",URIUtil.decodePath("/f%d8%a9%d8%a9%2523;ignore/bar;ignore"));
+        
         assertEquals("foo%23;,:=b a r",URIUtil.decodePath("foo%2523%3b%2c:%3db%20a%20r;rubbish"));
-        assertEquals("foo%23;,:=b a r=",URIUtil.decodePath("xxxfoo%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish".getBytes(),3,30));
+        assertEquals("/foo/bar%23;,:=b a r=",URIUtil.decodePath("xxx/foo/bar%2523%3b%2c:%3db%20a%20r%3Dxxx;rubbish",3,35));
         assertEquals("fää%23;,:=b a r=",URIUtil.decodePath("fää%2523%3b%2c:%3db%20a%20r%3D"));
         assertEquals("f\u0629\u0629%23;,:=b a r",URIUtil.decodePath("f%d8%a9%d8%a9%2523%3b%2c:%3db%20a%20r"));
         
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
index 4610883..b45b0e2 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URLEncodedTest.java
@@ -165,9 +165,9 @@
         assertEquals("encoded param size",1, url_encoded.size());
         assertEquals("encoded get", "xx\ufffdyy", url_encoded.getString("Name15"));
 
-        byte[] bad="Name=%FF%FF%FF".getBytes(StandardCharsets.UTF_8);
+        String bad="Name=%FF%FF%FF";
         MultiMap<String> map = new MultiMap<String>();
-        UrlEncoded.decodeUtf8To(bad,0,bad.length,map);
+        UrlEncoded.decodeUtf8To(bad,map);
         assertEquals("encoded param size",1, map.size());
         assertEquals("encoded get", "\ufffd\ufffd\ufffd", map.getString("Name"));
         
@@ -214,7 +214,7 @@
         {
             ByteArrayInputStream in = new ByteArrayInputStream(("name\n=value+"+charsets[i][2]+"&name1=&name2&n\u00e3me3=value+3").getBytes(charsets[i][0]));
             MultiMap<String> m = new MultiMap<>();
-            UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]), -1,-1);
+            UrlEncoded.decodeTo(in, m, charsets[i][1]==null?null:Charset.forName(charsets[i][1]),-1,-1);
             assertEquals(charsets[i][1]+" stream length",4,m.size());
             assertEquals(charsets[i][1]+" stream name\\n","value 0",m.getString("name\n"));
             assertEquals(charsets[i][1]+" stream name1","",m.getString("name1"));
@@ -227,7 +227,7 @@
         {
             ByteArrayInputStream in2 = new ByteArrayInputStream("name=%83e%83X%83g".getBytes(StandardCharsets.ISO_8859_1));
             MultiMap<String> m2 = new MultiMap<>();
-            UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"), -1,-1);
+            UrlEncoded.decodeTo(in2, m2, Charset.forName("Shift_JIS"),-1,-1);
             assertEquals("stream length",1,m2.size());
             assertEquals("stream name","\u30c6\u30b9\u30c8",m2.getString("name"));
         }
@@ -279,12 +279,12 @@
 
         MultiMap<String> map = new MultiMap<>();
         UrlEncoded.LOG.info("EXPECT 4 Not Valid UTF8 warnings...");
-        UrlEncoded.decodeUtf8To(query.getBytes(StandardCharsets.ISO_8859_1),0,query.length(),map);
+        UrlEncoded.decodeUtf8To(query,0,query.length(),map);
         assertEquals("X"+Utf8Appendable.REPLACEMENT+Utf8Appendable.REPLACEMENT+"Z",map.getValue("name",0));
 
         map.clear();
 
-        UrlEncoded.decodeUtf8To(new ByteArrayInputStream(query.getBytes(StandardCharsets.ISO_8859_1)),map,100,2);
+        UrlEncoded.decodeUtf8To(new ByteArrayInputStream(query.getBytes(StandardCharsets.ISO_8859_1)),map,100,-1);
         assertEquals("X"+Utf8Appendable.REPLACEMENT+Utf8Appendable.REPLACEMENT+"Z",map.getValue("name",0));
     }
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java b/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java
index 9fb6483..312af88 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/UrlEncodedUtf8Test.java
@@ -40,7 +40,7 @@
         String test=new String(bytes,StandardCharsets.UTF_8);
         String expected = "c"+Utf8Appendable.REPLACEMENT;
 
-        fromByteArray(test,bytes,"ab",expected,false);
+        fromString(test,test,"ab",expected,false);
         fromInputStream(test,bytes,"ab",expected,false);
     }
 
@@ -51,7 +51,7 @@
         String test=new String(bytes,StandardCharsets.UTF_8);
         String expected = ""+Utf8Appendable.REPLACEMENT;
 
-        fromByteArray(test,bytes,"ab",expected,false);
+        fromString(test,test,"ab",expected,false);
         fromInputStream(test,bytes,"ab",expected,false);
         
     }
@@ -64,7 +64,7 @@
         String name = "e"+Utf8Appendable.REPLACEMENT;
         String value = "fg";
 
-        fromByteArray(test,bytes,name,value,false);
+        fromString(test,test,name,value,false);
         fromInputStream(test,bytes,name,value,false);
     }
     
@@ -76,9 +76,8 @@
         String name = "ef";
         String value = "g"+Utf8Appendable.REPLACEMENT;
 
-        fromByteArray(test,bytes,name,value,false);
+        fromString(test,test,name,value,false);
         fromInputStream(test,bytes,name,value,false);
-        
     }
 
     @Test
@@ -90,9 +89,8 @@
         String name = "a";
         String value = "a";
 
-        fromByteArray(test,bytes,name,value,false);
+        fromString(test,test,name,value,false);
         fromInputStream(test,bytes,name,value,false);
-        
     }
     
     @Test
@@ -104,9 +102,8 @@
         String name = "a";
         String value = ""+Utf8Appendable.REPLACEMENT;
 
-        fromByteArray(test,bytes,name,value,false);
+        fromString(test,test,name,value,false);
         fromInputStream(test,bytes,name,value,false);
-        
     }
     
     @Test
@@ -118,18 +115,16 @@
         String name = "a";
         String value = ""+Utf8Appendable.REPLACEMENT;
 
-        fromByteArray(test,bytes,name,value,false);
+        fromString(test,test,name,value,false);
         fromInputStream(test,bytes,name,value,false);
-        
     }
 
-    static void fromByteArray(String test,byte[] b,String field,String expected,boolean thrown) throws Exception
+    static void fromString(String test,String s,String field,String expected,boolean thrown) throws Exception
     {
         MultiMap<String> values=new MultiMap<>();
         try
         {
-            //safeDecodeUtf8To(b, 0, b.length, values);
-            UrlEncoded.decodeUtf8To(b, 0, b.length, values);
+            UrlEncoded.decodeUtf8To(s, 0, s.length(), values);
             if (thrown)
                 Assert.fail();
             Assert.assertEquals(test, expected, values.getString(field));
@@ -148,8 +143,7 @@
         MultiMap<String> values=new MultiMap<>();
         try
         {
-            //safeDecodeUtf8To(is, values, 1000000, 10000000);
-            UrlEncoded.decodeUtf8To(is, values, 1000000, 10000000);
+            UrlEncoded.decodeUtf8To(is, values, 1000000,-1);
             if (thrown)
                 Assert.fail();
             Assert.assertEquals(test, expected, values.getString(field));
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
index b78d4d4..fb1c56d 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/LifeCycleListenerNestedTest.java
@@ -18,21 +18,27 @@
 
 package org.eclipse.jetty.util.component;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.hamcrest.Matcher;
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
  * Testing for LifeCycleListener events on nested components
  * during runtime.
  */
+@Ignore
 public class LifeCycleListenerNestedTest
 {
+    // Set this true to use test-specific workaround.
+    private final boolean WORKAROUND = false;
+    
     public static class Foo extends ContainerLifeCycle
     {
         @Override
@@ -153,18 +159,18 @@
         @Override
         public void beanAdded(Container parent, Object child)
         {
-            if(child instanceof ContainerLifeCycle)
+            if(child instanceof LifeCycle)
             {
-                ((ContainerLifeCycle)child).addLifeCycleListener(this);
+                ((LifeCycle)child).addLifeCycleListener(this);
             }
         }
 
         @Override
         public void beanRemoved(Container parent, Object child)
         {
-            if(child instanceof ContainerLifeCycle)
+            if(child instanceof LifeCycle)
             {
-                ((ContainerLifeCycle)child).removeLifeCycleListener(this);
+                ((LifeCycle)child).removeLifeCycleListener(this);
             }
         }
     }
@@ -180,7 +186,8 @@
 
         CapturingListener listener = new CapturingListener();
         foo.addLifeCycleListener(listener);
-        foo.addEventListener(listener);
+        if(WORKAROUND)
+            foo.addEventListener(listener);
 
         try
         {
@@ -210,7 +217,8 @@
 
         CapturingListener listener = new CapturingListener();
         foo.addLifeCycleListener(listener);
-        foo.addEventListener(listener);
+        if(WORKAROUND)
+            foo.addEventListener(listener);
 
         Bar bara = new Bar("a");
         Bar barb = new Bar("b");
@@ -247,7 +255,8 @@
 
         CapturingListener listener = new CapturingListener();
         foo.addLifeCycleListener(listener);
-        foo.addEventListener(listener);
+        if(WORKAROUND)
+            foo.addEventListener(listener);
 
         try
         {
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java
index e0ba4c4..d4a128c 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/log/StdErrLogTest.java
@@ -39,6 +39,11 @@
  */
 public class StdErrLogTest
 {
+    static
+    {
+        StdErrLog.setTagPad(0);
+    }
+    
     @Before
     public void before()
     {
@@ -156,6 +161,7 @@
 
     /**
      * Test to make sure that using a Null parameter on parameterized messages does not result in a NPE
+     * @throws NullPointerException failed test
      */
     @Test
     public void testParameterizedMessage_NullValues() throws NullPointerException
@@ -302,6 +308,7 @@
      * Tests StdErrLog.warn() methods with level filtering.
      * <p>
      * Should always see WARN level messages, regardless of set level.
+     * @throws UnsupportedEncodingException failed test
      */
     @Test
     public void testWarnFiltering() throws UnsupportedEncodingException
@@ -341,6 +348,7 @@
      * Tests StdErrLog.info() methods with level filtering.
      * <p>
      * Should only see INFO level messages when level is set to {@link StdErrLog#LEVEL_INFO} and below.
+     * @throws UnsupportedEncodingException failed test
      */
     @Test
     public void testInfoFiltering() throws UnsupportedEncodingException
@@ -386,6 +394,7 @@
 
     /**
      * Tests {@link StdErrLog#LEVEL_OFF} filtering.
+     * @throws UnsupportedEncodingException failed test
      */
     @Test
     public void testOffFiltering() throws UnsupportedEncodingException
@@ -413,6 +422,7 @@
      * Tests StdErrLog.debug() methods with level filtering.
      * <p>
      * Should only see DEBUG level messages when level is set to {@link StdErrLog#LEVEL_DEBUG} and below.
+     * @throws UnsupportedEncodingException failed test
      */
     @Test
     public void testDebugFiltering() throws UnsupportedEncodingException
@@ -461,6 +471,7 @@
      * Tests StdErrLog with {@link Logger#ignore(Throwable)} use.
      * <p>
      * Should only see IGNORED level messages when level is set to {@link StdErrLog#LEVEL_ALL}.
+     * @throws UnsupportedEncodingException failed test
      */
     @Test
     public void testIgnores() throws UnsupportedEncodingException
@@ -605,7 +616,7 @@
     @Test
     public void testGetChildLogger_NullParent()
     {
-        StdErrLog log = new StdErrLog(null,new Properties());
+        AbstractLogger log = new StdErrLog(null,new Properties());
 
         Assert.assertThat("Logger.name", log.getName(), is(""));
 
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java
deleted file mode 100644
index deaff22..0000000
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/AbstractFSResourceTest.java
+++ /dev/null
@@ -1,535 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.resource;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.URI;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.file.FileSystemException;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.eclipse.jetty.toolchain.test.FS;
-import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.OS;
-import org.eclipse.jetty.toolchain.test.TestingDir;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.CollectionAssert;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-
-public abstract class AbstractFSResourceTest
-{
-    @Rule
-    public TestingDir testdir = new TestingDir();
-
-    public abstract Resource newResource(URI uri) throws IOException;
-
-    public abstract Resource newResource(File file) throws IOException;
-
-    private URI createEmptyFile(String name) throws IOException
-    {
-        File file = testdir.getFile(name);
-        file.createNewFile();
-        return file.toURI();
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testNonAbsoluteURI() throws Exception
-    {
-        newResource(new URI("path/to/resource"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testNotFileURI() throws Exception
-    {
-        newResource(new URI("http://www.eclipse.org/jetty/"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testBogusFilename() throws Exception
-    {
-        if (OS.IS_UNIX)
-        {
-            // A windows path is invalid under unix
-            newResource(new URI("file://Z:/:"));
-        }
-        else if (OS.IS_WINDOWS)
-        {
-            // "CON" is a reserved name under windows
-            newResource(new URI("file://CON"));
-        }
-        else
-        {
-            assumeFalse("Unknown OS type",false);
-        }   
-    }
-
-    @Test
-    public void testIsContainedIn() throws Exception
-    {
-        createEmptyFile("foo");
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("is contained in",res.isContainedIn(base),is(false));
-        }
-    }
-
-    @Test
-    public void testAddPath() throws Exception
-    {
-        File dir = testdir.getDir();
-        File subdir = new File(dir,"sub");
-        FS.ensureDirExists(subdir);
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource sub = base.addPath("sub");
-            assertThat("sub/.isDirectory",sub.isDirectory(),is(true));
-            
-            Resource tmp = sub.addPath("/tmp");
-            assertThat("No root",tmp.exists(),is(false));
-        }
-    }
-    
-    @Test
-    public void testIsDirectory() throws Exception
-    {
-        File dir = testdir.getDir();
-        createEmptyFile("foo");
-
-        File subdir = new File(dir,"sub");
-        FS.ensureDirExists(subdir);
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("foo.isDirectory",res.isDirectory(),is(false));
-
-            Resource sub = base.addPath("sub");
-            assertThat("sub/.isDirectory",sub.isDirectory(),is(true));
-        }
-    }
-
-    @Test
-    public void testLastModified() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        long expected = file.lastModified();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("foo.lastModified",res.lastModified(),is(expected));
-        }
-    }
-
-    @Test
-    public void testLastModified_NotExists() throws Exception
-    {
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("foo.lastModified",res.lastModified(),is(0L));
-        }
-    }
-
-    @Test
-    public void testLength() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        try (StringReader reader = new StringReader("foo"); FileWriter writer = new FileWriter(file))
-        {
-            IO.copy(reader,writer);
-        }
-
-        long expected = file.length();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("foo.length",res.length(),is(expected));
-        }
-    }
-
-    @Test
-    public void testLength_NotExists() throws Exception
-    {
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo");
-            assertThat("foo.length",res.length(),is(0L));
-        }
-    }
-
-    @Test
-    public void testDelete() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            // Is it there?
-            Resource res = base.addPath("foo");
-            assertThat("foo.exists",res.exists(),is(true));
-            // delete it
-            assertThat("foo.delete",res.delete(),is(true));
-            // is it there?
-            assertThat("foo.exists",res.exists(),is(false));
-        }
-    }
-
-    @Test
-    public void testDelete_NotExists() throws Exception
-    {
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            // Is it there?
-            Resource res = base.addPath("foo");
-            assertThat("foo.exists",res.exists(),is(false));
-            // delete it
-            assertThat("foo.delete",res.delete(),is(false));
-            // is it there?
-            assertThat("foo.exists",res.exists(),is(false));
-        }
-    }
-
-    @Test
-    public void testName() throws Exception
-    {
-        String expected = testdir.getDir().getAbsolutePath();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            assertThat("base.name",base.getName(),is(expected));
-        }
-    }
-
-    @Test
-    public void testInputStream() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        String content = "Foo is here";
-
-        try (StringReader reader = new StringReader(content); FileWriter writer = new FileWriter(file))
-        {
-            IO.copy(reader,writer);
-        }
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource foo = base.addPath("foo");
-            try (InputStream stream = foo.getInputStream(); InputStreamReader reader = new InputStreamReader(stream); StringWriter writer = new StringWriter())
-            {
-                IO.copy(reader,writer);
-                assertThat("Stream",writer.toString(),is(content));
-            }
-        }
-    }
-
-    @Test
-    public void testReadableByteChannel() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        String content = "Foo is here";
-
-        try (StringReader reader = new StringReader(content); FileWriter writer = new FileWriter(file))
-        {
-            IO.copy(reader,writer);
-        }
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource foo = base.addPath("foo");
-            try (ReadableByteChannel channel = foo.getReadableByteChannel())
-            {
-                ByteBuffer buf = ByteBuffer.allocate(256);
-                channel.read(buf);
-                buf.flip();
-                String actual = BufferUtil.toUTF8String(buf);
-                assertThat("ReadableByteChannel content",actual,is(content));
-            }
-        }
-    }
-    
-    @Test
-    public void testGetURI() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        URI expected = file.toURI();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource foo = base.addPath("foo");
-            assertThat("getURI",foo.getURI(),is(expected));
-        }
-    }
-
-    @Test
-    public void testGetURL() throws Exception
-    {
-        File file = testdir.getFile("foo");
-        file.createNewFile();
-
-        URL expected = file.toURI().toURL();
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource foo = base.addPath("foo");
-            assertThat("getURL",foo.getURL(),is(expected));
-        }
-    }
-    
-    @Test
-    public void testList() throws Exception
-    {
-        File dir = testdir.getDir();
-        FS.touch(new File(dir, "foo"));
-        FS.touch(new File(dir, "bar"));
-        FS.ensureDirExists(new File(dir, "tick"));
-        FS.ensureDirExists(new File(dir, "tock"));
-        
-        List<String> expected = new ArrayList<>();
-        expected.add("foo");
-        expected.add("bar");
-        expected.add("tick/");
-        expected.add("tock/");
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            String list[] = base.list();
-            List<String> actual = Arrays.asList(list);
-            
-            CollectionAssert.assertContainsUnordered("Resource Directory Listing",
-                    expected,actual);
-        }
-    }
-    
-    @Test
-    public void testSymlink() throws Exception
-    {
-        File dir = testdir.getDir();
-        
-        Path foo = new File(dir, "foo").toPath();
-        Path bar = new File(dir, "bar").toPath();
-        
-        try
-        {
-            Files.createFile(foo);
-            Files.createSymbolicLink(bar,foo);
-        }
-        catch (UnsupportedOperationException | FileSystemException e)
-        {
-            // if unable to create symlink, no point testing the rest
-            // this is the path that Microsoft Windows takes.
-            assumeNoException(e);
-        }
-        
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource resFoo = base.addPath("foo");
-            Resource resBar = base.addPath("bar");
-            
-            // Access to the same resource, but via a symlink means that they are not equivalent
-            assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
-            
-            assertThat("foo.alias", resFoo.getAlias(), nullValue());
-            assertThat("bar.alias", resBar.getAlias(), is(foo.toUri()));
-        }
-    }
-    
-    @Test
-    public void testSemicolon() throws Exception
-    {
-        File dir = testdir.getDir();
-        
-        try
-        {
-            // attempt to create file
-            Path foo = new File(dir, "foo;").toPath();
-            Files.createFile(foo);
-        }
-        catch (Exception e)
-        {
-            // if unable to create file, no point testing the rest
-            // this is the path that Microsoft Windows takes.
-            assumeNoException(e);
-        }
-
-        try (Resource base = newResource(testdir.getDir()))
-        {
-            Resource res = base.addPath("foo;");
-            assertThat("Alias: " + res,res.getAlias(),nullValue());
-        }
-    }
-
-    @Test
-    public void testExist_Normal() throws Exception
-    {
-        createEmptyFile("a.jsp");
-
-        URI ref = testdir.getDir().toURI().resolve("a.jsp");
-        try (Resource fileres = newResource(ref))
-        {
-            assertThat("Resource: " + fileres,fileres.exists(),is(true));
-        }
-    }
-
-    @Test
-    public void testSingleQuoteInFileName() throws Exception
-    {
-        createEmptyFile("foo's.txt");
-        createEmptyFile("f o's.txt");
-
-        URI refQuoted = testdir.getDir().toURI().resolve("foo's.txt");
-
-        try (Resource fileres = newResource(refQuoted))
-        {
-            assertThat("Exists: " + refQuoted,fileres.exists(),is(true));
-            assertThat("Alias: " + refQuoted,fileres.getAlias(),nullValue());
-        }
-
-        URI refEncoded = testdir.getDir().toURI().resolve("foo%27s.txt");
-
-        try (Resource fileres = newResource(refEncoded))
-        {
-            assertThat("Exists: " + refEncoded,fileres.exists(),is(true));
-            assertThat("Alias: " + refEncoded,fileres.getAlias(),nullValue());
-        }
-
-        URI refQuoteSpace = testdir.getDir().toURI().resolve("f%20o's.txt");
-
-        try (Resource fileres = newResource(refQuoteSpace))
-        {
-            assertThat("Exists: " + refQuoteSpace,fileres.exists(),is(true));
-            assertThat("Alias: " + refQuoteSpace,fileres.getAlias(),nullValue());
-        }
-
-        URI refEncodedSpace = testdir.getDir().toURI().resolve("f%20o%27s.txt");
-
-        try (Resource fileres = newResource(refEncodedSpace))
-        {
-            assertThat("Exists: " + refEncodedSpace,fileres.exists(),is(true));
-            assertThat("Alias: " + refEncodedSpace,fileres.getAlias(),nullValue());
-        }
-
-        URI refA = testdir.getDir().toURI().resolve("foo's.txt");
-        URI refB = testdir.getDir().toURI().resolve("foo%27s.txt");
-
-        StringBuilder msg = new StringBuilder();
-        msg.append("URI[a].equals(URI[b])").append(System.lineSeparator());
-        msg.append("URI[a] = ").append(refA).append(System.lineSeparator());
-        msg.append("URI[b] = ").append(refB);
-
-        // show that simple URI.equals() doesn't work
-        assertThat(msg.toString(),refA.equals(refB),is(false));
-
-        // now show that Resource.equals() does work
-        try (Resource a = newResource(refA); Resource b = newResource(refB);)
-        {
-            assertThat("A.equals(B)",a.equals(b),is(true));
-        }
-    }
-
-    @Test
-    public void testExist_BadNull() throws Exception
-    {
-        createEmptyFile("a.jsp");
-
-        try
-        {
-            // request with null at end
-            URI ref = testdir.getDir().toURI().resolve("a.jsp%00");
-            assertThat("Null URI",ref,notNullValue());
-
-            newResource(ref);
-            fail("Should have thrown " + InvalidPathException.class);
-        }
-        catch (InvalidPathException e)
-        {
-            // Expected path
-        }
-    }
-
-    @Test
-    public void testExist_BadNullX() throws Exception
-    {
-        createEmptyFile("a.jsp");
-
-        try
-        {
-            // request with null and x at end
-            URI ref = testdir.getDir().toURI().resolve("a.jsp%00x");
-            assertThat("NullX URI",ref,notNullValue());
-
-            newResource(ref);
-            fail("Should have thrown " + InvalidPathException.class);
-        }
-        catch (InvalidPathException e)
-        {
-            // Expected path
-        }
-    }
-    
-    @Test
-    public void testUtf8Dir() throws Exception
-    {
-        File dir=new File(testdir.getDir(),"bãm");
-        dir.mkdir();
-        File file = new File(dir,"file.txt");
-        file.createNewFile();
-        
-        Resource base = newResource(dir);
-        Assert.assertNull(base.getAlias());
-        
-        Resource r = base.addPath("file.txt");
-        Assert.assertNull(r.getAlias());
-        
-    }
-}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java
new file mode 100644
index 0000000..94c8264
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ClassPathResourceTest.java
@@ -0,0 +1,112 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.resource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Test;
+
+public class ClassPathResourceTest
+{
+    /**
+     * Test a class path resource for existence.
+     */
+    @Test
+    public void testClassPathResourceClassRelative()
+    {
+        final String classPathName="Resource.class";
+
+        try(Resource resource=Resource.newClassPathResource(classPathName);)
+        {
+            // A class path cannot be a directory
+            assertFalse("Class path cannot be a directory.",resource.isDirectory());
+
+            // A class path must exist
+            assertTrue("Class path resource does not exist.",resource.exists());
+        }
+    }
+
+    /**
+     * Test a class path resource for existence.
+     */
+    @Test
+    public void testClassPathResourceClassAbsolute()
+    {
+        final String classPathName="/org/eclipse/jetty/util/resource/Resource.class";
+
+        Resource resource=Resource.newClassPathResource(classPathName);
+
+        // A class path cannot be a directory
+        assertFalse("Class path cannot be a directory.",resource.isDirectory());
+
+        // A class path must exist
+        assertTrue("Class path resource does not exist.",resource.exists());
+    }
+
+    /**
+     * Test a class path resource for directories.
+     * @throws Exception failed test
+     */
+    @Test
+    public void testClassPathResourceDirectory() throws Exception
+    {
+        final String classPathName="/";
+
+        Resource resource=Resource.newClassPathResource(classPathName);
+
+        // A class path must be a directory
+        assertTrue("Class path must be a directory.",resource.isDirectory());
+
+        assertTrue("Class path returned file must be a directory.",resource.getFile().isDirectory());
+
+        // A class path must exist
+        assertTrue("Class path resource does not exist.",resource.exists());
+    }
+
+    /**
+     * Test a class path resource for a file.
+     * @throws Exception failed test
+     */
+    @Test
+    public void testClassPathResourceFile() throws Exception
+    {
+        final String fileName="resource.txt";
+        final String classPathName="/"+fileName;
+
+        // Will locate a resource in the class path
+        Resource resource=Resource.newClassPathResource(classPathName);
+
+        // A class path cannot be a directory
+        assertFalse("Class path must be a directory.",resource.isDirectory());
+
+        assertTrue(resource!=null);
+
+        File file=resource.getFile();
+
+        assertEquals("File name from class path is not equal.",fileName,file.getName());
+        assertTrue("File returned from class path should be a file.",file.isFile());
+
+        // A class path must exist
+        assertTrue("Class path resource does not exist.",resource.exists());
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java
deleted file mode 100644
index ff63159..0000000
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileResourceTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.resource;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class FileResourceTest extends AbstractFSResourceTest
-{
-    @Override
-    public Resource newResource(URI uri) throws IOException
-    {
-        return new FileResource(uri);
-    }
-    
-    @Override
-    public Resource newResource(File file) throws IOException
-    {
-        return new FileResource(file);
-    }
-    
-    @Ignore("Cannot get null to be seen by FileResource")
-    @Test
-    public void testExist_BadNull() throws Exception
-    {
-    }
-
-    @Ignore("Validation shouldn't be done in FileResource")
-    @Test
-    public void testExist_BadNullX() throws Exception
-    {
-    }
-}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
new file mode 100644
index 0000000..25418ee
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
@@ -0,0 +1,1212 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.resource;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemException;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jetty.toolchain.test.FS;
+import org.eclipse.jetty.toolchain.test.IO;
+import org.eclipse.jetty.toolchain.test.OS;
+import org.eclipse.jetty.toolchain.test.TestingDir;
+import org.eclipse.jetty.util.BufferUtil;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FileSystemResourceTest
+{
+    @Rule
+    public TestingDir testdir = new TestingDir();
+    
+    private final Class<? extends Resource> _class;
+
+    @SuppressWarnings("deprecation")
+    @Parameters(name="{0}")
+    public static Collection<Object[]> data() 
+    {
+        List<Object[]> data = new ArrayList<>();
+        data.add(new Class<?>[]{FileResource.class});
+        data.add(new Class<?>[]{PathResource.class});
+        return data;
+    }
+    
+    public FileSystemResourceTest(Class<? extends Resource> test)
+    {
+        _class=test;
+    }
+    
+    public Resource newResource(URI uri) throws Exception
+    {
+        try
+        {
+            return _class.getConstructor(URI.class).newInstance(uri);
+        }
+        catch(InvocationTargetException e)
+        {
+            try
+            {
+                throw e.getTargetException();
+            }
+            catch(Exception|Error ex)
+            {
+                throw ex;
+            }
+            catch(Throwable th)
+            {
+                throw new Error(th);
+            }
+        }
+    }
+
+    public Resource newResource(File file) throws Exception
+    {
+        try
+        {
+            return _class.getConstructor(File.class).newInstance(file); 
+        }
+        catch(InvocationTargetException e)
+        {
+            try
+            {
+                throw e.getTargetException();
+            }
+            catch(Exception|Error ex)
+            {
+                throw ex;
+            }
+            catch(Throwable th)
+            {
+                throw new Error(th);
+            }
+        }
+    }
+    
+    private Matcher<Resource> hasNoAlias()
+    {
+        return new BaseMatcher<Resource>()
+        {
+            @Override
+            public boolean matches(Object item)
+            {
+                final Resource res = (Resource)item;
+                return !res.isAlias();
+            }
+
+            @Override
+            public void describeTo(Description description)
+            {
+                description.appendText("getAlias should return null");
+            }
+            
+            @Override
+            public void describeMismatch(Object item, Description description)
+            {
+                description.appendText("was ").appendValue(((Resource)item).getAlias());
+            }
+        };
+    }
+    
+    private Matcher<Resource> isAliasFor(final Resource resource)
+    {
+        return new BaseMatcher<Resource>()
+        {
+            @Override
+            public boolean matches(Object item)
+            {
+                final Resource ritem = (Resource)item;
+                final URI alias = ritem.getAlias();
+                if (alias == null)
+                {
+                    return ritem == null;
+                }
+                else
+                {
+                    return alias.equals(resource.getURI());
+                }
+            }
+
+            @Override
+            public void describeTo(Description description)
+            {
+                description.appendText("getAlias should return ").appendValue(resource.getURI());
+            }
+            
+            @Override
+            public void describeMismatch(Object item, Description description)
+            {
+                description.appendText("was ").appendValue(((Resource)item).getAlias());
+            }
+        };
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNonAbsoluteURI() throws Exception
+    {
+        newResource(new URI("path/to/resource"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNotFileURI() throws Exception
+    {
+        newResource(new URI("http://www.eclipse.org/jetty/"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBogusFilename() throws Exception
+    {
+        if (OS.IS_UNIX)
+        {
+            // A windows path is invalid under unix
+            newResource(new URI("file://Z:/:"));
+        }
+        else if (OS.IS_WINDOWS)
+        {
+            // "CON" is a reserved name under windows
+            newResource(new URI("file://CON"));
+        }
+        else
+        {
+            assumeFalse("Unknown OS type",false);
+        }   
+    }
+    
+    @Test
+    public void testAddPath() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        
+        Path subdir = dir.resolve("sub");
+        FS.ensureDirExists(subdir.toFile());
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource sub = base.addPath("sub");
+            assertThat("sub/.isDirectory",sub.isDirectory(),is(true));
+
+            Resource tmp = sub.addPath("/tmp");
+            assertThat("No root",tmp.exists(),is(false));
+        }
+    }
+
+    @Test
+    public void testAddRootPath() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path subdir = dir.resolve("sub");
+        Files.createDirectories(subdir);
+
+        String readableRootDir = findRootDir(dir.getFileSystem());
+        assumeThat("Readable Root Dir found",readableRootDir,notNullValue());
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource sub = base.addPath("sub");
+            assertThat("sub",sub.isDirectory(),is(true));
+
+            try
+            {
+                Resource rrd = sub.addPath(readableRootDir);
+                // valid path for unix and OSX
+                assertThat("Readable Root Dir",rrd.exists(),is(false));
+            }
+            catch (MalformedURLException | InvalidPathException e)
+            {
+                // valid path on Windows
+            }
+        }
+    }
+
+    private String findRootDir(FileSystem fs) throws IOException
+    {
+        // look for a directory off of a root path
+        for (Path rootDir : fs.getRootDirectories())
+        {
+            try (DirectoryStream<Path> dir = Files.newDirectoryStream(rootDir))
+            {
+                for (Path entry : dir)
+                {
+                    if (Files.isDirectory(entry) && !Files.isHidden(entry))
+                    {
+                        return entry.toAbsolutePath().toString();
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @Test
+    public void testIsContainedIn() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        Path foo = dir.resolve("foo");
+        Files.createFile(foo);
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("is contained in",res.isContainedIn(base),is(false));
+        }
+    }
+
+    @Test
+    public void testIsDirectory() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        Path foo = dir.resolve("foo");
+        Files.createFile(foo);
+
+        Path subdir = dir.resolve("sub");
+        Files.createDirectories(subdir);
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("foo.isDirectory",res.isDirectory(),is(false));
+
+            Resource sub = base.addPath("sub");
+            assertThat("sub/.isDirectory",sub.isDirectory(),is(true));
+        }
+    }
+
+    @Test
+    public void testLastModified() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        File file = testdir.getFile("foo");
+        file.createNewFile();
+
+        long expected = file.lastModified();
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("foo.lastModified",res.lastModified()/1000*1000, lessThanOrEqualTo(expected));
+        }
+    }
+
+    @Test
+    public void testLastModified_NotExists() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("foo.lastModified",res.lastModified(),is(0L));
+        }
+    }
+
+    @Test
+    public void testLength() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path file = dir.resolve("foo");
+
+        try (StringReader reader = new StringReader("foo");
+             BufferedWriter writer = Files.newBufferedWriter(file))
+        {
+            IO.copy(reader,writer);
+        }
+
+        long expected = Files.size(file);
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("foo.length",res.length(),is(expected));
+        }
+    }
+
+    @Test
+    public void testLength_NotExists() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo");
+            assertThat("foo.length",res.length(),is(0L));
+        }
+    }
+
+    @Test
+    public void testDelete() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        Path file = dir.resolve("foo");
+        Files.createFile(file);
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // Is it there?
+            Resource res = base.addPath("foo");
+            assertThat("foo.exists",res.exists(),is(true));
+            // delete it
+            assertThat("foo.delete",res.delete(),is(true));
+            // is it there?
+            assertThat("foo.exists",res.exists(),is(false));
+        }
+    }
+
+    @Test
+    public void testDelete_NotExists() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // Is it there?
+            Resource res = base.addPath("foo");
+            assertThat("foo.exists",res.exists(),is(false));
+            // delete it
+            assertThat("foo.delete",res.delete(),is(false));
+            // is it there?
+            assertThat("foo.exists",res.exists(),is(false));
+        }
+    }
+
+    @Test
+    public void testName() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        String expected = dir.toAbsolutePath().toString();
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            assertThat("base.name",base.getName(),is(expected));
+        }
+    }
+
+    @Test
+    public void testInputStream() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path file = dir.resolve("foo");
+        String content = "Foo is here";
+
+        try (StringReader reader = new StringReader(content);
+             BufferedWriter writer = Files.newBufferedWriter(file))
+        {
+            IO.copy(reader,writer);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource foo = base.addPath("foo");
+            try (InputStream stream = foo.getInputStream(); InputStreamReader reader = new InputStreamReader(stream); StringWriter writer = new StringWriter())
+            {
+                IO.copy(reader,writer);
+                assertThat("Stream",writer.toString(),is(content));
+            }
+        }
+    }
+
+    @Test
+    public void testReadableByteChannel() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path file = dir.resolve("foo");
+        String content = "Foo is here";
+
+        try (StringReader reader = new StringReader(content);
+             BufferedWriter writer = Files.newBufferedWriter(file))
+        {
+            IO.copy(reader,writer);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource foo = base.addPath("foo");
+            try (ReadableByteChannel channel = foo.getReadableByteChannel())
+            {
+                ByteBuffer buf = ByteBuffer.allocate(256);
+                channel.read(buf);
+                buf.flip();
+                String actual = BufferUtil.toUTF8String(buf);
+                assertThat("ReadableByteChannel content",actual,is(content));
+            }
+        }
+    }
+    
+    @Test
+    public void testGetURI() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path file = dir.resolve("foo");
+        Files.createFile(file);
+
+        URI expected = file.toUri();
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource foo = base.addPath("foo");
+            assertThat("getURI",foo.getURI(),is(expected));
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test
+    public void testGetURL() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path file = dir.resolve("foo");
+        Files.createFile(file);
+
+        URL expected = file.toUri().toURL();
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource foo = base.addPath("foo");
+            assertThat("getURL",foo.getURL(),is(expected));
+        }
+    }
+    
+    @Test
+    public void testList() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Files.createFile(dir.resolve("foo"));
+        Files.createFile(dir.resolve("bar"));
+        Files.createDirectories(dir.resolve("tick"));
+        Files.createDirectories(dir.resolve("tock"));
+        
+        List<String> expected = new ArrayList<>();
+        expected.add("foo");
+        expected.add("bar");
+        expected.add("tick/");
+        expected.add("tock/");
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            String list[] = base.list();
+            List<String> actual = Arrays.asList(list);
+            
+            assertEquals(expected.size(),actual.size());
+            for (String s : expected)
+                assertEquals(true,actual.contains(s));
+            
+        }
+    }
+    
+    @Test
+    public void testSymlink() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        
+        Path foo = dir.resolve("foo");
+        Path bar = dir.resolve("bar");
+        
+        try
+        {
+            Files.createFile(foo);
+            Files.createSymbolicLink(bar,foo);
+        }
+        catch (UnsupportedOperationException | FileSystemException e)
+        {
+            // if unable to create symlink, no point testing the rest
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource resFoo = base.addPath("foo");
+            Resource resBar = base.addPath("bar");
+            
+            assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri()));
+            
+            // Access to the same resource, but via a symlink means that they are not equivalent
+            assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
+            
+            assertThat("resource.alias", resFoo, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resFoo.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resFoo.getFile()), hasNoAlias());
+            
+            assertThat("alias", resBar, isAliasFor(resFoo));
+            assertThat("uri.alias", newResource(resBar.getURI()), isAliasFor(resFoo));
+            assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo));
+        }
+    }
+
+    @Test
+    public void testNonExistantSymlink() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path foo = dir.resolve("foo");
+        Path bar = dir.resolve("bar");
+        
+        try
+        {
+            Files.createSymbolicLink(bar,foo);
+        }
+        catch (UnsupportedOperationException | FileSystemException e)
+        {
+            // if unable to create symlink, no point testing the rest
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // FileResource does not pass this test!
+            assumeFalse(base instanceof FileResource);
+            
+            Resource resFoo = base.addPath("foo");
+            Resource resBar = base.addPath("bar");
+            
+            assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri()));
+            
+            // Access to the same resource, but via a symlink means that they are not equivalent
+            assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
+            
+            assertThat("resource.alias", resFoo, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resFoo.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resFoo.getFile()), hasNoAlias());
+            
+            assertThat("alias", resBar, isAliasFor(resFoo));
+            assertThat("uri.alias", newResource(resBar.getURI()), isAliasFor(resFoo));
+            assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo));
+        }
+    }
+
+    @Test
+    public void testCaseInsensitiveAlias() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        Path path = dir.resolve("file");
+        Files.createFile(path);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // Reference to actual resource that exists
+            Resource resource = base.addPath("file");
+                        
+            assertThat("resource.alias", resource, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias());
+
+            // On some case insensitive file systems, lets see if an alternate
+            // case for the filename results in an alias reference
+            Resource alias = base.addPath("FILE");
+            if (alias.exists())
+            {
+                // If it exists, it must be an alias
+                assertThat("alias", alias, isAliasFor(resource));
+                assertThat("alias.uri", newResource(alias.getURI()), isAliasFor(resource));
+                assertThat("alias.file", newResource(alias.getFile()), isAliasFor(resource));
+            }
+        }
+    }
+
+    /**
+     * Test for Windows feature that exposes 8.3 filename references
+     * for long filenames.
+     * <p>
+     * See: http://support.microsoft.com/kb/142982
+     * @throws Exception failed test
+     */
+    @Test
+    public void testCase8dot3Alias() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path path = dir.resolve("TextFile.Long.txt");
+        Files.createFile(path);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // Long filename
+            Resource resource = base.addPath("TextFile.Long.txt");
+                        
+            assertThat("resource.alias", resource, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias());
+
+            // On some versions of Windows, the long filename can be referenced
+            // via a short 8.3 equivalent filename.
+            Resource alias = base.addPath("TEXTFI~1.TXT");
+            if (alias.exists())
+            {
+                // If it exists, it must be an alias
+                assertThat("alias", alias, isAliasFor(resource));
+                assertThat("alias.uri", newResource(alias.getURI()), isAliasFor(resource));
+                assertThat("alias.file", newResource(alias.getFile()), isAliasFor(resource));
+            }
+        }
+    }
+
+    /**
+     * NTFS Alternative Data / File Streams.
+     * <p>
+     * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx
+     * @throws Exception failed test
+     */
+    @Test
+    public void testNTFSFileStreamAlias() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path path = dir.resolve("testfile");
+        Files.createFile(path);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource resource = base.addPath("testfile");
+                        
+            assertThat("resource.alias", resource, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias());
+
+            try
+            {
+                // Attempt to reference same file, but via NTFS simple stream
+                Resource alias = base.addPath("testfile:stream");
+                if (alias.exists())
+                {
+                    // If it exists, it must be an alias
+                    assertThat("resource.alias",alias,isAliasFor(resource));
+                    assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource));
+                    assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource));
+                }
+            }
+            catch (InvalidPathException e)
+            {
+                // NTFS filesystem streams are unsupported on some platforms.
+                assumeNoException(e);
+            }
+        }
+    }
+    
+    /**
+     * NTFS Alternative Data / File Streams.
+     * <p>
+     * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx
+     * @throws Exception failed test
+     */
+    @Test
+    public void testNTFSFileDataStreamAlias() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path path = dir.resolve("testfile");
+        Files.createFile(path);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource resource = base.addPath("testfile");
+                        
+            assertThat("resource.alias", resource, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias());
+
+            try
+            {
+                // Attempt to reference same file, but via NTFS DATA stream
+                Resource alias = base.addPath("testfile::$DATA");
+                if (alias.exists())
+                {
+                    assumeThat(alias.getURI().getScheme(), is("http"));
+                    
+                    // If it exists, it must be an alias
+                    assertThat("resource.alias",alias,isAliasFor(resource));
+                    assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource));
+                    assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource));
+                }
+            }
+            catch (InvalidPathException e)
+            {
+                // NTFS filesystem streams are unsupported on some platforms.
+                assumeNoException(e);
+            }
+        }
+    }
+    
+    /**
+     * NTFS Alternative Data / File Streams.
+     * <p>
+     * See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx
+     * @throws Exception failed test
+     */
+    @Test
+    public void testNTFSFileEncodedDataStreamAlias() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path path = dir.resolve("testfile");
+        Files.createFile(path);
+        
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource resource = base.addPath("testfile");
+                        
+            assertThat("resource.alias", resource, hasNoAlias());
+            assertThat("resource.uri.alias", newResource(resource.getURI()), hasNoAlias());
+            assertThat("resource.file.alias", newResource(resource.getFile()), hasNoAlias());
+
+            try
+            {
+                // Attempt to reference same file, but via NTFS DATA stream (encoded addPath version) 
+                Resource alias = base.addPath("testfile::%24DATA");
+                if (alias.exists())
+                {
+                    // If it exists, it must be an alias
+                    assertThat("resource.alias",alias,isAliasFor(resource));
+                    assertThat("resource.uri.alias",newResource(alias.getURI()),isAliasFor(resource));
+                    assertThat("resource.file.alias",newResource(alias.getFile()),isAliasFor(resource));
+                }
+            }
+            catch (InvalidPathException e)
+            {
+                // NTFS filesystem streams are unsupported on some platforms.
+                assumeNoException(e);
+            }
+        }
+    }
+    
+    @Test
+    public void testSemicolon() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo;");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo;");
+            assertThat("Alias: " + res,res,hasNoAlias());
+        }
+    }
+    
+    @Test
+    public void testSingleQuote() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo' bar");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo' bar");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+    
+    @Test
+    public void testSingleBackTick() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo` bar");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // FileResource does not pass this test!
+            assumeFalse(base instanceof FileResource);
+
+            Resource res = base.addPath("foo` bar");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+    
+    @Test
+    public void testBrackets() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo[1]");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            Resource res = base.addPath("foo[1]");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+    
+    @Test
+    public void testBraces() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo.{bar}.txt");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // FileResource does not pass this test!
+            assumeFalse(base instanceof FileResource);
+
+            Resource res = base.addPath("foo.{bar}.txt");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+    
+    @Test
+    public void testCaret() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo^3.txt");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // FileResource does not pass this test!
+            assumeFalse(base instanceof FileResource);
+
+            Resource res = base.addPath("foo^3.txt");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+    
+    @Test
+    public void testPipe() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        try
+        {
+            // attempt to create file
+            Path foo = dir.resolve("foo|bar.txt");
+            Files.createFile(foo);
+        }
+        catch (Exception e)
+        {
+            // if unable to create file, no point testing the rest.
+            // this is the path that Microsoft Windows takes.
+            assumeNoException(e);
+        }
+
+        try (Resource base = newResource(dir.toFile()))
+        {
+            // FileResource does not pass this test!
+            assumeFalse(base instanceof FileResource);
+
+            Resource res = base.addPath("foo|bar.txt");
+            assertThat("Alias: " + res,res.getAlias(),nullValue());
+        }
+    }
+
+    /**
+     * The most basic access example
+     * @throws Exception failed test
+     */
+    @Test
+    public void testExist_Normal() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path path = dir.resolve("a.jsp");
+        Files.createFile(path);
+
+        URI ref = testdir.getDir().toURI().resolve("a.jsp");
+        try (Resource fileres = newResource(ref))
+        {
+            assertThat("Resource: " + fileres,fileres.exists(),is(true));
+        }
+    }
+
+    @Test
+    public void testSingleQuoteInFileName() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path fooA = dir.resolve("foo's.txt");
+        Path fooB = dir.resolve("f o's.txt");
+        
+        Files.createFile(fooA);
+        Files.createFile(fooB);
+        
+        URI refQuoted = dir.resolve("foo's.txt").toUri();
+
+        try (Resource fileres = newResource(refQuoted))
+        {
+            // This test does not pass on FileResource
+            assumeFalse(fileres instanceof FileResource);
+            
+            assertThat("Exists: " + refQuoted,fileres.exists(),is(true));
+            assertThat("Alias: " + refQuoted,fileres,hasNoAlias());
+        }
+
+        URI refEncoded = dir.toUri().resolve("foo%27s.txt");
+
+        try (Resource fileres = newResource(refEncoded))
+        {
+            assertThat("Exists: " + refEncoded,fileres.exists(),is(true));
+            assertThat("Alias: " + refEncoded,fileres,hasNoAlias());
+        }
+
+        URI refQuoteSpace = dir.toUri().resolve("f%20o's.txt");
+
+        try (Resource fileres = newResource(refQuoteSpace))
+        {
+            assertThat("Exists: " + refQuoteSpace,fileres.exists(),is(true));
+            assertThat("Alias: " + refQuoteSpace,fileres,hasNoAlias());
+        }
+
+        URI refEncodedSpace = dir.toUri().resolve("f%20o%27s.txt");
+
+        try (Resource fileres = newResource(refEncodedSpace))
+        {
+            assertThat("Exists: " + refEncodedSpace,fileres.exists(),is(true));
+            assertThat("Alias: " + refEncodedSpace,fileres,hasNoAlias());
+        }
+
+        URI refA = dir.toUri().resolve("foo's.txt");
+        URI refB = dir.toUri().resolve("foo%27s.txt");
+
+        StringBuilder msg = new StringBuilder();
+        msg.append("URI[a].equals(URI[b])").append(System.lineSeparator());
+        msg.append("URI[a] = ").append(refA).append(System.lineSeparator());
+        msg.append("URI[b] = ").append(refB);
+
+        // show that simple URI.equals() doesn't work
+        assertThat(msg.toString(),refA.equals(refB),is(false));
+
+        // now show that Resource.equals() does work
+        try (Resource a = newResource(refA); Resource b = newResource(refB);)
+        {
+            assertThat("A.equals(B)",a.equals(b),is(true));
+        }
+    }
+
+    @Test
+    public void testExist_BadURINull() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path path = dir.resolve("a.jsp");
+        Files.createFile(path);
+
+        try
+        {
+            // request with null at end
+            URI uri = testdir.getDir().toURI().resolve("a.jsp%00");
+            assertThat("Null URI",uri,notNullValue());
+
+            Resource r = newResource(uri);
+            
+            // if we have r, then it better not exist
+            assertFalse(r.exists());
+        }
+        catch (InvalidPathException e)
+        {
+            // Exception is acceptable
+        }
+    }
+
+    @Test
+    public void testExist_BadURINullX() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+        
+        Path path = dir.resolve("a.jsp");
+        Files.createFile(path);
+
+        try
+        {
+            // request with null and x at end
+            URI uri = testdir.getDir().toURI().resolve("a.jsp%00x");
+            assertThat("NullX URI",uri,notNullValue());
+
+            Resource r = newResource(uri);
+            
+            // if we have r, then it better not exist
+            assertFalse(r.exists());
+        }
+        catch (InvalidPathException e)
+        {
+            // Exception is acceptable
+        }
+    }
+    
+    @Test
+    public void testEncoding() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Files.createDirectories(dir);
+
+        Path specials = dir.resolve("a file with,spe#ials");
+        Files.createFile(specials);
+        
+        try(Resource res = newResource(specials.toFile()))
+        {
+            assertThat("Specials URL", res.getURI().toASCIIString(), containsString("a%20file%20with,spe%23ials"));
+            assertThat("Specials Filename", res.getFile().toString(), containsString("a file with,spe#ials"));
+            
+            res.delete();
+            assertThat("File should have been deleted.",res.exists(),is(false));
+        }
+    }
+    
+    @Test
+    public void testUtf8Dir() throws Exception
+    {
+        Path dir = testdir.getDir().toPath().normalize().toRealPath();
+        Path utf8Dir = dir.resolve("bãm");
+        Files.createDirectories(utf8Dir);
+        
+        Path file = utf8Dir.resolve("file.txt");
+        Files.createFile(file);
+        
+        try (Resource base = newResource(utf8Dir.toFile()))
+        {
+            assertThat("Exists: " + utf8Dir,base.exists(),is(true));
+            assertThat("Alias: " + utf8Dir,base,hasNoAlias());
+
+            Resource r = base.addPath("file.txt");
+            assertThat("Exists: " + r,r.exists(),is(true));
+            assertThat("Alias: " + r,r,hasNoAlias());
+        }
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java
new file mode 100644
index 0000000..3cd2406
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/JarResourceTest.java
@@ -0,0 +1,205 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.resource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.zip.ZipFile;
+
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.IO;
+import org.junit.Test;
+
+public class JarResourceTest
+{
+    private String testResURI = MavenTestingUtils.getTestResourcesDir().getAbsoluteFile().toURI().toASCIIString();
+
+    @Test
+    public void testJarFile()
+    throws Exception
+    {
+        String s = "jar:"+testResURI+"TestData/test.zip!/subdir/";
+        Resource r = Resource.newResource(s);
+
+        Set<String> entries = new HashSet<>(Arrays.asList(r.list()));
+        assertEquals(3,entries.size());
+        assertTrue(entries.contains("alphabet"));
+        assertTrue(entries.contains("numbers"));
+        assertTrue(entries.contains("subsubdir/"));
+
+        File extract = File.createTempFile("extract", null);
+        if (extract.exists())
+            extract.delete();
+        extract.mkdir();
+        extract.deleteOnExit();
+
+        r.copyTo(extract);
+
+        Resource e = Resource.newResource(extract.getAbsolutePath());
+
+        entries = new HashSet<>(Arrays.asList(e.list()));
+        assertEquals(3,entries.size());
+        assertTrue(entries.contains("alphabet"));
+        assertTrue(entries.contains("numbers"));
+        assertTrue(entries.contains("subsubdir/"));
+        IO.delete(extract);
+
+        s = "jar:"+testResURI+"TestData/test.zip!/subdir/subsubdir/";
+        r = Resource.newResource(s);
+
+        entries = new HashSet<>(Arrays.asList(r.list()));
+        assertEquals(2,entries.size());
+        assertTrue(entries.contains("alphabet"));
+        assertTrue(entries.contains("numbers"));
+
+        extract = File.createTempFile("extract", null);
+        if (extract.exists())
+            extract.delete();
+        extract.mkdir();
+        extract.deleteOnExit();
+
+        r.copyTo(extract);
+
+        e = Resource.newResource(extract.getAbsolutePath());
+
+        entries = new HashSet<>(Arrays.asList(e.list()));
+        assertEquals(2,entries.size());
+        assertTrue(entries.contains("alphabet"));
+        assertTrue(entries.contains("numbers"));
+        IO.delete(extract);
+
+    }
+
+    /* ------------------------------------------------------------ */
+    @Test
+    public void testJarFileGetAllResoures()
+    throws Exception
+    {
+        String s = "jar:"+testResURI+"TestData/test.zip!/subdir/";
+        Resource r = Resource.newResource(s);
+        Collection<Resource> deep=r.getAllResources();
+        
+        assertEquals(4, deep.size());
+    }
+    
+    @Test
+    public void testJarFileIsContainedIn ()
+    throws Exception
+    {
+        String s = "jar:"+testResURI+"TestData/test.zip!/subdir/";
+        Resource r = Resource.newResource(s);
+        Resource container = Resource.newResource(testResURI+"TestData/test.zip");
+
+        assertTrue(r instanceof JarFileResource);
+        JarFileResource jarFileResource = (JarFileResource)r;
+
+        assertTrue(jarFileResource.isContainedIn(container));
+
+        container = Resource.newResource(testResURI+"TestData");
+        assertFalse(jarFileResource.isContainedIn(container));
+    }
+
+    /* ------------------------------------------------------------ */
+    @Test
+    public void testJarFileLastModified ()
+    throws Exception
+    {
+        String s = "jar:"+testResURI+"TestData/test.zip!/subdir/numbers";
+
+        try(ZipFile zf = new ZipFile(MavenTestingUtils.getTestResourceFile("TestData/test.zip")))
+        {
+            long last = zf.getEntry("subdir/numbers").getTime();
+
+            Resource r = Resource.newResource(s);
+            assertEquals(last,r.lastModified());
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Test
+    public void testJarFileCopyToDirectoryTraversal () throws Exception
+    {
+        String s = "jar:"+testResURI+"TestData/extract.zip!/";
+        Resource r = Resource.newResource(s);
+
+        assertTrue(r instanceof JarResource);
+        JarResource jarResource = (JarResource)r;
+
+        File destParent = File.createTempFile("copyjar", null);
+        if (destParent.exists())
+            destParent.delete();
+        destParent.mkdir();
+        destParent.deleteOnExit();
+
+        File dest = new File(destParent.getCanonicalPath()+"/extract");
+        if(dest.exists())
+            dest.delete();
+        dest.mkdir();
+        dest.deleteOnExit();
+
+        jarResource.copyTo(dest);
+
+        // dest contains only the valid entry; dest.getParent() contains only the dest directory
+        assertEquals(1, dest.listFiles().length);
+        assertEquals(1, dest.getParentFile().listFiles().length);
+
+        FilenameFilter dotdotFilenameFilter = new FilenameFilter() {
+            @Override
+            public boolean accept(File directory, String name)
+            {
+                return name.equals("dotdot.txt");
+            }
+        };
+        assertEquals(0, dest.listFiles(dotdotFilenameFilter).length);
+        assertEquals(0, dest.getParentFile().listFiles(dotdotFilenameFilter).length);
+
+        FilenameFilter extractfileFilenameFilter = new FilenameFilter() {
+            @Override
+            public boolean accept(File directory, String name)
+            {
+                return name.equals("extract-filenotdir");
+            }
+        };
+        assertEquals(0, dest.listFiles(extractfileFilenameFilter).length);
+        assertEquals(0, dest.getParentFile().listFiles(extractfileFilenameFilter).length);
+
+        FilenameFilter currentDirectoryFilenameFilter = new FilenameFilter() {
+            @Override
+            public boolean accept(File directory, String name)
+            {
+                return name.equals("current.txt");
+            }
+        };
+        assertEquals(1, dest.listFiles(currentDirectoryFilenameFilter).length);
+        assertEquals(0, dest.getParentFile().listFiles(currentDirectoryFilenameFilter).length);
+
+        IO.delete(dest);
+        assertFalse(dest.exists());
+    }
+
+
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java
deleted file mode 100644
index 38eb27e..0000000
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/PathResourceTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.util.resource;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-
-public class PathResourceTest extends AbstractFSResourceTest
-{
-    @Override
-    public Resource newResource(URI uri) throws IOException
-    {
-        return new PathResource(uri);
-    }
-
-    @Override
-    public Resource newResource(File file) throws IOException
-    {
-        return new PathResource(file);
-    }
-}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java
index 95ee5b2..667c5af 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java
@@ -18,39 +18,34 @@
 
 package org.eclipse.jetty.util.resource;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
 
 import java.io.File;
-import java.io.FilePermission;
-import java.io.FilenameFilter;
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URL;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.zip.ZipFile;
 
+import org.eclipse.jetty.toolchain.test.FS;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.toolchain.test.OS;
 import org.eclipse.jetty.util.IO;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
-import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
-
+@RunWith(Parameterized.class)
 public class ResourceTest
 {
-    public static String __userDir = System.getProperty("basedir", ".");
-    public static URL __userURL=null;
-    private static String __relDir="";
-    private static File tmpFile;
-
     private static final boolean DIR=true;
     private static final boolean EXISTS=true;
 
@@ -98,6 +93,24 @@
             this.dir=dir;
             resource=Resource.newResource(url);
         }
+        
+        Data(URI uri,boolean exists, boolean dir)
+                throws Exception
+        {
+            this.test=uri.toASCIIString();
+            this.exists=exists;
+            this.dir=dir;
+            resource=Resource.newResource(uri);
+        }
+        
+        Data(File file,boolean exists, boolean dir)
+                throws Exception
+        {
+            this.test=file.toString();
+            this.exists=exists;
+            this.dir=dir;
+            resource=Resource.newResource(file);
+        }
 
         Data(String url,boolean exists, boolean dir, String content)
             throws Exception
@@ -108,423 +121,169 @@
             this.content=content;
             resource=Resource.newResource(url);
         }
+        
+        @Override
+        public String toString()
+        {
+            return this.test;
+        }
     }
-
-    public static Data[] data;
-
-    /* ------------------------------------------------------------ */
-    @BeforeClass
-    public static void setUp()
-    throws Exception
+    
+    static class UseCases
     {
-        if (data!=null)
-            return;
-
-        File file = new File(__userDir);
-        file=new File(file.getCanonicalPath());
-        URI uri = file.toURI();
-        __userURL=uri.toURL();
+        final Collection<Data[]> data;
+        final File fileRef;
+        final URI uriRef;
+        final String relRef;
         
-        __userURL = MavenTestingUtils.getTestResourcesDir().toURI().toURL();
-        FilePermission perm = (FilePermission) __userURL.openConnection().getPermission();
-        __userDir = new File(perm.getName()).getCanonicalPath() + File.separatorChar;
-        __relDir = "src/test/resources/".replace('/', File.separatorChar);  
+        final Data[] baseCases;
         
-        //System.err.println("User Dir="+__userDir);
-        //System.err.println("Rel  Dir="+__relDir);
-        //System.err.println("User URL="+__userURL);
-
-        tmpFile=File.createTempFile("test",null).getCanonicalFile();
-        tmpFile.deleteOnExit();
-
-        data = new Data[50];
-        int i=0;
-
-        data[i++]=new Data(tmpFile.toString(),EXISTS,!DIR);
-
-        int rt=i;
-        data[i++]=new Data(__userURL,EXISTS,DIR);
-        data[i++]=new Data(__userDir,EXISTS,DIR);
-        data[i++]=new Data(__relDir,EXISTS,DIR);
-        data[i++]=new Data(__userURL+"resource.txt",EXISTS,!DIR);
-        data[i++]=new Data(__userDir+"resource.txt",EXISTS,!DIR);
-        data[i++]=new Data(__relDir+"resource.txt",EXISTS,!DIR);
-        data[i++]=new Data(__userURL+"NoName.txt",!EXISTS,!DIR);
-        data[i++]=new Data(__userDir+"NoName.txt",!EXISTS,!DIR);
-        data[i++]=new Data(__relDir+"NoName.txt",!EXISTS,!DIR);
-
-        data[i++]=new Data(data[rt],"resource.txt",EXISTS,!DIR);
-        data[i++]=new Data(data[rt],"/resource.txt",EXISTS,!DIR);
-        data[i++]=new Data(data[rt],"NoName.txt",!EXISTS,!DIR);
-        data[i++]=new Data(data[rt],"/NoName.txt",!EXISTS,!DIR);
-
-        int td=i;
-        data[i++]=new Data(data[rt],"TestData",EXISTS,DIR);
-        data[i++]=new Data(data[rt],"TestData/",EXISTS,DIR);
-        data[i++]=new Data(data[td],"alphabet.txt",EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-
-        data[i++]=new Data("jar:file:/somejar.jar!/content/",!EXISTS,DIR);
-        data[i++]=new Data("jar:file:/somejar.jar!/",!EXISTS,DIR);
-
-        int tj=i;
-        data[i++]=new Data("jar:"+__userURL+"TestData/test.zip!/",EXISTS,DIR);
-        data[i++]=new Data(data[tj],"Unkown",!EXISTS,!DIR);
-        data[i++]=new Data(data[tj],"/Unkown/",!EXISTS,DIR);
-
-        data[i++]=new Data(data[tj],"subdir",EXISTS,DIR);
-        data[i++]=new Data(data[tj],"/subdir/",EXISTS,DIR);
-        data[i++]=new Data(data[tj],"alphabet",EXISTS,!DIR,
-                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-        data[i++]=new Data(data[tj],"/subdir/alphabet",EXISTS,!DIR,
-                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-
-        Resource base = Resource.newResource(__userDir);
-        Resource dir0 = base.addPath("TestData");
-        assertTrue(dir0.isDirectory());
-        assertTrue(dir0.toString().endsWith("/"));
-        assertTrue(dir0.getAlias()==null);
-        Resource dir1 = base.addPath("TestData/");
-        assertTrue(dir1.isDirectory());
-        assertTrue(dir1.toString().endsWith("/"));
-        assertTrue(dir1.getAlias()==null);
-
-
+        public UseCases(String ref) throws Exception {
+            this.data = new ArrayList<Data[]>();
+            // relative directory reference
+            this.relRef = OS.separators(ref);
+            // File object reference
+            this.fileRef = MavenTestingUtils.getProjectDir(relRef);
+            // URI reference
+            this.uriRef = fileRef.toURI();
+            
+            // create baseline cases
+            baseCases = new Data[] { 
+                new Data(relRef,EXISTS,DIR), 
+                new Data(uriRef,EXISTS,DIR), 
+                new Data(fileRef,EXISTS,DIR) 
+            };
+            
+            // add all baseline cases
+            for (Data bcase : baseCases)
+            {
+                addCase(bcase);
+            }
+        }
+        
+        public void addCase(Data ucase)
+        {
+            this.data.add(new Data[]{ ucase });
+        }
+        
+        public void addAllSimpleCases(String subpath, boolean exists, boolean dir) 
+            throws Exception
+        {
+            addCase(new Data(OS.separators(relRef + subpath), exists, dir));
+            addCase(new Data(uriRef.resolve(subpath).toURL(), exists, dir));
+            addCase(new Data(new File(fileRef,subpath),exists, dir));
+        }
+        
+        public Data addAllAddPathCases(String subpath, boolean exists, boolean dir) throws Exception
+        {
+            Data bdata = null;
+            
+            for (Data bcase : baseCases)
+            {
+                bdata = new Data(bcase, subpath, exists, dir);
+                addCase(bdata);
+            }
+            
+            return bdata;
+        }
     }
+    
 
-    /* ------------------------------------------------------------ */
+    @Parameters(name="{0}")
+    public static Collection<Data[]> data() throws Exception
+    {
+        UseCases cases = new UseCases("src/test/resources/");
+        
+        File testDir = MavenTestingUtils.getTargetTestingDir(ResourceTest.class.getName());
+        FS.ensureEmpty(testDir);
+        File tmpFile = File.createTempFile("test",null,testDir);
+        
+        cases.addCase(new Data(tmpFile.toString(),EXISTS,!DIR));
+        
+        // Some resource references.
+        cases.addAllSimpleCases("resource.txt",EXISTS,!DIR);
+        cases.addAllSimpleCases("NoName.txt",!EXISTS,!DIR);
+        
+        // Some addPath() forms
+        cases.addAllAddPathCases("resource.txt",EXISTS,!DIR);
+        cases.addAllAddPathCases("/resource.txt",EXISTS,!DIR);
+        cases.addAllAddPathCases("//resource.txt",EXISTS,!DIR);
+        cases.addAllAddPathCases("NoName.txt",!EXISTS,!DIR);
+        cases.addAllAddPathCases("/NoName.txt",!EXISTS,!DIR);
+        cases.addAllAddPathCases("//NoName.txt",!EXISTS,!DIR);
+
+        Data tdata1 = cases.addAllAddPathCases("TestData", EXISTS, DIR);
+        Data tdata2 = cases.addAllAddPathCases("TestData/", EXISTS, DIR);
+        
+        cases.addCase(new Data(tdata1, "alphabet.txt", EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+        cases.addCase(new Data(tdata2, "alphabet.txt", EXISTS,!DIR,"ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+
+        cases.addCase(new Data("jar:file:/somejar.jar!/content/",!EXISTS,DIR));
+        cases.addCase(new Data("jar:file:/somejar.jar!/",!EXISTS,DIR));
+
+        String urlRef = cases.uriRef.toASCIIString();
+        Data zdata = new Data("jar:"+urlRef +"TestData/test.zip!/",EXISTS,DIR);
+        cases.addCase(zdata);
+        cases.addCase(new Data(zdata,"Unkown",!EXISTS,!DIR));
+        cases.addCase(new Data(zdata,"/Unkown/",!EXISTS,DIR));
+
+        cases.addCase(new Data(zdata,"subdir",EXISTS,DIR));
+        cases.addCase(new Data(zdata,"/subdir/",EXISTS,DIR));
+        cases.addCase(new Data(zdata,"alphabet",EXISTS,!DIR,
+                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+        cases.addCase(new Data(zdata,"/subdir/alphabet",EXISTS,!DIR,
+                           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+        
+        cases.addAllAddPathCases("/TestData/test/subdir/subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("//TestData/test/subdir/subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("/TestData//test/subdir/subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("/TestData/test//subdir/subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("/TestData/test/subdir//subsubdir/",EXISTS,DIR);
+        
+        cases.addAllAddPathCases("TestData/test/subdir/subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("TestData/test/subdir/subsubdir//",EXISTS,DIR);
+        cases.addAllAddPathCases("TestData/test/subdir//subsubdir/",EXISTS,DIR);
+        cases.addAllAddPathCases("TestData/test//subdir/subsubdir/",EXISTS,DIR);
+
+        cases.addAllAddPathCases("/TestData/../TestData/test/subdir/subsubdir/",EXISTS,DIR);
+
+        return cases.data;
+    }
+    
+    @Parameter(value=0)
+    public Data data;
+
     @Test
     public void testResourceExists()
     {
-        for (int i=0;i<data.length;i++)
-        {
-            if (data[i]==null)
-                continue;
-
-            assertEquals(""+i+":"+data[i].test,data[i].exists,data[i].resource.exists());
-        }
+        assertThat("Exists: " + data.resource.getName(), data.resource.exists(), equalTo(data.exists));
     }
 
-    /* ------------------------------------------------------------ */
     @Test
     public void testResourceDir()
     {
-        for (int i=0;i<data.length;i++)
-        {
-            if (data[i]==null)
-                continue;
-
-            assertEquals(""+i+":"+data[i].test,data[i].dir,data[i].resource.isDirectory());
-        }
+        assertThat("Is Directory: " + data.test, data.resource.isDirectory(),equalTo(data.dir));
     }
 
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testResourceContent()
-        throws Exception
-    {
-        for (int i=0;i<data.length;i++)
-        {
-            if (data[i]==null || data[i].content==null)
-                continue;
-
-            InputStream in = data[i].resource.getInputStream();
-            String c=IO.toString(in);
-            assertTrue(""+i+":"+data[i].test,c.startsWith(data[i].content));
-        }
-    }
-
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testEncoding() throws Exception
-    {
-        Resource r =Resource.newResource("/tmp/a file with,spe#ials/");
-        assertTrue(r.getURL().toString().indexOf("a%20file%20with,spe%23ials")>0);
-        assertTrue(r.getFile().toString().indexOf("a file with,spe#ials")>0);
-        r.delete();
-        assertFalse("File should have been deleted.",r.exists());
-    }
-
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testJarFile()
-    throws Exception
-    {
-        String s = "jar:"+__userURL+"TestData/test.zip!/subdir/";
-        Resource r = Resource.newResource(s);
-
-        Set<String> entries = new HashSet<>(Arrays.asList(r.list()));
-        assertEquals(3,entries.size());
-        assertTrue(entries.contains("alphabet"));
-        assertTrue(entries.contains("numbers"));
-        assertTrue(entries.contains("subsubdir/"));
-
-        File extract = File.createTempFile("extract", null);
-        if (extract.exists())
-            extract.delete();
-        extract.mkdir();
-        extract.deleteOnExit();
-
-        r.copyTo(extract);
-
-        Resource e = Resource.newResource(extract.getAbsolutePath());
-
-        entries = new HashSet<>(Arrays.asList(e.list()));
-        assertEquals(3,entries.size());
-        assertTrue(entries.contains("alphabet"));
-        assertTrue(entries.contains("numbers"));
-        assertTrue(entries.contains("subsubdir/"));
-        IO.delete(extract);
-
-        s = "jar:"+__userURL+"TestData/test.zip!/subdir/subsubdir/";
-        r = Resource.newResource(s);
-
-        entries = new HashSet<>(Arrays.asList(r.list()));
-        assertEquals(2,entries.size());
-        assertTrue(entries.contains("alphabet"));
-        assertTrue(entries.contains("numbers"));
-
-        extract = File.createTempFile("extract", null);
-        if (extract.exists())
-            extract.delete();
-        extract.mkdir();
-        extract.deleteOnExit();
-
-        r.copyTo(extract);
-
-        e = Resource.newResource(extract.getAbsolutePath());
-
-        entries = new HashSet<>(Arrays.asList(e.list()));
-        assertEquals(2,entries.size());
-        assertTrue(entries.contains("alphabet"));
-        assertTrue(entries.contains("numbers"));
-        IO.delete(extract);
-
-    }
-
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testJarFileGetAllResoures()
-    throws Exception
-    {
-        String s = "jar:"+__userURL+"TestData/test.zip!/subdir/";
-        Resource r = Resource.newResource(s);
-        Collection<Resource> deep=r.getAllResources();
-        
-        assertEquals(4, deep.size());
-    }
-    
-    @Test
-    public void testJarFileIsContainedIn ()
-    throws Exception
-    {
-        String s = "jar:"+__userURL+"TestData/test.zip!/subdir/";
-        Resource r = Resource.newResource(s);
-        Resource container = Resource.newResource(__userURL+"TestData/test.zip");
-
-        assertTrue(r instanceof JarFileResource);
-        JarFileResource jarFileResource = (JarFileResource)r;
-
-        assertTrue(jarFileResource.isContainedIn(container));
-
-        container = Resource.newResource(__userURL+"TestData");
-        assertFalse(jarFileResource.isContainedIn(container));
-    }
-
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testJarFileLastModified ()
-    throws Exception
-    {
-        String s = "jar:"+__userURL+"TestData/test.zip!/subdir/numbers";
-
-        try(ZipFile zf = new ZipFile(MavenTestingUtils.getTestResourceFile("TestData/test.zip")))
-        {
-            long last = zf.getEntry("subdir/numbers").getTime();
-
-            Resource r = Resource.newResource(s);
-            assertEquals(last,r.lastModified());
-        }
-    }
-
-    /* ------------------------------------------------------------ */
     @Test
     public void testEncodeAddPath ()
     throws Exception
     {
-        Resource r;
-
-        r = Resource.newResource(__userURL+"TestData/").addPath("foo%/b r");
-        Assert.assertThat(r.getURI().toString(),Matchers.endsWith("/foo%25/b%20r"));
-        
-        r = Resource.newResource("jar:"+__userURL+"TestData/test.zip!/subdir/").addPath("foo%/b r");
-        Assert.assertThat(r.getURI().toString(),Matchers.endsWith("/foo%25/b%20r"));
-    }
-    
-    
-    /* ------------------------------------------------------------ */
-    @Test
-    public void testJarFileCopyToDirectoryTraversal () throws Exception
-    {
-        String s = "jar:"+__userURL+"TestData/extract.zip!/";
-        Resource r = Resource.newResource(s);
-
-        assertTrue(r instanceof JarResource);
-        JarResource jarResource = (JarResource)r;
-
-        File destParent = File.createTempFile("copyjar", null);
-        if (destParent.exists())
-            destParent.delete();
-        destParent.mkdir();
-        destParent.deleteOnExit();
-
-        File dest = new File(destParent.getCanonicalPath()+"/extract");
-        if(dest.exists())
-            dest.delete();
-        dest.mkdir();
-        dest.deleteOnExit();
-
-        jarResource.copyTo(dest);
-
-        // dest contains only the valid entry; dest.getParent() contains only the dest directory
-        assertEquals(1, dest.listFiles().length);
-        assertEquals(1, dest.getParentFile().listFiles().length);
-
-        FilenameFilter dotdotFilenameFilter = new FilenameFilter() {
-            @Override
-            public boolean accept(File directory, String name)
-            {
-                return name.equals("dotdot.txt");
-            }
-        };
-        assertEquals(0, dest.listFiles(dotdotFilenameFilter).length);
-        assertEquals(0, dest.getParentFile().listFiles(dotdotFilenameFilter).length);
-
-        FilenameFilter extractfileFilenameFilter = new FilenameFilter() {
-            @Override
-            public boolean accept(File directory, String name)
-            {
-                return name.equals("extract-filenotdir");
-            }
-        };
-        assertEquals(0, dest.listFiles(extractfileFilenameFilter).length);
-        assertEquals(0, dest.getParentFile().listFiles(extractfileFilenameFilter).length);
-
-        FilenameFilter currentDirectoryFilenameFilter = new FilenameFilter() {
-            @Override
-            public boolean accept(File directory, String name)
-            {
-                return name.equals("current.txt");
-            }
-        };
-        assertEquals(1, dest.listFiles(currentDirectoryFilenameFilter).length);
-        assertEquals(0, dest.getParentFile().listFiles(currentDirectoryFilenameFilter).length);
-
-        IO.delete(dest);
-        assertFalse(dest.exists());
-    }
-
-    /**
-     * Test a class path resource for existence.
-     */
-    @Test
-    public void testClassPathResourceClassRelative()
-    {
-        final String classPathName="Resource.class";
-
-        try(Resource resource=Resource.newClassPathResource(classPathName);)
+        if (data.dir)
         {
-            // A class path cannot be a directory
-            assertFalse("Class path cannot be a directory.",resource.isDirectory());
-
-            // A class path must exist
-            assertTrue("Class path resource does not exist.",resource.exists());
+            Resource r = data.resource.addPath("foo%/b r");
+            Assert.assertThat(r.getURI().toString(),Matchers.endsWith("/foo%25/b%20r"));
         }
     }
-
-    /**
-     * Test a class path resource for existence.
-     */
+    
     @Test
-    public void testClassPathResourceClassAbsolute()
+    public void testResourceContent()
+        throws Exception
     {
-        final String classPathName="/org/eclipse/jetty/util/resource/Resource.class";
-
-        Resource resource=Resource.newClassPathResource(classPathName);
-
-        // A class path cannot be a directory
-        assertFalse("Class path cannot be a directory.",resource.isDirectory());
-
-        // A class path must exist
-        assertTrue("Class path resource does not exist.",resource.exists());
-    }
-
-    /**
-     * Test a class path resource for directories.
-     */
-    @Test
-    public void testClassPathResourceDirectory() throws Exception
-    {
-        final String classPathName="/";
-
-        Resource resource=Resource.newClassPathResource(classPathName);
-
-        // A class path must be a directory
-        assertTrue("Class path must be a directory.",resource.isDirectory());
-
-        assertTrue("Class path returned file must be a directory.",resource.getFile().isDirectory());
-
-        // A class path must exist
-        assertTrue("Class path resource does not exist.",resource.exists());
-    }
-
-    /**
-     * Test a class path resource for a file.
-     */
-    @Test
-    public void testClassPathResourceFile() throws Exception
-    {
-        final String fileName="resource.txt";
-        final String classPathName="/"+fileName;
-
-        // Will locate a resource in the class path
-        Resource resource=Resource.newClassPathResource(classPathName);
-
-        // A class path cannot be a directory
-        assertFalse("Class path must be a directory.",resource.isDirectory());
-
-        assertTrue(resource!=null);
-
-        File file=resource.getFile();
-
-        assertEquals("File name from class path is not equal.",fileName,file.getName());
-        assertTrue("File returned from class path should be a file.",file.isFile());
-
-        // A class path must exist
-        assertTrue("Class path resource does not exist.",resource.exists());
-    }
-
-    @Test
-    public void testUncPathResourceFile() throws Exception
-    {
-        // This test is intended to run only on Windows platform
-        assumeTrue(OS.IS_WINDOWS);
-
-        String path = __userURL.toURI().getPath().replace('/','\\')+"resource.txt";
-        //System.err.println(path);
-
-        Resource resource = Resource.newResource(path, false);
-        //System.err.println(resource);
-        assertTrue(resource.exists());
-
-        /*
-
-        String uncPath = "\\\\127.0.0.1"+__userURL.toURI().getPath().replace('/','\\').replace(':','$')+"ResourceTest.java";
-        System.err.println(uncPath);
-
-        Resource uncResource = Resource.newResource(uncPath, false);
-        System.err.println(uncResource);
-        assertTrue(uncResource.exists());
-
-        */
+        assumeThat(data.content, notNullValue());
+        
+        InputStream in = data.resource.getInputStream();
+        String c = IO.toString(in);
+        assertThat("Content: " + data.test,c,startsWith(data.content));
     }
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ssl/SslContextFactoryTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ssl/SslContextFactoryTest.java
index e407047..0ca6644 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/ssl/SslContextFactoryTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/ssl/SslContextFactoryTest.java
@@ -18,9 +18,10 @@
 
 package org.eclipse.jetty.util.ssl;
 
-import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -37,6 +38,7 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.StdErrLog;
 import org.eclipse.jetty.util.resource.Resource;
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Before;
@@ -57,7 +59,6 @@
     @Test
     public void testNoTsFileKs() throws Exception
     {
-        String keystorePath = System.getProperty("basedir",".") + "/src/test/resources/keystore";
         cf.setKeyStorePassword("storepwd");
         cf.setKeyManagerPassword("keypwd");
 
@@ -104,6 +105,8 @@
         cf.setKeyStoreResource(keystoreResource);
         cf.setKeyStorePassword("storepwd");
         cf.setKeyManagerPassword("keypwd");
+        cf.setTrustStoreResource(keystoreResource);
+        cf.setTrustStorePassword(null);
 
         cf.start();
 
@@ -130,7 +133,6 @@
     @Test
     public void testResourceTsResourceKsWrongPW() throws Exception
     {
-        SslContextFactory.LOG.info("EXPECT SslContextFactory@????????(null,null): java.security.UnrecoverableKeyException: Cannot recover key...");
         Resource keystoreResource = Resource.newSystemResource("keystore");
         Resource truststoreResource = Resource.newSystemResource("keystore");
 
@@ -148,13 +150,13 @@
         }
         catch(java.security.UnrecoverableKeyException e)
         {
+            Assert.assertThat(e.toString(),Matchers.containsString("UnrecoverableKeyException"));
         }
     }
 
     @Test
     public void testResourceTsWrongPWResourceKs() throws Exception
     {
-        SslContextFactory.LOG.info("EXPECT SslContextFactory@????????(null,null): java.io.IOException: Keystore was tampered with ...");
         Resource keystoreResource = Resource.newSystemResource("keystore");
         Resource truststoreResource = Resource.newSystemResource("keystore");
 
@@ -172,6 +174,7 @@
         }
         catch(IOException e)
         {
+            Assert.assertThat(e.toString(),Matchers.containsString("java.io.IOException: Keystore was tampered with, or password was incorrect"));
         }
     }
 
@@ -180,7 +183,6 @@
     {
         try
         {
-            SslContextFactory.LOG.info("EXPECT SslContextFactory@????????(null,/foo): java.lang.IllegalStateException: SSL doesn't have a valid keystore...");
             ((StdErrLog)Log.getLogger(AbstractLifeCycle.class)).setHideStacks(true);
             cf.setTrustStorePath("/foo");
             cf.start();
@@ -188,11 +190,7 @@
         }
         catch (IllegalStateException e)
         {
-
-        }
-        catch (Exception e)
-        {
-            Assert.fail("Unexpected exception");
+            Assert.assertThat(e.toString(),Matchers.containsString("IllegalStateException: no valid keystore"));
         }
     }
 
@@ -205,46 +203,21 @@
         String[] enabledCipherSuites = sslEngine.getEnabledCipherSuites();
         assertThat("At least 1 cipherSuite is enabled", enabledCipherSuites.length, greaterThan(0));
         for (String enabledCipherSuite : enabledCipherSuites)
-            assertThat("CipherSuite does not contain RC4", enabledCipherSuite.contains("RC4"), is(false));
+            assertThat("CipherSuite does not contain RC4", enabledCipherSuite.contains("RC4"), equalTo(false));
     }
 
     @Test
     public void testSetIncludeCipherSuitesRegex() throws Exception
     {
-        // Test does not work on JDK 8+ (RC4 is disabled)
+        cf.setIncludeCipherSuites(".*ECDHE.*",".*WIBBLE.*");
         Assume.assumeFalse(JDK.IS_8);
         
-        cf.setIncludeCipherSuites(".*RC4.*");
         cf.start();
         SSLEngine sslEngine = cf.newSSLEngine();
         String[] enabledCipherSuites = sslEngine.getEnabledCipherSuites();
-        assertThat("At least 1 cipherSuite is enabled", enabledCipherSuites.length, greaterThan(0));
+        assertThat("At least 1 cipherSuite is enabled", enabledCipherSuites.length, greaterThan(1));
         for (String enabledCipherSuite : enabledCipherSuites)
-            assertThat("CipherSuite contains RC4", enabledCipherSuite.contains("RC4"), is(true));
-    }
-
-    @Test
-    public void testSetIncludeCipherSuitesPreservesOrder()
-    {
-        String[] supportedCipherSuites = new String[]{"cipher4", "cipher2", "cipher1", "cipher3"};
-        String[] includeCipherSuites = {"cipher1", "cipher3", "cipher4"};
-
-        cf.setIncludeCipherSuites(includeCipherSuites);
-        String[] selectedCipherSuites = cf.selectCipherSuites(null, supportedCipherSuites);
-
-        assertSelectedMatchesIncluded(includeCipherSuites, selectedCipherSuites);
-    }
-
-    @Test
-    public void testSetIncludeProtocolsPreservesOrder()
-    {
-        String[] supportedProtocol = new String[]{"cipher4", "cipher2", "cipher1", "cipher3"};
-        String[] includeProtocol = {"cipher1", "cipher3", "cipher4"};
-
-        cf.setIncludeProtocols(includeProtocol);
-        String[] selectedProtocol = cf.selectProtocols(null, supportedProtocol);
-
-        assertSelectedMatchesIncluded(includeProtocol, selectedProtocol);
+            assertThat("CipherSuite contains ECDHE", enabledCipherSuite.contains("ECDHE"), equalTo(true));
     }
 
     @Test
@@ -256,11 +229,44 @@
     	assertNotNull(cf.getIncludeCipherSuites());
     }
     
-    private void assertSelectedMatchesIncluded(String[] includeStrings, String[] selectedStrings)
+    @Test
+    public void testSNICertificates() throws Exception
     {
-        assertThat(includeStrings.length + " strings are selected", selectedStrings.length, is(includeStrings.length));
-        assertThat("order from includeStrings is preserved", selectedStrings[0], equalTo(includeStrings[0]));
-        assertThat("order from includeStrings is preserved", selectedStrings[1], equalTo(includeStrings[1]));
-        assertThat("order from includeStrings is preserved", selectedStrings[2], equalTo(includeStrings[2]));
+        Resource keystoreResource = Resource.newSystemResource("snikeystore");
+
+        cf.setKeyStoreResource(keystoreResource);
+        cf.setKeyStorePassword("storepwd");
+        cf.setKeyManagerPassword("keypwd");
+        
+        cf.start();
+        
+        assertThat(cf.getAliases(),containsInAnyOrder("jetty","other","san","wild"));
+        
+        assertThat(cf.getX509("jetty").getHosts(),containsInAnyOrder("jetty.eclipse.org"));
+        assertTrue(cf.getX509("jetty").getWilds().isEmpty());
+        assertTrue(cf.getX509("jetty").matches("JETTY.Eclipse.Org"));
+        assertFalse(cf.getX509("jetty").matches("m.jetty.eclipse.org"));
+        assertFalse(cf.getX509("jetty").matches("eclipse.org"));
+        
+        assertThat(cf.getX509("other").getHosts(),containsInAnyOrder("www.example.com"));
+        assertTrue(cf.getX509("other").getWilds().isEmpty());
+        assertTrue(cf.getX509("other").matches("www.example.com"));
+        assertFalse(cf.getX509("other").matches("eclipse.org"));
+        
+        assertThat(cf.getX509("san").getHosts(),containsInAnyOrder("www.san.com","m.san.com"));
+        assertTrue(cf.getX509("san").getWilds().isEmpty());
+        assertTrue(cf.getX509("san").matches("www.san.com"));
+        assertTrue(cf.getX509("san").matches("m.san.com"));
+        assertFalse(cf.getX509("san").matches("other.san.com"));
+        assertFalse(cf.getX509("san").matches("san.com"));
+        assertFalse(cf.getX509("san").matches("eclipse.org"));
+        
+        assertTrue(cf.getX509("wild").getHosts().isEmpty());
+        assertThat(cf.getX509("wild").getWilds(),containsInAnyOrder("domain.com"));
+        assertTrue(cf.getX509("wild").matches("domain.com"));
+        assertTrue(cf.getX509("wild").matches("www.domain.com"));
+        assertTrue(cf.getX509("wild").matches("other.domain.com"));
+        assertFalse(cf.getX509("wild").matches("foo.bar.domain.com"));
+        assertFalse(cf.getX509("wild").matches("other.com"));
     }
 }
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/CounterStatisticTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/CounterStatisticTest.java
new file mode 100644
index 0000000..33b6d08
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/statistic/CounterStatisticTest.java
@@ -0,0 +1,80 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.statistic;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.lessThan;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/* ------------------------------------------------------------ */
+public class CounterStatisticTest
+{
+
+    @Test
+    public void testCounter()
+        throws Exception
+    {
+        CounterStatistic count = new CounterStatistic();
+        
+        assertThat(count.getCurrent(),equalTo(0L));
+        assertThat(count.getMax(),equalTo(0L));
+        assertThat(count.getTotal(),equalTo(0L));
+        
+        count.increment();
+        count.increment();
+        count.decrement();
+        count.add(4);
+        count.add(-2);
+
+        assertThat(count.getCurrent(),equalTo(3L));
+        assertThat(count.getMax(),equalTo(5L));
+        assertThat(count.getTotal(),equalTo(6L));
+        
+        count.reset();
+        assertThat(count.getCurrent(),equalTo(3L));
+        assertThat(count.getMax(),equalTo(3L));
+        assertThat(count.getTotal(),equalTo(3L));
+
+        count.increment();
+        count.decrement();
+        count.add(-2);
+        count.decrement();
+        assertThat(count.getCurrent(),equalTo(0L));
+        assertThat(count.getMax(),equalTo(4L));
+        assertThat(count.getTotal(),equalTo(4L));
+     
+        count.decrement();
+        assertThat(count.getCurrent(),equalTo(-1L));
+        assertThat(count.getMax(),equalTo(4L));
+        assertThat(count.getTotal(),equalTo(4L));
+
+        count.increment();
+        assertThat(count.getCurrent(),equalTo(0L));
+        assertThat(count.getMax(),equalTo(4L));
+        assertThat(count.getTotal(),equalTo(5L));
+    }
+
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/LockerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/LockerTest.java
new file mode 100644
index 0000000..be57142
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/LockerTest.java
@@ -0,0 +1,155 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@RunWith(Parameterized.class)
+public class LockerTest
+{
+    @Parameterized.Parameters
+    public static Collection<Object[]> parameters()
+    {
+        return Arrays.asList(new Object[]{true}, new Object[]{false});
+    }
+
+    private boolean spin;
+
+    public LockerTest(boolean spin)
+    {
+        this.spin = spin;
+    }
+
+    @Test
+    public void testLocked()
+    {
+        Locker lock = new Locker(spin);
+        assertFalse(lock.isLocked());
+
+        try(Locker.Lock l = lock.lock())
+        {
+            assertTrue(lock.isLocked());
+        }
+        finally
+        {
+            assertFalse(lock.isLocked());
+        }
+
+        assertFalse(lock.isLocked());
+    }
+
+    @Test
+    public void testLockedException()
+    {
+        Locker lock = new Locker(spin);
+        assertFalse(lock.isLocked());
+
+        try(Locker.Lock l = lock.lock())
+        {
+            assertTrue(lock.isLocked());
+            throw new Exception();
+        }
+        catch(Exception e)
+        {
+            assertFalse(lock.isLocked());
+        }
+        finally
+        {
+            assertFalse(lock.isLocked());
+        }
+
+        assertFalse(lock.isLocked());
+    }
+
+    @Test
+    public void testContend() throws Exception
+    {
+        final Locker lock = new Locker(spin);
+
+        final CountDownLatch held0 = new CountDownLatch(1);
+        final CountDownLatch hold0 = new CountDownLatch(1);
+
+        Thread thread0 = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                try(Locker.Lock l = lock.lock())
+                {
+                    held0.countDown();
+                    hold0.await();
+                }
+                catch (InterruptedException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        };
+        thread0.start();
+        held0.await();
+
+        assertTrue(lock.isLocked());
+
+
+        final CountDownLatch held1 = new CountDownLatch(1);
+        final CountDownLatch hold1 = new CountDownLatch(1);
+        Thread thread1 = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                try(Locker.Lock l = lock.lock())
+                {
+                    held1.countDown();
+                    hold1.await();
+                }
+                catch (InterruptedException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        };
+        thread1.start();
+        // thread1 will be spinning here
+        assertFalse(held1.await(100, TimeUnit.MILLISECONDS));
+
+        // Let thread0 complete
+        hold0.countDown();
+        thread0.join();
+
+        // thread1 can progress
+        held1.await();
+
+        // let thread1 complete
+        hold1.countDown();
+        thread1.join();
+
+        assertFalse(lock.isLocked());
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java
index ecff241..71f76ad 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java
@@ -18,6 +18,11 @@
 
 package org.eclipse.jetty.util.thread;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -30,11 +35,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
 @RunWith(AdvancedRunner.class)
 public class QueuedThreadPoolTest
 {
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/SchedulerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/SchedulerTest.java
index dc00b2c..8c88205 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/SchedulerTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/SchedulerTest.java
@@ -177,7 +177,7 @@
             @Override
             public void run()
             {
-                throw new RuntimeException();
+                throw new RuntimeException("Thrown by testTaskThrowsException");
             }
         }, delay, TimeUnit.MILLISECONDS);
 
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScopeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScopeTest.java
new file mode 100644
index 0000000..27fb89c
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/ThreadClassLoaderScopeTest.java
@@ -0,0 +1,79 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.junit.Test;
+
+public class ThreadClassLoaderScopeTest
+{
+    private static class ClassLoaderFoo extends URLClassLoader
+    {
+        public ClassLoaderFoo()
+        {
+            super(new URL[0]);
+        }
+    }
+
+    private static class ClassLoaderBar extends URLClassLoader
+    {
+        public ClassLoaderBar()
+        {
+            super(new URL[0]);
+        }
+    }
+    
+    @Test
+    public void testNormal()
+    {
+        try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(new ClassLoaderFoo()))
+        {
+            assertThat("ClassLoader in scope",Thread.currentThread().getContextClassLoader(),instanceOf(ClassLoaderFoo.class));
+            assertThat("Scoped ClassLoader",scope.getScopedClassLoader(),instanceOf(ClassLoaderFoo.class));
+        }
+        assertThat("ClassLoader after scope",Thread.currentThread().getContextClassLoader(),not(instanceOf(ClassLoaderFoo.class)));
+    }
+
+    @Test
+    public void testWithException()
+    {
+        try (ThreadClassLoaderScope scope = new ThreadClassLoaderScope(new ClassLoaderBar()))
+        {
+            assertThat("ClassLoader in 'scope'",Thread.currentThread().getContextClassLoader(),instanceOf(ClassLoaderBar.class));
+            assertThat("Scoped ClassLoader",scope.getScopedClassLoader(),instanceOf(ClassLoaderBar.class));
+            try (ThreadClassLoaderScope inner = new ThreadClassLoaderScope(new ClassLoaderFoo()))
+            {
+                assertThat("ClassLoader in 'inner'",Thread.currentThread().getContextClassLoader(),instanceOf(ClassLoaderFoo.class));
+                assertThat("Scoped ClassLoader",scope.getScopedClassLoader(),instanceOf(ClassLoaderFoo.class));
+                throw new RuntimeException("Intention exception");
+            }
+        }
+        catch (Throwable ignore)
+        {
+            /* ignore */
+        }
+        assertThat("ClassLoader after 'scope'",Thread.currentThread().getContextClassLoader(),not(instanceOf(ClassLoaderBar.class)));
+    }
+}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceRunTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceRunTest.java
new file mode 100644
index 0000000..bfa15dd
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceRunTest.java
@@ -0,0 +1,398 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread.strategy;
+
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.util.BlockingArrayQueue;
+import org.eclipse.jetty.util.ConcurrentArrayQueue;
+import org.eclipse.jetty.util.thread.ExecutionStrategy.Producer;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExecuteProduceRunTest
+{
+    private final Runnable NULLTASK = new Runnable()
+    {
+        @Override
+        public void run()
+        {            
+        }
+    };
+    
+    
+    ExecuteProduceConsume _ewyk;
+    final BlockingQueue<Runnable> _produce = new BlockingArrayQueue<>();
+    final Queue<Runnable> _executions = new ConcurrentArrayQueue<>();
+    volatile Thread _producer;
+    
+    @Before
+    public void before()
+    {
+        _executions.clear();
+        
+        Producer producer = new Producer()
+        {
+            @Override
+            public Runnable produce()
+            {
+                try
+                {
+                    _producer=Thread.currentThread();
+                    Runnable task= _produce.take();
+                    if (task==NULLTASK)
+                        return null;
+                    return task;
+                }
+                catch(InterruptedException e)
+                {
+                    e.printStackTrace();
+                    return null;
+                }
+                finally
+                {
+                    _producer=null;
+                }
+            }
+        };
+
+        Executor executor =  new Executor()
+        {
+            @Override
+            public void execute(Runnable task)
+            {
+                _executions.add(task);
+            }
+        };
+
+        _ewyk = new ExecuteProduceConsume(producer,executor);
+    }
+
+    @After
+    public void after()
+    {
+        // All done and checked
+        assertThat(_produce.size(),equalTo(0));
+        assertThat(_executions.size(),equalTo(0));
+    }
+    
+    @Test
+    public void testIdle()
+    {
+        _produce.add(NULLTASK);
+        _ewyk.execute();
+    }
+    
+    @Test
+    public void testProduceOneNonBlockingTask()
+    {
+        Task t0 = new Task();
+        _produce.add(t0);
+        _produce.add(NULLTASK);
+        _ewyk.execute();
+        assertThat(t0.hasRun(),equalTo(true));
+        Assert.assertEquals(_ewyk,_executions.poll());
+    }
+    
+    @Test
+    public void testProduceManyNonBlockingTask()
+    {
+        Task[] t = new Task[10];
+        for (int i=0;i<t.length;i++)
+        {
+            t[i]=new Task();
+            _produce.add(t[i]);
+        }
+        _produce.add(NULLTASK);
+        _ewyk.execute();
+
+        for (int i=0;i<t.length;i++)
+            assertThat(t[i].hasRun(),equalTo(true));
+        Assert.assertEquals(_ewyk,_executions.poll());
+
+    }
+
+    @Test
+    public void testProduceOneBlockingTaskIdleByDispatch() throws Exception
+    {
+        final Task t0 = new Task(true);
+        Thread thread = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                _produce.add(t0);
+                _produce.add(NULLTASK);
+                _ewyk.execute();
+            }
+        };
+        thread.start();
+        
+        // wait for execute thread to block in 
+        t0.awaitRun();
+        assertEquals(thread,t0.getThread());
+        
+        // Should have dispatched only one helper 
+        assertEquals(_ewyk,_executions.poll());
+        // which is make us idle
+        _ewyk.run();
+        assertThat(_ewyk.isIdle(),equalTo(true));
+
+        
+        // unblock task
+        t0.unblock();
+        // will run to completion because are already idle
+        thread.join();
+    }
+
+    @Test
+    public void testProduceOneBlockingTaskIdleByTask() throws Exception
+    {
+        final Task t0 = new Task(true);
+        Thread thread = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                _produce.add(t0);
+                _produce.add(NULLTASK);
+                _ewyk.execute();
+            }
+        };
+        thread.start();
+        
+        // wait for execute thread to block in 
+        t0.awaitRun();
+        
+        // Should have dispatched only one helper 
+        Assert.assertEquals(_ewyk,_executions.poll());
+               
+        // unblock task
+        t0.unblock();
+        // will run to completion because are become idle
+        thread.join();
+        assertThat(_ewyk.isIdle(),equalTo(true));
+
+        // because we are idle, dispatched thread is noop
+        _ewyk.run();
+    }
+
+    @Test
+    public void testBlockedInProduce() throws Exception
+    {
+        final Task t0 = new Task(true);
+        Thread thread0 = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                _produce.add(t0);
+                _ewyk.execute();
+            }
+        };
+        thread0.start();
+        
+        // wait for execute thread to block in task
+        t0.awaitRun();
+        assertEquals(thread0,t0.getThread());
+
+        // Should have dispatched another helper 
+        Assert.assertEquals(_ewyk,_executions.poll());
+        
+        // dispatched thread will block in produce 
+        Thread thread1 = new Thread(_ewyk);
+        thread1.start();
+        
+        // Spin
+        while(_producer==null)
+            Thread.yield();
+        
+        // thread1 is blocked in producing
+        assertEquals(thread1,_producer);
+
+        // because we are producing, any other dispatched threads are noops
+        _ewyk.run();
+        
+        // ditto with execute
+        _ewyk.execute();
+        
+        // Now if unblock the production by the dispatched thread
+        final Task t1 = new Task(true);
+        _produce.add(t1);
+
+        // task will be run by thread1
+        t1.awaitRun();
+        assertEquals(thread1,t1.getThread());
+        
+        // and another thread will have been requested
+        Assert.assertEquals(_ewyk,_executions.poll());
+        
+        // If we unblock t1, it will overtake t0 and try to produce again!
+        t1.unblock();
+        
+        // Now thread1 is producing again
+        while(_producer==null)
+            Thread.yield();
+        assertEquals(thread1,_producer);
+        
+        // If we unblock t0, it will decide it is not needed
+        t0.unblock();
+        thread0.join();
+        
+        // If the requested extra thread turns up, it is also noop because we are producing
+        _ewyk.run();
+        
+        // Give the idle job
+        _produce.add(NULLTASK);
+        
+        // Which will eventually idle the producer
+        thread1.join();
+        assertEquals(null,_producer);
+    }
+
+    @Test
+    public void testExecuteWhileIdling() throws Exception
+    {
+        final Task t0 = new Task(true);
+        Thread thread0 = new Thread()
+        {
+            @Override
+            public void run()
+            {
+                _produce.add(t0);
+                _ewyk.execute();
+            }
+        };
+        thread0.start();
+        
+        // wait for execute thread to block in task
+        t0.awaitRun();
+        assertEquals(thread0,t0.getThread());
+
+        // Should have dispatched another helper 
+        Assert.assertEquals(_ewyk,_executions.poll());
+        
+        // We will go idle when we next produce
+        _produce.add(NULLTASK);
+        
+        // execute will return immediately because it did not yet see the idle.
+        _ewyk.execute();
+        
+        // When we unblock t0, thread1 will see the idle, 
+        t0.unblock();
+        
+        // but because there was a pending execute it will try producing again
+        while(_producer==null)
+            Thread.yield();
+        assertEquals(thread0,_producer);
+
+        // and will see new tasks 
+        final Task t1 = new Task(true);
+        _produce.add(t1);
+        t1.awaitRun();
+        assertThat(t1.getThread(),equalTo(thread0));
+
+        // Should NOT have dispatched another helper, because the last is still pending
+        assertThat(_executions.size(),equalTo(0));
+        
+        // When the dispatched thread turns up, it will see the second idle
+        _produce.add(NULLTASK);
+        _ewyk.run();
+        assertThat(_ewyk.isIdle(),equalTo(true));
+        
+        // So that when t1 completes it does not produce again.
+        t1.unblock();
+        thread0.join();
+    }
+    
+
+    public static class Task implements Runnable
+    {
+        final CountDownLatch _block = new CountDownLatch(1);
+        final CountDownLatch _run = new CountDownLatch(1);
+        volatile Thread _thread;
+
+        public Task()
+        {
+            this(false);
+        }
+        
+        public Task(boolean block)
+        {
+            if (!block)
+                _block.countDown();
+        }
+        
+        @Override
+        public void run()
+        {
+            try
+            {
+                _thread=Thread.currentThread();
+                _run.countDown();
+                _block.await();
+            }
+            catch (InterruptedException e)
+            {
+                throw new IllegalStateException(e);
+            }
+            finally
+            {
+                _thread=null;
+            }
+        }
+        
+        public boolean hasRun()
+        {
+            return _run.getCount()<=0;
+        }
+        
+        public void awaitRun()
+        {
+            try
+            {
+                _run.await();
+            }
+            catch (InterruptedException e)
+            {
+                throw new IllegalStateException(e);
+            }
+        }
+        
+        public void unblock()
+        {
+            _block.countDown();
+        }
+        
+        public Thread getThread()
+        {
+            return _thread;
+        }
+    }
+}
diff --git a/jetty-util/src/test/resources/jetty-logging.properties b/jetty-util/src/test/resources/jetty-logging.properties
index 3a0ce97..76035ea 100644
--- a/jetty-util/src/test/resources/jetty-logging.properties
+++ b/jetty-util/src/test/resources/jetty-logging.properties
@@ -1,3 +1,5 @@
 # Setup default logging implementation for during testing
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
 #org.eclipse.jetty.util.LEVEL=DEBUG
+
+#org.eclipse.jetty.util.PathWatcher.Noisy.LEVEL=OFF
diff --git a/jetty-util/src/test/resources/snikeystore b/jetty-util/src/test/resources/snikeystore
new file mode 100644
index 0000000..3c69266
--- /dev/null
+++ b/jetty-util/src/test/resources/snikeystore
Binary files differ
diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml
index 9134dee..7718eef 100644
--- a/jetty-webapp/pom.xml
+++ b/jetty-webapp/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-webapp</artifactId>
@@ -28,60 +28,20 @@
     </resources>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Import-Package>javax.servlet.*;version="[2.6.0,3.2]",*</Import-Package>
-              </instructions>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>
-              ${project.build.outputDirectory}/META-INF/MANIFEST.MF
-            </manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
           <onlyAnalyze>org.eclipse.jetty.webapp.*</onlyAnalyze>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
   <dependencies>
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java
new file mode 100644
index 0000000..e2ff230
--- /dev/null
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/CachingWebAppClassLoader.java
@@ -0,0 +1,121 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.webapp;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jetty.util.ConcurrentHashSet;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.annotation.ManagedOperation;
+
+
+/**
+ * A WebAppClassLoader that caches {@link #getResource(String)} results.
+ * Specifically this ClassLoader caches not found classes and resources,
+ * which can greatly increase performance for applications that search 
+ * for resources.
+ */
+@ManagedObject
+public class CachingWebAppClassLoader extends WebAppClassLoader
+{
+    private final ConcurrentHashSet<String> _notFound = new ConcurrentHashSet<>();
+    private final ConcurrentHashMap<String,URL> _cache = new ConcurrentHashMap<>();
+    
+    public CachingWebAppClassLoader(ClassLoader parent, Context context) throws IOException
+    {
+        super(parent,context);
+    }
+
+    public CachingWebAppClassLoader(Context context) throws IOException
+    {
+        super(context);
+    }
+
+    @Override
+    public URL getResource(String name)
+    {
+        if (_notFound.contains(name))
+            return null;
+        
+        URL url = _cache.get(name);
+        
+        if (name==null)
+        {
+            url = super.getResource(name);
+        
+            if (url==null)
+            {
+                _notFound.add(name);
+            }
+            else
+            {
+                _cache.putIfAbsent(name,url);
+            }
+        }
+        
+        return url;
+    }
+
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
+    {
+        if (_notFound.contains(name))
+            throw new ClassNotFoundException(name+": in notfound cache");
+        try
+        {
+            return super.loadClass(name,resolve);
+        }
+        catch (ClassNotFoundException nfe)
+        {
+            _notFound.add(name);
+            throw nfe; 
+        }
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (_notFound.contains(name))
+            throw new ClassNotFoundException(name+": in notfound cache");
+        try
+        {
+            return super.findClass(name);
+        }
+        catch (ClassNotFoundException nfe)
+        {
+            _notFound.add(name);
+            throw nfe; 
+        }
+    }
+
+    @ManagedOperation
+    public void clearCache()
+    {
+        _cache.clear();
+        _notFound.clear();
+    }
+    
+    @Override
+    public String toString()
+    {
+        return "Caching["+super.toString()+"]";
+    }
+}
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
index fc96019..a9e923e 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
@@ -19,33 +19,56 @@
 
 package org.eclipse.jetty.webapp;
 
+import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
-import java.util.StringTokenizer;
+import java.util.ListIterator;
 
+import org.eclipse.jetty.util.StringUtil;
 
 /* ------------------------------------------------------------ */
 /**
- * ClasspathPattern performs sequential pattern matching of a class name 
+ * Classpath classes list performs sequential pattern matching of a class name 
  * against an internal array of classpath pattern entries.
- * 
- * When an entry starts with '-' (minus), reverse matching is performed.
- * When an entry ends with '.' (period), prefix matching is performed.
- * 
+ * A class pattern is a string of one of the forms:<ul>
+ * <li>'org.package.SomeClass' will match a specific class
+ * <li>'org.package.' will match a specific package hierarchy
+ * <li>'-org.package.Classname' excludes a specific class
+ * <li>'-org.package.' excludes a specific package hierarchy
+ * <li>Nested classes must be specified with the '$' separator if they 
+ * are to be explicitly included or excluded (eg. org.example.MyClass$NestedClass).
+ * <li>Nested classes are matched by their containing class. (eg. -org.example.MyClass
+ * would exclude org.example.MyClass$AnyNestedClass)
+ * </ul>
  * When class is initialized from a classpath pattern string, entries 
  * in this string should be separated by ':' (semicolon) or ',' (comma).
  */
 
-public class ClasspathPattern
+public class ClasspathPattern extends AbstractList<String>
 {
     private static class Entry
     {
-        public String classpath = null;
-        public boolean result = false;
-        public boolean partial = false;      
+        public final String _pattern;
+        public final String _name;
+        public final boolean _inclusive;
+        public final boolean _package;     
+        
+        Entry(String pattern)
+        {
+            _pattern=pattern;
+            _inclusive = !pattern.startsWith("-");
+            _package = pattern.endsWith(".");
+            _name = _inclusive ? pattern : pattern.substring(1).trim();
+        }
+        
+        @Override
+        public String toString()
+        {
+            return _pattern;
+        }
     }
     
-    final private List<String> _patterns = new ArrayList<String>();
     final private List<Entry> _entries = new ArrayList<Entry>();
     
     /* ------------------------------------------------------------ */
@@ -56,160 +79,140 @@
     /* ------------------------------------------------------------ */
     public ClasspathPattern(String[] patterns)
     {
-        setPatterns(patterns);
+        setAll(patterns);
     }
     
     /* ------------------------------------------------------------ */
     public ClasspathPattern(String pattern)
     {
-        setPattern(pattern);
+        add(pattern);
     }
     
+    /* ------------------------------------------------------------ */
+    @Override
+    public String get(int index)
+    {
+        return _entries.get(index)._pattern;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String set(int index, String element)
+    {
+        Entry e = _entries.set(index,new Entry(element));
+        return e==null?null:e._pattern;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void add(int index, String element)
+    {
+        _entries.add(index,new Entry(element));
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public void addPattern(String element)
+    {
+        add(element);
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public String remove(int index)
+    {
+        Entry e = _entries.remove(index);
+        return e==null?null:e._pattern;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public boolean remove(String pattern)
+    {
+        for (int i=_entries.size();i-->0;)
+        {
+            if (pattern.equals(_entries.get(i)._pattern))
+            {
+                _entries.remove(i);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public int size()
+    {
+        return _entries.size();
+    }
 
     /* ------------------------------------------------------------ */
     /**
      * Initialize the matcher by parsing each classpath pattern in an array
      * 
-     * @param patterns array of classpath patterns
+     * @param classes array of classpath patterns
      */
-    private void setPatterns(String[] patterns)
+    private void setAll(String[] classes)
     {
-        _patterns.clear();
         _entries.clear();
-        addPatterns(patterns);
+        addAll(classes);
     }
     
     /* ------------------------------------------------------------ */
     /**
-     * @param patterns array of classpath patterns
+     * @param classes array of classpath patterns
      */
-    private void addPatterns(String[] patterns)
+    private void addAll(String[] classes)
     {
-        if (patterns != null)
-        {
-            Entry entry = null; 
-            for (String pattern : patterns)
-            {
-                entry = createEntry(pattern);
-                if (entry != null) 
-                {
-                    _patterns.add(pattern);
-                    _entries.add(entry);
-                }
-            }
-        }
+        if (classes!=null)
+            addAll(Arrays.asList(classes));
     }
     
     /* ------------------------------------------------------------ */
     /**
-     * @param patterns array of classpath patterns
+     * @param classes array of classpath patterns
      */
-    private void prependPatterns(String[] patterns)
+    public void prepend(String[] classes)
     {
-        if (patterns != null)
+        if (classes != null)
         {
-            Entry entry = null;
             int i=0;
-            for (String pattern : patterns)
+            for (String c : classes)
             {
-                entry = createEntry(pattern);
-                if (entry != null) 
-                {
-                    _patterns.add(i,pattern);
-                    _entries.add(i,entry);
-                    i++;
-                }
+                add(i,c);
+                i++;
             }
         }
     }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * Create an entry object containing information about 
-     * a single classpath pattern
-     * 
-     * @param pattern single classpath pattern
-     * @return corresponding Entry object
-     */
-    private Entry createEntry(String pattern)
-    {
-        Entry entry = null;
-        
-        if (pattern != null)
-        {
-            String item = pattern.trim();
-            if (item.length() > 0)
-            {
-                entry = new Entry();
-                entry.result = !item.startsWith("-");
-                entry.partial = item.endsWith(".");
-                entry.classpath = entry.result ? item : item.substring(1).trim();
-            }
-        }
-        return entry;
-    }
-    
-    /* ------------------------------------------------------------ */
-    /**
-     * Initialize the matcher by parsing a classpath pattern string
-     * 
-     * @param pattern classpath pattern string
-     */
-    public void setPattern(String pattern)
-    {
-        _patterns.clear();
-        _entries.clear();
-        addPattern(pattern);
-    }
 
     /* ------------------------------------------------------------ */
-    /**
-     * Parse a classpath pattern string and appending the result
-     * to the existing configuration.
-     * 
-     * @param pattern classpath pattern string
-     */
-    public void addPattern(String pattern)
+    public void prependPattern(String pattern)
     {
-        ArrayList<String> patterns = new ArrayList<String>();
-        StringTokenizer entries = new StringTokenizer(pattern, ":,");
-        while (entries.hasMoreTokens())
-        {
-            patterns.add(entries.nextToken());
-        }
-        
-        addPatterns(patterns.toArray(new String[patterns.size()]));
-    }   
-    
-
-    /* ------------------------------------------------------------ */
-    public void prependPattern(String classOrPackage)
-    {
-        ArrayList<String> patterns = new ArrayList<String>();
-        StringTokenizer entries = new StringTokenizer(classOrPackage, ":,");
-        while (entries.hasMoreTokens())
-        {
-            patterns.add(entries.nextToken());
-        }
-        
-        prependPatterns(patterns.toArray(new String[patterns.size()]));
+        add(0,pattern);
     }
     
-    
     /* ------------------------------------------------------------ */
     /**
      * @return array of classpath patterns
      */
     public String[] getPatterns()
     {
-        String[] patterns = null;
-        
-        if (_patterns!=null && _patterns.size() > 0)
+        return toArray(new String[_entries.size()]);
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return List of classes excluded class exclusions and package patterns
+     */
+    public List<String> getClasses()
+    {
+        List<String> list = new ArrayList<>();
+        for (Entry e:_entries)
         {
-            patterns = _patterns.toArray(new String[_patterns.size()]);
+            if (e._inclusive && !e._package)
+                list.add(e._name);
         }
-        
-        return patterns;
+        return list;
     }
     
     /* ------------------------------------------------------------ */
@@ -221,48 +224,65 @@
      */
     public boolean match(String name)
     {       
-        boolean result=false;
+        name = name.replace('/','.');
 
-        if (_entries != null)
+        for (Entry entry : _entries)
         {
-            name = name.replace('/','.');
-
-            int startIndex = 0;
-
-            while(startIndex < name.length() && name.charAt(startIndex) == '.') {
-                startIndex++;
-            }
-
-            int dollar = name.indexOf("$");
-
-            int endIndex =  dollar != -1 ? dollar : name.length();
-
-            for (Entry entry : _entries)
+            if (entry==null)
+                continue;
+            if (entry._package)
             {
-                if (entry != null)
-                {               
-                    if (entry.partial)
-                    {
-                        if (name.regionMatches(startIndex, entry.classpath, 0, entry.classpath.length()))
-                        {
-                            result = entry.result;
-                            break;
-                        }
-                    }
-                    else
-                    {
-                        int regionLength = endIndex-startIndex;
-                        if (regionLength == entry.classpath.length()
-                                && name.regionMatches(startIndex, entry.classpath, 0, regionLength))
-                        {
-                            result = entry.result;
-                            break;
-                        }
-                    }
+                if (name.startsWith(entry._name))
+                    return entry._inclusive;
+            }
+            else
+            {
+                if (name.equals(entry._name))
+                    return entry._inclusive;
+                
+                if (name.length()>entry._name.length() && '$'==name.charAt(entry._name.length()) && name.startsWith(entry._name))
+                    return entry._inclusive;
+            }
+        }
+        return false;
+    }
+
+    public void addAfter(String afterPattern,String... patterns)
+    {
+        if (patterns!=null && afterPattern!=null)
+        {
+            ListIterator<String> iter = listIterator();
+            while (iter.hasNext())
+            {
+                String cc=iter.next();
+                if (afterPattern.equals(cc))
+                {
+                    for (int i=0;i<patterns.length;i++)
+                        iter.add(patterns[i]);
+                    return;
                 }
             }
         }
-        return result;
+        throw new IllegalArgumentException("after '"+afterPattern+"' not found in "+this);
     }
 
+    public void addBefore(String beforePattern,String... patterns)
+    {
+        if (patterns!=null && beforePattern!=null)
+        {
+            ListIterator<String> iter = listIterator();
+            while (iter.hasNext())
+            {
+                String cc=iter.next();
+                if (beforePattern.equals(cc))
+                {
+                    iter.previous();
+                    for (int i=0;i<patterns.length;i++)
+                        iter.add(patterns[i]);
+                    return;
+                }
+            }
+        }
+        throw new IllegalArgumentException("before '"+beforePattern+"' not found in "+this);
+    }
 }
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configuration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configuration.java
index 24fc836..005e90b 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configuration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Configuration.java
@@ -41,7 +41,7 @@
      * <p>
      * Typically this step discovers configuration resources
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to pre configure
      */
     public void preConfigure (WebAppContext context) throws Exception;
     
@@ -52,7 +52,7 @@
      * Typically this step applies the discovered configuration resources to
      * either the {@link WebAppContext} or the associated {@link MetaData}.
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to configure
      */
     public void configure (WebAppContext context) throws Exception;
     
@@ -60,7 +60,7 @@
     /* ------------------------------------------------------------------------------- */
     /** Clear down after configuration.
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to post configure
      */
     public void postConfigure (WebAppContext context) throws Exception;
     
@@ -69,7 +69,7 @@
      * This method is called to undo all configuration done. This is
      * called to allow the context to work correctly over a stop/start cycle
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to deconfigure
      */
     public void deconfigure (WebAppContext context) throws Exception;
 
@@ -78,7 +78,7 @@
      * This method is called to destroy a webappcontext. It is typically called when a context 
      * is removed from a server handler hierarchy by the deployer.
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to destroy
      */
     public void destroy (WebAppContext context) throws Exception;
     
@@ -90,7 +90,7 @@
      * has previously been configured by this Configuration.
      * @param template The template context
      * @param context The context to configure
-     * @throws Exception
+     * @throws Exception if unable to clone
      */
     public void cloneConfigure (WebAppContext template, WebAppContext context) throws Exception;
     
@@ -128,14 +128,18 @@
          */
         public static ClassList serverDefault(Server server)
         {
-            ClassList cl=server.getBean(ClassList.class);
-            if (cl!=null)
-                return new ClassList(cl);
-            Object attr = server.getAttribute(ATTR);
-            if (attr instanceof ClassList)
-                return new ClassList((ClassList)attr);
-            if (attr instanceof String[])
-                return new ClassList((String[])attr);
+            ClassList cl=null;
+            if (server!=null)
+            {
+                cl= server.getBean(ClassList.class);
+                if (cl!=null)
+                    return new ClassList(cl);
+                Object attr = server.getAttribute(ATTR);
+                if (attr instanceof ClassList)
+                    return new ClassList((ClassList)attr);
+                if (attr instanceof String[])
+                    return new ClassList((String[])attr);
+            }
             return new ClassList();
         }
         
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java
index 781bc9c..335989f 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java
@@ -25,9 +25,7 @@
 
 /**
  * FragmentConfiguration
- * 
- * 
- * 
+ * <p>
  * Process web-fragments in jars
  */
 public class FragmentConfiguration extends AbstractConfiguration
@@ -55,8 +53,10 @@
     /* ------------------------------------------------------------------------------- */
     /**
      * Look for any web-fragment.xml fragments in META-INF of jars in WEB-INF/lib
+     * @param context the web app context to look in
+     * @param metaData the metadata to populate with fragments
      * 
-     * @throws Exception
+     * @throws Exception if unable to find web fragments
      */
     public void findWebFragments (final WebAppContext context, final MetaData metaData) throws Exception
     {
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java
index c8236cb..94be93f 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/IterativeDescriptorProcessor.java
@@ -27,8 +27,6 @@
 
 /**
  * IterativeDescriptorProcessor
- *
- *
  */
 public abstract class IterativeDescriptorProcessor implements DescriptorProcessor
 {
@@ -41,8 +39,8 @@
      * Register a method to be called back when visiting the node with the given name.
      * The method must exist on a subclass of this class, and must have the signature:
      * public void method (Descriptor descriptor, XmlParser.Node node)
-     * @param nodeName
-     * @param m
+     * @param nodeName the node name
+     * @param m the method name
      */
     public void registerVisitor(String nodeName, Method m)
     {
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java
index abcc6b3..d51acd6 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java
@@ -48,7 +48,6 @@
 {
     private static final Logger LOG = Log.getLogger(JarScanner.class);
 
-
     public abstract void processEntry (URI jarUri, JarEntry entry);
     
     /**
@@ -73,10 +72,10 @@
      * Will iterate over the jar names, matching
      * all those starting with "aaa-" first, then "bbb-".
      *
-     * @param pattern
-     * @param uris
+     * @param pattern the pattern to use for jar matching
+     * @param uris the uris of the jars to scan
      * @param isNullInclusive if true, an empty pattern means all names match, if false, none match
-     * @throws Exception
+     * @throws Exception if unable to scan
      */
     public void scan (Pattern pattern, URI[] uris, boolean isNullInclusive)
     throws Exception
@@ -110,11 +109,11 @@
      * parent loader hierarchy. If false, it is only applied to the
      * classloader passed in.
      * 
-     * @param pattern
-     * @param loader
-     * @param isNullInclusive
-     * @param visitParent
-     * @throws Exception
+     * @param pattern the pattern to use for jar matching
+     * @param loader the class loader to look for jars in
+     * @param isNullInclusive if true, an empty pattern means all names match, if false, none match
+     * @param visitParent if true, visit parent classloaders too
+     * @throws Exception if unable to scan
      */
     public void scan (Pattern pattern, ClassLoader loader, boolean isNullInclusive, boolean visitParent)
     throws Exception
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
index de87977..d198b07 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java
@@ -32,9 +32,6 @@
 import org.eclipse.jetty.util.resource.EmptyResource;
 import org.eclipse.jetty.util.resource.Resource;
 
-
-
-
 /**
  * MetaData
  *
@@ -64,10 +61,6 @@
     protected Ordering _ordering;//can be set to RelativeOrdering by web-default.xml, web.xml, web-override.xml
     protected boolean allowDuplicateFragmentNames = false;
 
-
-
-
-
     public static class OriginInfo
     {
         private final String name;
@@ -263,7 +256,7 @@
      *
      * @param jarResource the jar the fragment is contained in
      * @param xmlResource the resource representing the xml file
-     * @throws Exception
+     * @throws Exception if unable to add fragment
      */
     public void addFragment (Resource jarResource, Resource xmlResource)
     throws Exception
@@ -304,7 +297,7 @@
     /**
      * Annotations not associated with a WEB-INF/lib fragment jar.
      * These are from WEB-INF/classes or the ??container path??
-     * @param annotations
+     * @param annotations the list of discovered annotations to add
      */
     public void addDiscoveredAnnotations(List<DiscoveredAnnotation> annotations)
     {
@@ -324,7 +317,7 @@
      * This method is synchronized as it is anticipated that it may be called by many threads
      * during the annotation scanning phase.
      * 
-     * @param annotation
+     * @param annotation the discovered annotation
      */
     public synchronized void addDiscoveredAnnotation (DiscoveredAnnotation annotation)
     {
@@ -368,7 +361,9 @@
 
     /**
      * Resolve all servlet/filter/listener metadata from all sources: descriptors and annotations.
-     *
+     * 
+     * @param context the context to resolve servlets / filters / listeners metadata from 
+     * @throws Exception if unable to resolve metadata
      */
     public void resolve (WebAppContext context)
     throws Exception
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java
index 24cbcec..6e77a6d 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java
@@ -19,14 +19,21 @@
 package org.eclipse.jetty.webapp;
 
 
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
 import java.net.URI;
 import java.net.URL;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -35,12 +42,13 @@
 
 /**
  * MetaInfConfiguration
+ * <p>
  *
  * Scan META-INF of jars to find:
  * <ul>
- * <li>tlds
- * <li>web-fragment.xml
- * <li>resources
+ * <li>tlds</li>
+ * <li>web-fragment.xml</li>
+ * <li>resources</li>
  * </ul>
  * 
  * The jars which are scanned are:
@@ -91,10 +99,10 @@
      * cache the info discovered indexed by the jar in which it was discovered: this speeds
      * up subsequent context deployments.
      * 
-     * @param context
-     * @param jars
-     * @param useCaches
-     * @throws Exception
+     * @param context the context for the scan
+     * @param jars the jars resources to scan
+     * @param useCaches if true, cache the info discovered
+     * @throws Exception if unable to scan the jars
      */
     public void scanJars (final WebAppContext context, Collection<Resource> jars, boolean useCaches)
     throws Exception
@@ -140,10 +148,10 @@
     /**
      * Scan for META-INF/resources dir in the given jar.
      * 
-     * @param context
-     * @param target
-     * @param cache
-     * @throws Exception
+     * @param context the context for the scan
+     * @param target the target resource to scan for
+     * @param cache the resource cache
+     * @throws Exception if unable to scan for resources
      */
     public void scanForResources (WebAppContext context, Resource target, ConcurrentHashMap<Resource,Resource> cache)
     throws Exception
@@ -175,8 +183,12 @@
                 URI uri = target.getURI();
                 resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources");
             }
+            
             if (!resourcesDir.exists() || !resourcesDir.isDirectory())
+            {
+                resourcesDir.close();
                 resourcesDir = EmptyResource.INSTANCE;
+            }
 
             if (cache != null)
             {               
@@ -188,7 +200,9 @@
             }
 
             if (resourcesDir == EmptyResource.INSTANCE)
+            {
                 return;
+            }
         }
 
         //add it to the meta inf resources for this context
@@ -199,16 +213,17 @@
             context.setAttribute(METAINF_RESOURCES, dirs);
         }
         if (LOG.isDebugEnabled()) LOG.debug(resourcesDir+" added to context");
+
         dirs.add(resourcesDir);
     }
     
     /**
      * Scan for META-INF/web-fragment.xml file in the given jar.
      * 
-     * @param context
-     * @param jar
-     * @param cache
-     * @throws Exception
+     * @param context the context for the scan
+     * @param jar the jar resource to scan for fragements in
+     * @param cache the resource cache
+     * @throws Exception if unable to scan for fragments
      */
     public void scanForFragment (WebAppContext context, Resource jar, ConcurrentHashMap<Resource,Resource> cache)
     throws Exception
@@ -240,7 +255,10 @@
                 webFrag = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml");
             }
             if (!webFrag.exists() || webFrag.isDirectory())
+            {
+                webFrag.close();
                 webFrag = EmptyResource.INSTANCE;
+            }
             
             if (cache != null)
             {
@@ -270,10 +288,10 @@
     /**
      * Discover META-INF/*.tld files in the given jar
      * 
-     * @param context
-     * @param jar
-     * @param cache
-     * @throws Exception
+     * @param context the context for the scan
+     * @param jar the jar resources to scan tlds for
+     * @param cache the resource cache
+     * @throws Exception if unable to scan for tlds
      */
     public void scanForTlds (WebAppContext context, Resource jar, ConcurrentHashMap<Resource, Collection<URL>> cache)
     throws Exception
@@ -297,30 +315,17 @@
         else
         {
             //not using caches or not in the cache so find all tlds
-            Resource metaInfDir = null;
+            tlds = new HashSet<URL>();  
             if (jar.isDirectory())
             {
-                //TODO ??????
-                metaInfDir = jar.addPath("/META-INF/");
+                tlds.addAll(getTlds(jar.getFile()));
             }
             else
             {
                 URI uri = jar.getURI();
-                metaInfDir = Resource.newResource("jar:"+uri+"!/META-INF/");
+                tlds.addAll(getTlds(uri));
             }
 
-            //find any *.tld files inside META-INF or subdirs
-            tlds = new HashSet<URL>();      
-            Collection<Resource> resources = metaInfDir.getAllResources();
-            for (Resource t:resources)
-            {
-                String name = t.toString();
-                if (name.endsWith(".tld"))
-                {
-                    if (LOG.isDebugEnabled()) LOG.debug(t+" tld discovered");
-                    tlds.add(t.getURL());
-                }
-            }
             if (cache != null)
             {  
                 if (LOG.isDebugEnabled()) LOG.debug(jar+" tld cache updated");
@@ -333,13 +338,13 @@
                 return;
         }
 
-        Collection<URL> tld_resources=(Collection<URL>)context.getAttribute(METAINF_TLDS);
-        if (tld_resources == null)
+        Collection<URL> metaInfTlds = (Collection<URL>)context.getAttribute(METAINF_TLDS);
+        if (metaInfTlds == null)
         {
-            tld_resources = new HashSet<URL>();
-            context.setAttribute(METAINF_TLDS, tld_resources);
+            metaInfTlds = new HashSet<URL>();
+            context.setAttribute(METAINF_TLDS, metaInfTlds);
         }
-        tld_resources.addAll(tlds);  
+        metaInfTlds.addAll(tlds);  
         if (LOG.isDebugEnabled()) LOG.debug("tlds added to context");
     }
     
@@ -347,8 +352,72 @@
     @Override
     public void postConfigure(WebAppContext context) throws Exception
     {
-        context.setAttribute(METAINF_FRAGMENTS, null); 
         context.setAttribute(METAINF_RESOURCES, null);
+
+        context.setAttribute(METAINF_FRAGMENTS, null); 
+   
         context.setAttribute(METAINF_TLDS, null);
     }
+    
+    /**
+     * Find all .tld files in all subdirs of the given dir.
+     * 
+     * @param dir the directory to scan
+     * @return the list of tlds found
+     * @throws IOException if unable to scan the directory
+     */
+    public Collection<URL>  getTlds (File dir) throws IOException
+    {
+        if (dir == null || !dir.isDirectory())
+            return Collections.emptySet();
+        
+        HashSet<URL> tlds = new HashSet<URL>();
+        
+        File[] files = dir.listFiles();
+        if (files != null)
+        {
+            for (File f:files)
+            {
+                if (f.isDirectory())
+                    tlds.addAll(getTlds(f));
+                else
+                {
+                    String name = f.getCanonicalPath();
+                    if (name.contains("META-INF") && name.endsWith(".tld"))
+                        tlds.add(f.toURI().toURL());
+                }
+            }
+        }
+        return tlds;  
+    }
+    
+    /**
+     * Find all .tld files in the given jar.
+     * 
+     * @param uri the uri to jar file
+     * @return the collection of tlds as url references  
+     * @throws IOException if unable to scan the jar file
+     */
+    public Collection<URL> getTlds (URI uri) throws IOException
+    {
+        HashSet<URL> tlds = new HashSet<URL>();
+        
+        URL url = new URL("jar:"+uri+"!/");
+        JarURLConnection jarConn = (JarURLConnection) url.openConnection();
+        jarConn.setUseCaches(Resource.getDefaultUseCaches());
+        JarFile jarFile = jarConn.getJarFile();
+        Enumeration<JarEntry> entries = jarFile.entries();
+        while (entries.hasMoreElements())
+        {
+            JarEntry e = entries.nextElement();
+            String name = e.getName();
+            if (name.startsWith("META-INF") && name.endsWith(".tld"))
+            {
+                tlds.add(new URL("jar:"+uri+"!/"+name));
+            }
+        }
+        if (!Resource.getDefaultUseCaches())
+            jarFile.close();
+        return tlds;
+    }
 }
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java
index 7586d67..8d9aff9 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java
@@ -29,18 +29,14 @@
 
 
 /**
- * Ordering
- *
  * Ordering options for jars in WEB-INF lib.
  */
 public interface Ordering
 {  
-
     public List<Resource> order(List<Resource> fragments);
     public boolean isAbsolute ();
     public boolean hasOther();
 
-
     /**
      * AbsoluteOrdering
      *
@@ -150,6 +146,10 @@
         @Override
         public List<Resource> order(List<Resource> jars)
         {         
+            _beforeOthers.clear();
+            _afterOthers.clear();
+            _noOthers.clear();
+
             //for each jar, put it into the ordering according to the fragment ordering
             for (Resource jar:jars)
             {
@@ -161,17 +161,17 @@
                     {
                         case None:
                         {
-                            ((RelativeOrdering)_metaData.getOrdering()).addNoOthers(jar);
+                            addNoOthers(jar);
                             break;
                         }
                         case Before:
                         { 
-                            ((RelativeOrdering)_metaData.getOrdering()).addBeforeOthers(jar);
+                            addBeforeOthers(jar);
                             break;
                         }
                         case After:
                         {
-                            ((RelativeOrdering)_metaData.getOrdering()).addAfterOthers(jar);
+                            addAfterOthers(jar);
                             break;
                         }
                     } 
@@ -179,7 +179,7 @@
                 else
                 {
                     //jar fragment has no descriptor, but there is a relative ordering in place, so it must be part of the others
-                    ((RelativeOrdering)_metaData.getOrdering()).addNoOthers(jar);
+                    addNoOthers(jar);
                 }
             }            
                 
@@ -350,9 +350,10 @@
     
        /**
         * Is fragment with name a before fragment with name b?
-        * @param list
-        * @param fragNameA
-        * @param fragNameB
+        * 
+        * @param list the list of resources
+        * @param fragNameA the first fragment
+        * @param fragNameB the second fragment
         * @return true if fragment name A is before fragment name B 
         */
        protected boolean isBefore (List<Resource> list, String fragNameA, String fragNameB)
@@ -397,9 +398,10 @@
     
        /**
         * Is fragment name "a" after fragment name "b"?
-        * @param list
-        * @param fragNameA
-        * @param fragNameB
+        * 
+        * @param list the list of resources
+        * @param fragNameA the first fragment
+        * @param fragNameB the second fragment
         * @return true if fragment name A is after fragment name B
         */
        protected boolean isAfter(List<Resource> list, String fragNameA, String fragNameB)
@@ -441,9 +443,9 @@
         * Insert the resource matching the fragName into the list of resources
         * at the location indicated by index.
         * 
-        * @param list
-        * @param index
-        * @param fragName
+        * @param list the list of resources
+        * @param index the index to insert into
+        * @param fragName the fragment name to insert
         */
        protected void insert(List<Resource> list, int index, String fragName)
        {
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java
index 753b5f2..7f4ad3d 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java
@@ -51,6 +51,7 @@
 import org.eclipse.jetty.servlet.ServletMapping;
 import org.eclipse.jetty.util.ArrayUtil;
 import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.security.Constraint;
@@ -58,9 +59,9 @@
 import org.eclipse.jetty.xml.XmlParser.Node;
 
 /**
- * StandardDescriptorProcessor
- *
- * Process a web.xml, web-defaults.xml, web-overrides.xml, web-fragment.xml.
+ * StandardDescriptorProcessor.
+ * <p>
+ * Process the web.xml, web-defaults.xml, web-overrides.xml, and web-fragment.xml descriptors.
  */
 public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
 {
@@ -148,11 +149,6 @@
         _servletMappings.clear();
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitContextParam (WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String name = node.getString("param-name", false, true);
@@ -196,13 +192,6 @@
 
     }
 
-
-    /* ------------------------------------------------------------ */
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitDisplayName(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //Servlet Spec 3.0 p. 74 Ignore from web-fragments
@@ -213,12 +202,6 @@
         }
     }
 
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitServlet(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String id = node.getAttribute("id");
@@ -621,13 +604,6 @@
         }
     }
 
-
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitServletMapping(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //Servlet Spec 3.0, p74
@@ -669,12 +645,6 @@
         }
     }
 
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitSessionConfig(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         XmlParser.Node tNode = node.get("session-timeout");
@@ -997,13 +967,6 @@
         }
     }
 
-
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitMimeMapping(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String extension = node.getString("extension", false, true);
@@ -1046,11 +1009,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitWelcomeFileList(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         switch (context.getMetaData().getOrigin("welcome-file-list"))
@@ -1095,11 +1053,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitLocaleEncodingList(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         Iterator<XmlParser.Node> iter = node.iterator("locale-encoding-mapping");
@@ -1146,11 +1099,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitErrorPage(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String error = node.getString("error-code", false, true);
@@ -1212,10 +1160,6 @@
 
     }
 
-    /**
-     * @param context
-     * @param node
-     */
     public void addWelcomeFiles(WebAppContext context, XmlParser.Node node)
     {
         Iterator<XmlParser.Node> iter = node.iterator("welcome-file");
@@ -1230,12 +1174,6 @@
         }
     }
 
-
-    /**
-     * @param servletName
-     * @param node
-     * @param context
-     */
     public ServletMapping addServletMapping (String servletName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
     {
         ServletMapping mapping = new ServletMapping();
@@ -1249,8 +1187,7 @@
             String p = iter.next().toString(false, true);
             p = normalizePattern(p);
             
-            //check if there is already a mapping for this path, and if there is && it is from a defaultdescriptor
-            //remove it in favour of the new one      
+            //check if there is already a mapping for this path
             ListIterator<ServletMapping> listItor = _servletMappings.listIterator();
             boolean found = false;
             while (listItor.hasNext() && !found)
@@ -1260,21 +1197,30 @@
                 {
                     for (String ps:sm.getPathSpecs())
                     {
-                        if (p.equals(ps) && sm.isDefault())
+                        //The same path has been mapped multiple times, either to a different servlet or the same servlet.
+                        //If its a different servlet, this is only valid to do if the old mapping was from a default descriptor.
+                        if (p.equals(ps) && (sm.isDefault() || servletName.equals(sm.getServletName())))
                         {
-                            if (LOG.isDebugEnabled()) LOG.debug("{} in mapping {} from defaults descriptor is overridden by ",ps,sm,servletName);
+                            if (sm.isDefault())
+                            {
+                                if (LOG.isDebugEnabled()) LOG.debug("{} in mapping {} from defaults descriptor is overridden by ",ps,sm,servletName);
+                            }
+                            else
+                                LOG.warn("Duplicate mapping from {} to {}", p, servletName);
+
                             //remove ps from the path specs on the existing mapping
                             //if the mapping now has no pathspecs, remove it
                             String[] updatedPaths = ArrayUtil.removeFromArray(sm.getPathSpecs(), ps);
+                            
                             if (updatedPaths == null || updatedPaths.length == 0)
-                            { 
-                                if (LOG.isDebugEnabled()) LOG.debug("Removed mapping {} from defaults descriptor",sm);
+                            {
+                                if (LOG.isDebugEnabled()) LOG.debug("Removed empty mapping {}",sm);
                                 listItor.remove();
                             }
                             else 
                             {
                                 sm.setPathSpecs(updatedPaths);
-                                if (LOG.isDebugEnabled()) LOG.debug("Removed path {} from mapping {} from defaults descriptor ", p,sm);
+                                if (LOG.isDebugEnabled()) LOG.debug("Removed path {} from mapping {}", p,sm);
                             }
                             found = true;
                             break;
@@ -1282,24 +1228,17 @@
                     }
                 }
             }
-            
+
             paths.add(p);
             context.getMetaData().setOrigin(servletName+".servlet.mapping."+p, descriptor);
         }
+
         mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
         if (LOG.isDebugEnabled()) LOG.debug("Added mapping {} ",mapping);
-        
-      
-      
         _servletMappings.add(mapping);
         return mapping;
     }
 
-    /**
-     * @param filterName
-     * @param node
-     * @param context
-     */
     public void addFilterMapping (String filterName, XmlParser.Node node, WebAppContext context, Descriptor descriptor)
     {
         FilterMapping mapping = new FilterMapping();
@@ -1340,12 +1279,6 @@
         _filterMappings.add(mapping);
     }
 
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitTagLib(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //Additive across web.xml and web-fragment.xml
@@ -1367,11 +1300,6 @@
         config.addTaglibDescriptor(tl);
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitJspConfig(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //Additive across web.xml and web-fragment.xml
@@ -1441,18 +1369,55 @@
         //add mappings to the jsp servlet from the property-group mappings
         if (paths.size() > 0)
         {
-            ServletMapping mapping = new ServletMapping();
-            mapping.setServletName("jsp");
-            mapping.setPathSpecs(paths.toArray(new String[paths.size()]));
-            _servletMappings.add(mapping);
+            ServletMapping jspMapping = null;
+            for (ServletMapping m: _servletMappings)
+            {
+                if (m.getServletName().equals("jsp"))
+                {
+                    jspMapping = m;
+                    break;
+                }
+            }
+            if (jspMapping != null)
+            {
+                if (jspMapping.getPathSpecs() == null)
+                {
+                    //no paths in jsp servlet mapping, we will add all of ours
+                    if (LOG.isDebugEnabled()) LOG.debug("Adding all paths from jsp-config to jsp servlet mapping");
+                    jspMapping.setPathSpecs(paths.toArray(new String[paths.size()]));
+                }
+                else
+                {
+                    //check if each of our paths is already present in existing mapping
+                    ListIterator<String> piterator = paths.listIterator();
+                    while (piterator.hasNext())
+                    {
+                        String p = piterator.next();
+                        if (jspMapping.containsPathSpec(p))
+                            piterator.remove();
+                    }
+                    
+                    //any remaining paths, add to the jspMapping
+                    if (paths.size() > 0)
+                    {
+                        for (String p:jspMapping.getPathSpecs())
+                            paths.add(p);
+                        if (LOG.isDebugEnabled()) LOG.debug("Adding extra paths from jsp-config to jsp servlet mapping");
+                        jspMapping.setPathSpecs((String[])paths.toArray(new String[paths.size()]));
+                    }
+                }
+            }
+            else
+            {
+                //no mapping for jsp yet, make one
+                ServletMapping mapping = new ServletMapping();
+                mapping.setServletName("jsp");
+                mapping.setPathSpecs(paths.toArray(new String[paths.size()]));
+                _servletMappings.add(mapping);
+            }
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitSecurityConstraint(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         Constraint scBase = new Constraint();
@@ -1562,12 +1527,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     * @throws Exception
-     */
     public void visitLoginConfig(WebAppContext context, Descriptor descriptor, XmlParser.Node node) throws Exception
     {
         //ServletSpec 3.0 p74 says elements present 0/1 time if specified in web.xml take
@@ -1732,11 +1691,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitSecurityRole(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //ServletSpec 3.0, p74 elements with multiplicity >1 are additive when merged
@@ -1745,12 +1699,6 @@
         ((ConstraintAware)context.getSecurityHandler()).addRole(role);
     }
 
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitFilter(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String name = node.getString("filter-name", false, true);
@@ -1882,11 +1830,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitFilterMapping(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         //Servlet Spec 3.0, p74
@@ -1925,12 +1868,6 @@
         }
     }
 
-
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitListener(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         String className = node.getString("listener-class", false, true);
@@ -1972,11 +1909,6 @@
         }
     }
 
-    /**
-     * @param context
-     * @param descriptor
-     * @param node
-     */
     public void visitDistributable(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         // the element has no content, so its simple presence
@@ -1989,25 +1921,18 @@
     /**
      * Servlet spec 3.1. When present in web.xml, this means that http methods that are
      * not covered by security constraints should have access denied.
-     * 
+     * <p>
      * See section 13.8.4, pg 145
-     * @param context
-     * @param descriptor
-     * @param node
+     * 
+     * @param context the of the processing
+     * @param descriptor the descriptor
+     * @param node the xml node
      */
     public void visitDenyUncoveredHttpMethods(WebAppContext context, Descriptor descriptor, XmlParser.Node node)
     {
         ((ConstraintAware)context.getSecurityHandler()).setDenyUncoveredHttpMethods(true);
     }
 
-    /**
-     * @param context
-     * @param clazz
-     * @return the new event listener
-     * @throws ServletException
-     * @throws InstantiationException
-     * @throws IllegalAccessException
-     */
     public EventListener newListenerInstance(WebAppContext context,Class<? extends EventListener> clazz) throws Exception
     {
         ListenerHolder h = context.getServletHandler().newListenerHolder(Source.DESCRIPTOR);
@@ -2018,15 +1943,9 @@
 
     }
 
-    /**
-     * @param p
-     * @return the normalized pattern
-     */
     public String normalizePattern(String p)
     {
         if (p != null && p.length() > 0 && !p.startsWith("/") && !p.startsWith("*")) return "/" + p;
         return p;
     }
-
-
 }
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
index e7d3e0b..4256d2a 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
@@ -23,7 +23,6 @@
 import java.io.InputStream;
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
-import java.lang.instrument.Instrumentation;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.security.CodeSource;
@@ -46,11 +45,12 @@
 import org.eclipse.jetty.util.resource.ResourceCollection;
 
 
-/* ------------------------------------------------------------ */
-/** ClassLoader for HttpContext.
+/** 
+ * ClassLoader for HttpContext.
+ * <p>
  * Specializes URLClassLoader with some utility and file mapping
  * methods.
- *
+ * <p>
  * This loader defaults to the 2.3 servlet spec behavior where non
  * system classes are loaded from the classpath in preference to the
  * parent loader.  Java2 compliant loading, where the parent loader
@@ -58,14 +58,18 @@
  * {@link org.eclipse.jetty.webapp.WebAppContext#setParentLoaderPriority(boolean)} 
  * method and influenced with {@link WebAppContext#isServerClass(String)} and 
  * {@link WebAppContext#isSystemClass(String)}.
- *
+ * <p>
  * If no parent class loader is provided, then the current thread 
  * context classloader will be used.  If that is null then the 
  * classloader that loaded this class is used as the parent.
- * 
  */
 public class WebAppClassLoader extends URLClassLoader
 {
+    static
+    {
+        registerAsParallelCapable();
+    }
+
     private static final Logger LOG = Log.getLogger(WebAppClassLoader.class);
 
     private final Context _context;
@@ -131,7 +135,10 @@
     }
     
     /* ------------------------------------------------------------ */
-    /** Constructor.
+    /** 
+     * Constructor.
+     * @param context the context for this classloader
+     * @throws IOException if unable to initialize from context
      */
     public WebAppClassLoader(Context context)
         throws IOException
@@ -140,7 +147,12 @@
     }
     
     /* ------------------------------------------------------------ */
-    /** Constructor.
+    /** 
+     * Constructor.
+     * 
+     * @param parent the parent classloader 
+     * @param context the context for this classloader
+     * @throws IOException if unable to initialize classloader
      */
     public WebAppClassLoader(ClassLoader parent, Context context)
         throws IOException
@@ -200,6 +212,7 @@
      * @param resource Comma or semicolon separated path of filenames or URLs
      * pointing to directories or jar files. Directories should end
      * with '/'.
+     * @throws IOException if unable to add classpath from resource
      */
     public void addClassPath(Resource resource)
         throws IOException
@@ -220,6 +233,7 @@
      * @param classPath Comma or semicolon separated path of filenames or URLs
      * pointing to directories or jar files. Directories should end
      * with '/'.
+     * @throws IOException if unable to add classpath
      */
     public void addClassPath(String classPath)
         throws IOException
@@ -243,11 +257,13 @@
                 File file= resource.getFile();
                 if (file != null)
                 {
-                    URL url= resource.getURL();
+                    URL url= resource.getURI().toURL();
                     addURL(url);
                 }
                 else if (resource.isDirectory())
-                    addURL(resource.getURL());
+                {
+                    addURL(resource.getURI().toURL());
+                }
                 else
                 {
                     if (LOG.isDebugEnabled())
@@ -283,6 +299,8 @@
                 try 
                 {
                     Resource fn=lib.addPath(files[f]);
+                    if(LOG.isDebugEnabled())
+                        LOG.debug("addJar - {}", fn);
                     String fnlc=fn.getName().toLowerCase(Locale.ENGLISH);
                     // don't check if this is a directory, see Bug 353165
                     if (isFileSupported(fnlc))
@@ -356,42 +374,49 @@
         String tmp = name;
         if (tmp != null && tmp.endsWith(".class"))
             tmp = tmp.substring(0, tmp.length()-6);
-      
+        
         boolean system_class=_context.isSystemClass(tmp);
         boolean server_class=_context.isServerClass(tmp);
         
+        if (LOG.isDebugEnabled())
+            LOG.debug("getResource({}) system={} server={} cl={}",name,system_class,server_class,this);
+        
         if (system_class && server_class)
             return null;
         
+        ClassLoader source=null;
+        
         if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class)
         {
             tried_parent= true;
             
             if (_parent!=null)
-                url= _parent.getResource(name);
+            {
+                source=_parent;
+                url=_parent.getResource(name);
+            }
         }
 
         if (url == null)
         {
             url= this.findResource(name);
-
+            source=this;
             if (url == null && name.startsWith("/"))
-            {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("HACK leading / off " + name);
                 url= this.findResource(name.substring(1));
-            }
         }
 
         if (url == null && !tried_parent && !server_class )
         {
             if (_parent!=null)
+            {
+                tried_parent=true;
+                source=_parent;
                 url= _parent.getResource(name);
+            }
         }
 
-        if (url != null)
-            if (LOG.isDebugEnabled())
-                LOG.debug("getResource("+name+")=" + url);
+        if (LOG.isDebugEnabled())
+            LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent);
 
         return url;
     }
@@ -405,67 +430,85 @@
 
     /* ------------------------------------------------------------ */
     @Override
-    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
     {
-        Class<?> c= findLoadedClass(name);
-        ClassNotFoundException ex= null;
-        boolean tried_parent= false;
-        
-        boolean system_class=_context.isSystemClass(name);
-        boolean server_class=_context.isServerClass(name);
-        
-        if (system_class && server_class)
+        synchronized (getClassLoadingLock(name))
         {
-            return null;
-        }
-        
-        if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
-        {
-            tried_parent= true;
-            try
+            Class<?> c= findLoadedClass(name);
+            ClassNotFoundException ex= null;
+            boolean tried_parent= false;
+
+            boolean system_class=_context.isSystemClass(name);
+            boolean server_class=_context.isServerClass(name);
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("loadClass({}) system={} server={} cl={}",name,system_class,server_class,this);
+            
+            ClassLoader source=null;
+            
+            if (system_class && server_class)
             {
+                return null;
+            }
+
+            if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class)
+            {
+                tried_parent= true;
+                source=_parent;
+                try
+                {
+                    c= _parent.loadClass(name);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("loaded " + c);
+                }
+                catch (ClassNotFoundException e)
+                {
+                    ex= e;
+                }
+            }
+
+            if (c == null)
+            {
+                try
+                {
+                    source=this;
+                    c= this.findClass(name);
+                }
+                catch (ClassNotFoundException e)
+                {
+                    ex= e;
+                }
+            }
+
+            if (c == null && _parent!=null && !tried_parent && !server_class )
+            {
+                tried_parent=true;
+                source=_parent;
                 c= _parent.loadClass(name);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("loaded " + c);
             }
-            catch (ClassNotFoundException e)
+
+            if (c == null && ex!=null)
             {
-                ex= e;
+                LOG.debug("!loadedClass({}) from={} tried_parent={}",name,this,tried_parent);
+                throw ex;
             }
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent);
+            
+            if (resolve)
+                resolveClass(c);
+
+            return c;
         }
-
-        if (c == null)
-        {
-            try
-            {
-                c= this.findClass(name);
-            }
-            catch (ClassNotFoundException e)
-            {
-                ex= e;
-            }
-        }
-
-        if (c == null && _parent!=null && !tried_parent && !server_class )
-            c= _parent.loadClass(name);
-
-        if (c == null && ex!=null)
-            throw ex;
-
-        if (resolve)
-            resolveClass(c);
-
-        if (LOG.isDebugEnabled())
-            LOG.debug("loaded {} from {}",c,c==null?null:c.getClassLoader());
-        
-        return c;
     }
 
     /* ------------------------------------------------------------ */
     /**
-     * @see addTransformer
-     * @deprecated
+     * @param transformer the transformer to add
+     * @deprecated {@link #addTransformer(ClassFileTransformer)} instead
      */
+    @Deprecated
     public void addClassFileTransformer(ClassFileTransformer transformer)
     {
         _transformers.add(transformer);
@@ -473,27 +516,23 @@
     
     /* ------------------------------------------------------------ */
     /**
-     * @see removeTransformer
-     * @deprecated
+     * @param transformer the transformer to remove
+     * @return true if transformer was removed
+     * @deprecated use {@link #removeTransformer(ClassFileTransformer)} instead
      */
+    @Deprecated
     public boolean removeClassFileTransformer(ClassFileTransformer transformer)
     {
         return _transformers.remove(transformer);
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * @see addClassFileTransformer
-     */
     public void addTransformer(ClassFileTransformer transformer)
     {
         _transformers.add(transformer);
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @see removeClassFileTransformer
-     */
     public boolean removeTransformer(ClassFileTransformer transformer)
     {
         return _transformers.remove(transformer);
@@ -520,7 +559,10 @@
             {
                 content = url.openStream();
                 byte[] bytes = IO.readBytes(content);
-                    
+
+                if (LOG.isDebugEnabled())
+                    LOG.debug("foundClass({}) url={} cl={}",name,url,this);
+                
                 for (ClassFileTransformer transformer : _transformers)
                 {
                     byte[] tmp = transformer.transform(this,name,null,null,bytes);
@@ -557,6 +599,13 @@
         return clazz;
     }
     
+    
+    @Override
+    public void close() throws IOException
+    {
+        super.close();
+    }
+
     /* ------------------------------------------------------------ */
     @Override
     public String toString()
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
index 91415d5..25d65ad 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLClassLoader;
 import java.security.PermissionCollection;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -47,6 +48,7 @@
 import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.server.ClassLoaderDump;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HandlerContainer;
 import org.eclipse.jetty.server.Server;
@@ -56,18 +58,21 @@
 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.util.AttributesMap;
 import org.eclipse.jetty.util.Loader;
 import org.eclipse.jetty.util.MultiException;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.DumpableCollection;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceCollection;
 
-/* ------------------------------------------------------------ */
-/** Web Application Context Handler.
+/** 
+ * Web Application Context Handler.
+ * <p>
  * The WebAppContext handler is an extension of ContextHandler that
  * coordinates the construction and configuration of nested handlers:
  * {@link org.eclipse.jetty.security.ConstraintSecurityHandler}, {@link org.eclipse.jetty.server.session.SessionHandler}
@@ -76,8 +81,6 @@
  * the default being  {@link org.eclipse.jetty.webapp.WebXmlConfiguration} and
  * {@link org.eclipse.jetty.webapp.JettyWebXmlConfiguration}.
  *
- * @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base"
- *
  */
 @ManagedObject("Web Application ContextHandler")
 public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
@@ -105,6 +108,8 @@
     // System classes are classes that cannot be replaced by
     // the web application, and they are *always* loaded via
     // system classloader.
+    // TODO This centrally managed list of features that are exposed/hidden needs to be replaced
+    // with a more automatic distributed mechanism
     public final static String[] __dftSystemClasses =
     {
         "java.",                            // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
@@ -118,16 +123,18 @@
         "org.eclipse.jetty.jaas.",          // webapp cannot change jaas classes
         "org.eclipse.jetty.websocket.",     // webapp cannot change / replace websocket classes
         "org.eclipse.jetty.util.log.",      // webapp should use server log
-        "org.eclipse.jetty.servlet.ServletContextHandler.Decorator", // for CDI / weld use
         "org.eclipse.jetty.servlet.DefaultServlet", // webapp cannot change default servlets
         "org.eclipse.jetty.jsp.JettyJspServlet", //webapp cannot change jetty jsp servlet
-        "org.eclipse.jetty.servlets.AsyncGzipFilter" // special case for AsyncGzipFilter
+        "org.eclipse.jetty.servlets.PushCacheFilter", //must be loaded by container classpath
+        "org.eclipse.jetty.servlets.PushSessionCacheFilter" //must be loaded by container classpath
     } ;
 
     // Server classes are classes that are hidden from being
     // loaded by the web application using system classloader,
     // so if web application needs to load any of such classes,
     // it has to include them in its distribution.
+    // TODO This centrally managed list of features that are exposed/hidden needs to be replaced
+    // with a more automatic distributed mechanism
     public final static String[] __dftServerClasses =
     {
         "-org.eclipse.jetty.jmx.",          // don't hide jmx classes
@@ -142,7 +149,7 @@
         "-org.eclipse.jetty.websocket.",    // don't hide websocket classes from webapps (allow webapp to use ones from system classloader)
         "-org.eclipse.jetty.apache.",       // don't hide jetty apache impls
         "-org.eclipse.jetty.util.log.",     // don't hide server log 
-        "-org.eclipse.jetty.servlet.ServletContextHandler.Decorator", // don't hide CDI / weld interface  
+        "-org.eclipse.jetty.alpn.",         // don't hide ALPN
         "org.objectweb.asm.",               // hide asm used by jetty
         "org.eclipse.jdt.",                 // hide jdt used by jetty
         "org.eclipse.jetty."                // hide other jetty classes
@@ -242,11 +249,14 @@
     /* ------------------------------------------------------------ */
     /**
      * This constructor is used in the geronimo integration.
-     *
+     * 
+     * @param parent the parent handler 
+     * @param contextPath the context path
      * @param sessionHandler SessionHandler for this web app
      * @param securityHandler SecurityHandler for this web app
      * @param servletHandler ServletHandler for this web app
      * @param errorHandler ErrorHandler for this web app
+     * @param options the options ({@link ServletContextHandler#SESSIONS} and/or {@link ServletContextHandler#SECURITY}) 
      */
     public WebAppContext(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler,int options) 
     {
@@ -280,12 +290,13 @@
 
 
     /* ------------------------------------------------------------ */
-    /** Set Resource Alias.
+    /** 
+     * Set Resource Alias.
      * Resource aliases map resource uri's within a context.
      * They may optionally be used by a handler when looking for
      * a resource.
-     * @param alias
-     * @param uri
+     * @param alias the alias for a resource
+     * @param uri the uri for the resource
      */
     public void setResourceAlias(String alias, String uri)
     {
@@ -345,13 +356,12 @@
     {
         super.setClassLoader(classLoader);
 
-//        if ( !(classLoader instanceof WebAppClassLoader) )
-//        {
-//            LOG.info("NOTE: detected a classloader which is not an instance of WebAppClassLoader being set on WebAppContext, some typical class and resource locations may be missing on: " + toString() );
-//        }
-
+        String name = getDisplayName();
+        if (name==null) 
+            name=getContextPath();
+        
         if (classLoader!=null && classLoader instanceof WebAppClassLoader && getDisplayName()!=null)
-            ((WebAppClassLoader)classLoader).setName(getDisplayName());
+            ((WebAppClassLoader)classLoader).setName(name);
     }
 
     /* ------------------------------------------------------------ */
@@ -415,11 +425,13 @@
     }
 
     /* ------------------------------------------------------------ */
-    /** Pre configure the web application.
+    /** 
+     * Pre configure the web application.
      * <p>
      * The method is normally called from {@link #start()}. It performs
      * the discovery of the configurations to be applied to this context,
-     * specifically:<ul>
+     * specifically:
+     * <ul>
      * <li>Instantiate the {@link Configuration} instances with a call to {@link #loadConfigurations()}.
      * <li>Setup the default System classes by calling {@link #loadSystemClasses()}
      * <li>Setup the default Server classes by calling <code>loadServerClasses()</code>
@@ -427,7 +439,7 @@
      * <li>Calls the {@link Configuration#preConfigure(WebAppContext)} method of all
      * Configuration instances.
      * </ul>
-     * @throws Exception
+     * @throws Exception if unable to pre configure
      */
     public void preConfigure() throws Exception
     {
@@ -527,25 +539,6 @@
     protected void doStop() throws Exception
     {
         super.doStop();
-
-        try
-        {
-            for (int i=_configurations.size();i-->0;)
-                _configurations.get(i).deconfigure(this);
-
-            if (_metadata != null)
-                _metadata.clear();
-            _metadata=new MetaData();
-
-        }
-        finally
-        {
-            if (_ownClassLoader)
-                setClassLoader(null);
-
-            setAvailable(true);
-            _unavailableException=null;
-        }
     }
 
     /* ------------------------------------------------------------ */
@@ -683,7 +676,7 @@
         if (_serverClasses == null)
             loadServerClasses();
 
-        _serverClasses.addPattern(classOrPackage);
+        _serverClasses.add(classOrPackage);
     }
 
     /* ------------------------------------------------------------ */
@@ -733,7 +726,7 @@
         if (_systemClasses == null)
             loadSystemClasses();
 
-        _systemClasses.addPattern(classOrPackage);
+        _systemClasses.add(classOrPackage);
     }
 
 
@@ -947,7 +940,22 @@
         }
         return super.toString();
     }
-
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        dumpBeans(out,indent,
+            Collections.singletonList(new ClassLoaderDump(getClassLoader())),
+            Collections.singletonList(new DumpableCollection("Systemclasses "+this,_systemClasses)),
+            Collections.singletonList(new DumpableCollection("Serverclasses "+this,_serverClasses)),
+            Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations)),
+            Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())),
+            Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())),
+            Collections.singletonList(new DumpableCollection("Initparams "+this,getInitParams().entrySet()))
+            );
+    }
+    
     /* ------------------------------------------------------------ */
     /**
      * @param configurations The configuration class names.  If setConfigurations is not called
@@ -1064,7 +1072,7 @@
     /* ------------------------------------------------------------ */
     /** Add EventListener
      * Convenience method that calls {@link #setEventListeners(EventListener[])}
-     * @param listener
+     * @param listener the listener to add
      */
     @Override
     public void addEventListener(EventListener listener)
@@ -1152,9 +1160,10 @@
      *
      * In certain circumstances you want may want to deny access of one webapp from another
      * when you may not fully trust the webapp.  Setting this white list will enable a
-     * check when a servlet called getContext(String), validating that the uriInPath
+     * check when a servlet called {@link org.eclipse.jetty.servlet.ServletContextHandler.Context#getContext(String)}, validating that the uriInPath
      * for the given webapp has been declaratively allows access to the context.
-     * @param contextWhiteList
+     * 
+     * @param contextWhiteList the whitelist of contexts for {@link org.eclipse.jetty.servlet.ServletContextHandler.Context#getContext(String)} 
      */
     public void setContextWhiteList(String[] contextWhiteList)
     {
@@ -1168,12 +1177,7 @@
      * Server classes/packages are classes used to implement the server and are hidden
      * from the context.  If the context needs to load these classes, it must have its
      * own copy of them in WEB-INF/lib or WEB-INF/classes.
-     * A class pattern is a string of one of the forms:<dl>
-     * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
-     * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
-     * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
-     * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
-     * </dl>
+     * A {@link ClasspathPattern} is used to match the server classes.
      * @param serverClasses The serverClasses to set.
      */
     public void setServerClasses(String[] serverClasses)
@@ -1188,12 +1192,7 @@
      * System classes/packages are classes provided by the JVM and that
      * cannot be replaced by classes of the same name from WEB-INF,
      * regardless of the value of {@link #setParentLoaderPriority(boolean)}.
-     * A class pattern is a string of one of the forms:<dl>
-     * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
-     * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
-     * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
-     * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
-     * </dl>
+     * A {@link ClasspathPattern} is used to match the system classes.
      * @param systemClasses The systemClasses to set.
      */
     public void setSystemClasses(String[] systemClasses)
@@ -1234,7 +1233,7 @@
      * webapp will be kept when the webapp stops. Otherwise,
      * it will be deleted.
      * 
-     * @param delete
+     * @param persist true to persist the temp directory on shutdown / exit of the webapp
      */
     public void setPersistTempDirectory(boolean persist)
     {
@@ -1242,7 +1241,7 @@
     }
     
     /**
-     * @return
+     * @return true if tmp directory will persist between startups of the webapp
      */
     public boolean isPersistTempDirectory()
     {
@@ -1341,6 +1340,37 @@
 
         startWebapp();
     }
+    
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    protected void stopContext() throws Exception
+    {
+        stopWebapp();
+        try
+        {
+            for (int i=_configurations.size();i-->0;)
+                _configurations.get(i).deconfigure(this);
+
+            if (_metadata != null)
+                _metadata.clear();
+            _metadata=new MetaData();
+
+        }
+        finally
+        {
+            if (_ownClassLoader)
+            {
+                ClassLoader loader = getClassLoader();
+                if (loader != null && loader instanceof URLClassLoader)
+                    ((URLClassLoader)loader).close(); 
+                setClassLoader(null);
+            }
+
+            setAvailable(true);
+            _unavailableException=null;
+        }
+    }
 
     /* ------------------------------------------------------------ */
     protected void startWebapp()
@@ -1349,6 +1379,11 @@
         super.startContext();
     }
     
+    /* ------------------------------------------------------------ */
+    protected void stopWebapp() throws Exception
+    {
+        super.stopContext();
+    }
     /* ------------------------------------------------------------ */    
     @Override
     public Set<String> setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement)
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
index d35fda1..64306fd 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
@@ -192,15 +192,17 @@
         //if we're not persisting the temp dir contents delete it
         if (!context.isPersistTempDirectory())
         {
-            IO.delete(context.getTempDirectory());
+           IO.delete(context.getTempDirectory());
         }
         
         //if it wasn't explicitly configured by the user, then unset it
-        Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
+       Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
         if (tmpdirConfigured != null && !tmpdirConfigured) 
             context.setTempDirectory(null);
 
         //reset the base resource back to what it was before we did any unpacking of resources
+        if (context.getBaseResource() != null)
+            context.getBaseResource().close();
         context.setBaseResource(_preUnpackBaseResource);
     }
 
@@ -227,8 +229,8 @@
      * Get a temporary directory in which to unpack the war etc etc.
      * The algorithm for determining this is to check these alternatives
      * in the order shown:
-     *
-     * <p>A. Try to use an explicit directory specifically for this webapp:</p>
+     * <p>
+     * A. Try to use an explicit directory specifically for this webapp:
      * <ol>
      * <li>
      * Iff an explicit directory is set for this webapp, use it. Set delete on
@@ -236,19 +238,21 @@
      * </li>
      * <li>
      * Iff javax.servlet.context.tempdir context attribute is set for
-     * this webapp && exists && writeable, then use it. Set delete on exit depends on
+     * this webapp &amp;&amp; exists &amp;&amp; writeable, then use it. Set delete on exit depends on
      * value of persistTempDirectory.
      * </li>
      * </ol>
      *
-     * <p>B. Create a directory based on global settings. The new directory
-     * will be called "Jetty-"+host+"-"+port+"__"+context+"-"+virtualhost+"-"+randomdigits+".dir"
-     * </p>
+     * <p>
+     * B. Create a directory based on global settings. The new directory
+     * will be called <code>"Jetty-"+host+"-"+port+"__"+context+"-"+virtualhost+"-"+randomdigits+".dir"</code>
      * <p>
      * If the user has specified the context attribute org.eclipse.jetty.webapp.basetempdir, the
      * directory specified by this attribute will be the parent of the temp dir created. Otherwise,
-     * the parent dir is $(java.io.tmpdir). Set delete on exit depends on value of persistTempDirectory. 
-     * </p>
+     * the parent dir is <code>${java.io.tmpdir}</code>. Set delete on exit depends on value of persistTempDirectory.
+     *  
+     * @param context the context to resolve the temp directory from
+     * @throws Exception if unable to resolve the temp directory
      */
     public void resolveTempDirectory (WebAppContext context)
     throws Exception
@@ -402,7 +406,7 @@
                 throw new IllegalStateException("No resourceBase or war set for context");
 
             // Accept aliases for WAR files
-            if (web_app.getAlias() != null)
+            if (web_app.isAlias())
             {
                 LOG.debug(web_app + " anti-aliased to " + web_app.getAlias());
                 web_app = context.newResource(web_app.getAlias());
@@ -546,18 +550,18 @@
         }
     }
 
-
-
-
     /**
      * Create a canonical name for a webapp temp directory.
+     * <p>
      * The form of the name is:
-     *  <code>"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"</code>
+     * 
+     * <pre>"jetty-"+host+"-"+port+"-"+resourceBase+"-_"+context+"-"+virtualhost+"-"+randomdigits+".dir"</pre>
      *
      *  host and port uniquely identify the server
      *  context and virtual host uniquely identify the webapp
      *  randomdigits ensure every tmp directory is unique
      *  
+     * @param context the context to get the canonical name from 
      * @return the canonical name for the webapp temp directory
      */
     public static String getCanonicalNameForWebAppTmpDir (WebAppContext context)
@@ -598,7 +602,6 @@
             }
         }
 
-
         //Resource  base
         try
         {
@@ -678,9 +681,9 @@
     /**
      * Look for jars that should be treated as if they are in WEB-INF/lib
      * 
-     * @param context
+     * @param context the context to find the jars in
      * @return the list of jar resources found within context
-     * @throws Exception
+     * @throws Exception if unable to find the jars
      */
     protected List<Resource> findJars (WebAppContext context)
     throws Exception
@@ -696,11 +699,11 @@
     }
     
     /**
-     *  Look for jars in WEB-INF/lib
+     * Look for jars in <code>WEB-INF/lib</code>
      *  
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the context to find the lib jars in
+     * @return the list of jars as {@link Resource}
+     * @throws Exception if unable to scan for lib jars
      */
     protected List<Resource> findWebInfLibJars(WebAppContext context)
     throws Exception
@@ -741,9 +744,9 @@
     /**
      * Get jars from WebAppContext.getExtraClasspath as resources
      * 
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the context to find extra classpath jars in
+     * @return the list of Resources with the extra classpath, or null if not found
+     * @throws Exception if unable to find the extra classpath jars
      */
     protected List<Resource>  findExtraClasspathJars(WebAppContext context)
     throws Exception
@@ -769,11 +772,11 @@
     }
     
     /**
-     * Get WEB-INF/classes dir
+     * Get <code>WEB-INF/classes</code> dir
      * 
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the context to look for the <code>WEB-INF/classes</code> directory
+     * @return the Resource for the <code>WEB-INF/classes</code> directory
+     * @throws Exception if unable to find the <code>WEB-INF/classes</code> directory
      */
     protected Resource findWebInfClassesDir (WebAppContext context)
     throws Exception
@@ -798,9 +801,9 @@
     /**
      * Get class dirs from WebAppContext.getExtraClasspath as resources
      * 
-     * @param context
-     * @return
-     * @throws Exception
+     * @param context the context to look for extra classpaths in
+     * @return the list of Resources to the extra classpath 
+     * @throws Exception if unable to find the extra classpaths
      */
     protected List<Resource>  findExtraClasspathDirs(WebAppContext context)
     throws Exception
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java
new file mode 100644
index 0000000..eb74b75
--- /dev/null
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java
@@ -0,0 +1,109 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.webapp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ClasspathPatternTest
+{
+    private final ClasspathPattern pattern = new ClasspathPattern();
+    
+    @Before
+    public void before()
+    {
+        pattern.clear();
+        pattern.add("org.package.");
+        pattern.add("-org.excluded.");
+        pattern.add("org.example.FooBar");
+        pattern.add("-org.example.Excluded");
+        pattern.addAll(Arrays.asList(new String[]{"-org.example.Nested$Minus","org.example.Nested","org.example.Nested$Something"}));
+    }
+    
+    @Test
+    public void testClassMatch()
+    {
+        assertTrue(pattern.match("org.example.FooBar"));
+        assertTrue(pattern.match("org.example.Nested"));
+        
+        assertFalse(pattern.match("org.example.Unknown"));
+        assertFalse(pattern.match("org.example.FooBar.Unknown"));
+    }
+    
+    @Test
+    public void testPackageMatch()
+    {
+        assertTrue(pattern.match("org.package.Something"));
+        assertTrue(pattern.match("org.package.other.Something"));
+        
+        assertFalse(pattern.match("org.example.Unknown"));
+        assertFalse(pattern.match("org.example.FooBar.Unknown"));
+        assertFalse(pattern.match("org.example.FooBarElse"));
+    }
+
+    @Test
+    public void testExplicitNestedMatch()
+    {
+        assertTrue(pattern.match("org.example.Nested$Something"));
+        
+        assertFalse(pattern.match("org.example.Nested$Minus"));
+    }
+
+    @Test
+    public void testImplicitNestedMatch()
+    {
+        assertTrue(pattern.match("org.example.FooBar$Other"));
+        assertTrue(pattern.match("org.example.Nested$Other"));
+    }
+    
+    @Test
+    public void testAddBefore()
+    {
+        pattern.addBefore("-org.excluded.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo");
+
+        assertTrue(pattern.match("org.excluded.ExceptionOne"));
+        assertTrue(pattern.match("org.excluded.ExceptionTwo"));
+        
+        assertFalse(pattern.match("org.example.Unknown"));
+    }
+    
+    @Test
+    public void testAddAfter()
+    {
+        pattern.addAfter("org.package.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo");
+
+        assertTrue(pattern.match("org.excluded.ExceptionOne"));
+        assertTrue(pattern.match("org.excluded.ExceptionTwo"));
+        
+        assertFalse(pattern.match("org.example.Unknown"));
+    }
+
+    @Test
+    public void testDoubledNested()
+    {
+        assertTrue(pattern.match("org.example.Nested$Something$Else"));
+        
+        assertFalse(pattern.match("org.example.Nested$Minus$Else"));
+    }
+}
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java
index 10fa55f..2f6b90e 100644
--- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/OrderingTest.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.webapp;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -37,8 +38,6 @@
 
 /**
  * OrderingTest
- *
- *
  */
 public class OrderingTest
 {
@@ -111,9 +110,6 @@
             return _name;
         }
         
-        /**
-         * @see org.eclipse.jetty.util.resource.Resource#getURL()
-         */
         @Override
         public URL getURL()
         {
@@ -510,6 +506,22 @@
     }
 
     @Test
+    public void testOrderFragments() throws Exception 
+    {
+        final MetaData metadata = new MetaData();
+        final Resource jarResource = new TestResource("A");
+
+        metadata.setOrdering(new Ordering.RelativeOrdering(metadata));
+        metadata.addWebInfJar(jarResource);
+        metadata.orderFragments();
+        assertEquals(1, metadata.getOrderedWebInfJars().size());
+        metadata.orderFragments();
+        assertEquals(1, metadata.getOrderedWebInfJars().size());
+    }
+
+
+
+    @Test
     public void testCircular1 ()
     throws Exception
     {
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java
index ed1c843..373c746 100644
--- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java
@@ -18,33 +18,45 @@
 
 package org.eclipse.jetty.webapp;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.eclipse.jetty.toolchain.test.ExtraMatchers.*; 
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
+import java.net.URI;
 import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
+import java.util.Collections;
 import java.util.List;
 
+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.util.resource.PathResource;
 import org.eclipse.jetty.util.resource.Resource;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class WebAppClassLoaderTest
 {
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    private Path testWebappDir;
     private WebAppContext _context;
     private WebAppClassLoader _loader;
 
     @Before
     public void init() throws Exception
     {
-        Resource webapp = Resource.newResource("./src/test/webapp");
+        this.testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp");
+        Resource webapp = new PathResource(testWebappDir);
+        
+        System.err.printf("testWebappDir = %s%n", testWebappDir);
 
         _context = new WebAppContext();
         _context.setBaseResource(webapp);
@@ -55,16 +67,39 @@
         _loader.addClassPath(webapp.addPath("WEB-INF/classes"));
         _loader.setName("test");
     }
+    
+    public void assertCanLoadClass(String clazz) throws ClassNotFoundException
+    {
+        assertThat("Can Load Class ["+clazz+"]", _loader.loadClass(clazz), notNullValue());
+    }
+    
+    public void assertCanLoadResource(String res) throws ClassNotFoundException
+    {
+        assertThat("Can Load Resource ["+res+"]", _loader.getResource(res), notNullValue());
+    }
+    
+    public void assertCantLoadClass(String clazz)
+    {
+        try
+        {
+            assertThat("Can't Load Class ["+clazz+"]", _loader.loadClass(clazz), nullValue());
+        }
+        catch (ClassNotFoundException e)
+        {
+            // Valid path
+        }
+    }
 
     @Test
     public void testParentLoad() throws Exception
     {
         _context.setParentLoaderPriority(true);
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarB"));
-        assertTrue(canLoadClass("org.acme.other.ClassInClassesC"));
+        
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
+        assertCanLoadClass("org.acme.webapp.ClassInJarB");
+        assertCanLoadClass("org.acme.other.ClassInClassesC");
 
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration"));
+        assertCantLoadClass("org.eclipse.jetty.webapp.Configuration");
 
         Class<?> clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA");
         assertTrue(clazzA.getField("FROM_PARENT")!=null);
@@ -74,22 +109,15 @@
     public void testWebAppLoad() throws Exception
     {
         _context.setParentLoaderPriority(false);
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarB"));
-        assertTrue(canLoadClass("org.acme.other.ClassInClassesC"));
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
+        assertCanLoadClass("org.acme.webapp.ClassInJarB");
+        assertCanLoadClass("org.acme.other.ClassInClassesC");
 
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration"));
+        assertCantLoadClass("org.eclipse.jetty.webapp.Configuration");
 
         Class<?> clazzA = _loader.loadClass("org.acme.webapp.ClassInJarA");
-        try
-        {
-            clazzA.getField("FROM_PARENT");
-            assertTrue(false);
-        }
-        catch(NoSuchFieldException e)
-        {
-            assertTrue(true);
-        }
+        expectedException.expect(NoSuchFieldException.class);
+        clazzA.getField("FROM_PARENT");
     }
     
     @Test
@@ -123,20 +151,20 @@
         });
         
         _context.setParentLoaderPriority(false);
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarB"));
-        assertTrue(canLoadClass("org.acme.other.ClassInClassesC"));
-        assertTrue(canLoadClass("java.lang.String"));
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration"));
         
-        Iterator<Object> iter = results.iterator();
-        assertEquals(_loader,iter.next());
-        assertEquals("org.acme.webapp.ClassInJarA",iter.next());
-        assertEquals(_loader,iter.next());
-        assertEquals("org.acme.webapp.ClassInJarB",iter.next());
-        assertEquals(_loader,iter.next());
-        assertEquals("org.acme.other.ClassInClassesC",iter.next());
-        assertFalse(iter.hasNext());
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
+        assertCanLoadClass("org.acme.webapp.ClassInJarB");
+        assertCanLoadClass("org.acme.other.ClassInClassesC");
+        assertCanLoadClass("java.lang.String");
+        assertCantLoadClass("org.eclipse.jetty.webapp.Configuration");
+        
+        assertThat("Classname Results", results, contains(
+                _loader,
+                "org.acme.webapp.ClassInJarA",
+                _loader,
+                "org.acme.webapp.ClassInJarB",
+                _loader,
+                "org.acme.other.ClassInClassesC"));
     }
     
     @Test
@@ -151,8 +179,7 @@
             }
         });
         
-        
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
     }
 
     @Test
@@ -164,12 +191,12 @@
         System.arraycopy(oldSC,0,newSC,1,oldSC.length);
         _context.setServerClasses(newSC);
 
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarB"));
-        assertTrue(canLoadClass("org.acme.other.ClassInClassesC"));
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
+        assertCanLoadClass("org.acme.webapp.ClassInJarB");
+        assertCanLoadClass("org.acme.other.ClassInClassesC");
 
-        assertTrue(canLoadClass("org.eclipse.jetty.webapp.Configuration"));
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner"));
+        assertCanLoadClass("org.eclipse.jetty.webapp.Configuration");
+        assertCantLoadClass("org.eclipse.jetty.webapp.JarScanner");
     }
 
     @Test
@@ -187,11 +214,11 @@
         System.arraycopy(oldSysC,0,newSysC,1,oldSysC.length);
         _context.setSystemClasses(newSysC);
 
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarA"));
-        assertTrue(canLoadClass("org.acme.webapp.ClassInJarB"));
-        assertTrue(canLoadClass("org.acme.other.ClassInClassesC"));
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.Configuration"));
-        assertTrue(cantLoadClass("org.eclipse.jetty.webapp.JarScanner"));
+        assertCanLoadClass("org.acme.webapp.ClassInJarA");
+        assertCanLoadClass("org.acme.webapp.ClassInJarB");
+        assertCanLoadClass("org.acme.other.ClassInClassesC");
+        assertCantLoadClass("org.eclipse.jetty.webapp.Configuration");
+        assertCantLoadClass("org.eclipse.jetty.webapp.JarScanner");
 
         oldSysC=_context.getSystemClasses();
         newSysC=new String[oldSysC.length+1];
@@ -199,7 +226,7 @@
         System.arraycopy(oldSysC,0,newSysC,1,oldSysC.length);
         _context.setSystemClasses(newSysC);
 
-        assertNotNull(_loader.getResource("org/acme/webapp/ClassInJarA.class"));
+        assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
         _context.setSystemClasses(oldSysC);
 
         oldServC=_context.getServerClasses();
@@ -207,27 +234,54 @@
         newServC[0]="org.acme.webapp.ClassInJarA";
         System.arraycopy(oldServC,0,newServC,1,oldServC.length);
         _context.setServerClasses(newServC);
-        assertNotNull(_loader.getResource("org/acme/webapp/ClassInJarA.class"));
+        assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
     }
 
     @Test
     public void testResources() throws Exception
     {
+        List<URL> expected = new ArrayList<>();
         List<URL> resources;
+        
+        // Expected Locations
+        URL webappWebInfLibAcme = new URI("jar:" + testWebappDir.resolve("WEB-INF/lib/acme.jar").toUri().toASCIIString() + "!/org/acme/resource.txt").toURL();
+        URL webappWebInfClasses = testWebappDir.resolve("WEB-INF/classes/org/acme/resource.txt").toUri().toURL();
+        // (from parent classloader)
+        URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt");
 
         _context.setParentLoaderPriority(false);
-        resources =toList( _loader.getResources("org/acme/resource.txt"));
-        assertEquals(3,resources.size());
-        assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
-        assertEquals(-1,resources.get(1).toString().indexOf("test-classes"));
-        assertEquals(0,resources.get(2).toString().indexOf("file:"));
+        dump(_context);
+        resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
+        
+        expected.clear();
+        expected.add(webappWebInfLibAcme);
+        expected.add(webappWebInfClasses);
+        expected.add(targetTestClasses);
+        
+        assertThat("Resources Found (Parent Loader Priority == false)",resources,ordered(expected));
+        
+//        dump(resources);
+//        assertEquals(3,resources.size());
+//        assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
+//        assertEquals(-1,resources.get(1).toString().indexOf("test-classes"));
+//        assertEquals(0,resources.get(2).toString().indexOf("file:"));
 
         _context.setParentLoaderPriority(true);
-        resources =toList( _loader.getResources("org/acme/resource.txt"));
-        assertEquals(3,resources.size());
-        assertEquals(0,resources.get(0).toString().indexOf("file:"));
-        assertEquals(0,resources.get(1).toString().indexOf("jar:file:"));
-        assertEquals(-1,resources.get(2).toString().indexOf("test-classes"));
+        // dump(_context);
+        resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
+        
+        expected.clear();
+        expected.add(targetTestClasses);
+        expected.add(webappWebInfLibAcme);
+        expected.add(webappWebInfClasses);
+        
+        assertThat("Resources Found (Parent Loader Priority == true)",resources,ordered(expected));
+        
+//        dump(resources);
+//        assertEquals(3,resources.size());
+//        assertEquals(0,resources.get(0).toString().indexOf("file:"));
+//        assertEquals(0,resources.get(1).toString().indexOf("jar:file:"));
+//        assertEquals(-1,resources.get(2).toString().indexOf("test-classes"));
 
         String[] oldServC=_context.getServerClasses();
         String[] newServC=new String[oldServC.length+1];
@@ -236,10 +290,19 @@
         _context.setServerClasses(newServC);
 
         _context.setParentLoaderPriority(true);
-        resources =toList( _loader.getResources("org/acme/resource.txt"));
-        assertEquals(2,resources.size());
-        assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
-        assertEquals(0,resources.get(1).toString().indexOf("file:"));
+        // dump(_context);
+        resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
+        
+        expected.clear();
+        expected.add(webappWebInfLibAcme);
+        expected.add(webappWebInfClasses);
+        
+        assertThat("Resources Found (Parent Loader Priority == true) (with serverClasses filtering)",resources,ordered(expected));
+        
+//        dump(resources);
+//        assertEquals(2,resources.size());
+//        assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
+//        assertEquals(0,resources.get(1).toString().indexOf("file:"));
 
         _context.setServerClasses(oldServC);
         String[] oldSysC=_context.getSystemClasses();
@@ -249,33 +312,57 @@
         _context.setSystemClasses(newSysC);
 
         _context.setParentLoaderPriority(true);
-        resources =toList( _loader.getResources("org/acme/resource.txt"));
-        assertEquals(1,resources.size());
-        assertEquals(0,resources.get(0).toString().indexOf("file:"));
+        // dump(_context);
+        resources =Collections.list(_loader.getResources("org/acme/resource.txt"));
+        
+        expected.clear();
+        expected.add(targetTestClasses);
+        
+        assertThat("Resources Found (Parent Loader Priority == true) (with systemClasses filtering)",resources,ordered(expected));
+        
+//        dump(resources);
+//        assertEquals(1,resources.size());
+//        assertEquals(0,resources.get(0).toString().indexOf("file:"));
     }
 
-    private List<URL> toList(Enumeration<URL> e)
+    private void dump(WebAppContext wac)
     {
-        List<URL> list = new ArrayList<URL>();
-        while (e!=null && e.hasMoreElements())
-            list.add(e.nextElement());
-        return list;
+        System.err.println("--Dump WebAppContext - " + wac);
+        System.err.printf("  context.getClass().getClassLoader() = %s%n",wac.getClass().getClassLoader());
+        dumpClassLoaderHierarchy("  ",wac.getClass().getClassLoader());
+        System.err.printf("  context.getClassLoader() = %s%n",wac.getClassLoader());
+        dumpClassLoaderHierarchy("  ",wac.getClassLoader());
     }
 
-    private boolean canLoadClass(String clazz) throws ClassNotFoundException
+    private void dumpClassLoaderHierarchy(String indent, ClassLoader classLoader)
     {
-        return _loader.loadClass(clazz)!=null;
-    }
-
-    private boolean cantLoadClass(String clazz)
-    {
-        try
+        if (classLoader != null)
         {
-            return _loader.loadClass(clazz)==null;
+            if(classLoader instanceof URLClassLoader)
+            {
+                URLClassLoader urlCL = (URLClassLoader)classLoader;
+                URL urls[] = urlCL.getURLs();
+                for (URL url : urls)
+                {
+                    System.err.printf("%s url[] = %s%n",indent,url);
+                }
+            }
+            
+            ClassLoader parent = classLoader.getParent();
+            if (parent != null)
+            {
+                System.err.printf("%s .parent = %s%n",indent,parent);
+                dumpClassLoaderHierarchy(indent + "  ",parent);
+            }
         }
-        catch(ClassNotFoundException e)
+    }
+
+    private void dump(List<URL> resources)
+    {
+        System.err.println("--Dump--");
+        for(URL url: resources)
         {
-            return true;
+            System.err.printf(" \"%s\"%n",url);
         }
     }
 }
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
index eaa831a..391aaad 100644
--- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.webapp;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -32,8 +33,6 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
-import junit.framework.Assert;
-
 import org.eclipse.jetty.server.LocalConnector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
@@ -41,6 +40,7 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.resource.Resource;
 import org.eclipse.jetty.util.resource.ResourceCollection;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class WebAppContextTest
@@ -51,7 +51,7 @@
         Server server = new Server();
         //test if no classnames set, its the defaults
         WebAppContext wac = new WebAppContext();
-        Assert.assertEquals(0,wac.getConfigurations().length);
+        assertEquals(0,wac.getConfigurations().length);
         String[] classNames = wac.getConfigurationClasses();
         assertNotNull(classNames);
 
@@ -123,7 +123,7 @@
     /**
      * tests that the servlet context white list works
      *
-     * @throws Exception
+     * @throws Exception on test failure
      */
     @Test
     public void testContextWhiteList() throws Exception
diff --git a/jetty-webapp/src/test/resources/jetty-logging.properties b/jetty-webapp/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..4c4c7f8
--- /dev/null
+++ b/jetty-webapp/src/test/resources/jetty-logging.properties
@@ -0,0 +1,6 @@
+# Setup default logging implementation for during testing
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.LEVEL=INFO
+# org.eclipse.jetty.webapp.WebAppClassLoader.LEVEL=DEBUG
+# org.eclipse.jetty.util.LEVEL=DEBUG
+# org.eclipse.jetty.util.PathWatcher.Noisy.LEVEL=OFF
diff --git a/jetty-websocket/javax-websocket-client-impl/pom.xml b/jetty-websocket/javax-websocket-client-impl/pom.xml
index dc4763b..ee1e1ce 100644
--- a/jetty-websocket/javax-websocket-client-impl/pom.xml
+++ b/jetty-websocket/javax-websocket-client-impl/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty.websocket</groupId>
     <artifactId>websocket-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
 
   <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java
index ec80cba..8eb2364 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.concurrent.Future;
+
 import javax.websocket.EncodeException;
 import javax.websocket.Encoder;
 import javax.websocket.RemoteEndpoint;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
index 9e939d9..13c30b7 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
@@ -30,6 +30,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Future;
+
 import javax.websocket.ClientEndpoint;
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.DeploymentException;
@@ -39,18 +40,24 @@
 import javax.websocket.Session;
 import javax.websocket.WebSocketContainer;
 
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.ShutdownThread;
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.WebSocketClient;
 import org.eclipse.jetty.websocket.client.io.UpgradeListener;
+import org.eclipse.jetty.websocket.common.SessionFactory;
 import org.eclipse.jetty.websocket.common.SessionListener;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
 import org.eclipse.jetty.websocket.jsr356.client.AnnotatedClientEndpointMetadata;
 import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
@@ -66,10 +73,12 @@
  * <p>
  * This should be specific to a JVM if run in a standalone mode. or specific to a WebAppContext if running on the Jetty server.
  */
-public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, SessionListener
+public class ClientContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketContainerScope, SessionListener
 {
     private static final Logger LOG = Log.getLogger(ClientContainer.class);
     
+    /** The delegated Container Scope */
+    private final WebSocketContainerScope scopeDelegate;
     /** Tracking all primitive decoders for the container */
     private final DecoderFactory decoderFactory;
     /** Tracking all primitive encoders for the container */
@@ -85,30 +94,28 @@
     public ClientContainer()
     {
         // This constructor is used with Standalone JSR Client usage.
-        this(null);
+        this(new SimpleContainerScope(WebSocketPolicy.newClientPolicy()));
         client.setDaemon(true);
     }
     
-    public ClientContainer(Executor executor)
+    public ClientContainer(WebSocketContainerScope scope)
     {
-        endpointClientMetadataCache = new ConcurrentHashMap<>();
-        decoderFactory = new DecoderFactory(PrimitiveDecoderMetadataSet.INSTANCE);
-        encoderFactory = new EncoderFactory(PrimitiveEncoderMetadataSet.INSTANCE);
-
-        EmptyClientEndpointConfig empty = new EmptyClientEndpointConfig();
-        decoderFactory.init(empty);
-        encoderFactory.init(empty);
-
         boolean trustAll = Boolean.getBoolean("org.eclipse.jetty.websocket.jsr356.ssl-trust-all");
         
-        client = new WebSocketClient(new SslContextFactory(trustAll), executor);
+        this.scopeDelegate = scope;
+        client = new WebSocketClient(scope, new SslContextFactory(trustAll));
         client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
-        client.setSessionFactory(new JsrSessionFactory(this,this,client));
+        SessionFactory sessionFactory = new JsrSessionFactory(this,this,client);
+        client.setSessionFactory(sessionFactory);
         addBean(client);
 
+        this.endpointClientMetadataCache = new ConcurrentHashMap<>();
+        this.decoderFactory = new DecoderFactory(this,PrimitiveDecoderMetadataSet.INSTANCE);
+        this.encoderFactory = new EncoderFactory(this,PrimitiveEncoderMetadataSet.INSTANCE);
+
         ShutdownThread.register(this);
     }
-
+    
     private Session connect(EndpointInstance instance, URI path) throws IOException
     {
         Objects.requireNonNull(instance,"EndpointInstance cannot be null");
@@ -186,7 +193,18 @@
         EndpointInstance instance = newClientEndpointInstance(endpoint,null);
         return connect(instance,path);
     }
-
+    
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+        
+        // Initialize the default decoder / encoder factories
+        EmptyClientEndpointConfig empty = new EmptyClientEndpointConfig();
+        this.decoderFactory.init(empty);
+        this.encoderFactory.init(empty);
+    }
+    
     @Override
     protected void doStop() throws Exception
     {
@@ -195,6 +213,12 @@
         super.doStop();
     }
 
+    @Override
+    public ByteBufferPool getBufferPool()
+    {
+        return scopeDelegate.getBufferPool();
+    }
+
     public WebSocketClient getClient()
     {
         return client;
@@ -279,6 +303,12 @@
     }
 
     @Override
+    public Executor getExecutor()
+    {
+        return scopeDelegate.getExecutor();
+    }
+
+    @Override
     public Set<Extension> getInstalledExtensions()
     {
         Set<Extension> ret = new HashSet<>();
@@ -292,14 +322,33 @@
         return ret;
     }
 
+    @Override
+    public DecoratedObjectFactory getObjectFactory()
+    {
+        return scopeDelegate.getObjectFactory();
+    }
+
     /**
      * Used in {@link Session#getOpenSessions()}
+     * @return the set of open sessions
      */
     public Set<Session> getOpenSessions()
     {
         return Collections.unmodifiableSet(this.openSessions);
     }
 
+    @Override
+    public WebSocketPolicy getPolicy()
+    {
+        return scopeDelegate.getPolicy();
+    }
+    
+    @Override
+    public SslContextFactory getSslContextFactory()
+    {
+        return scopeDelegate.getSslContextFactory();
+    }
+
     private EndpointInstance newClientEndpointInstance(Class<?> endpointClass, ClientEndpointConfig config)
     {
         try
@@ -357,7 +406,7 @@
                     Session.class.getName());
         }
     }
-
+    
     @Override
     public void setAsyncSendTimeout(long ms)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/DecoderFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/DecoderFactory.java
index 51ed86e..38f7a7f 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/DecoderFactory.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/DecoderFactory.java
@@ -19,12 +19,16 @@
 package org.eclipse.jetty.websocket.jsr356;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
+
 import javax.websocket.Decoder;
 import javax.websocket.EndpointConfig;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope;
 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadataSet;
 
@@ -71,18 +75,26 @@
     private static final Logger LOG = Log.getLogger(DecoderFactory.class);
 
     private final DecoderMetadataSet metadatas;
+    private final WebSocketContainerScope containerScope;
     private DecoderFactory parentFactory;
     private Map<Class<?>, Wrapper> activeWrappers;
 
-    public DecoderFactory(DecoderMetadataSet metadatas)
+    public DecoderFactory(WebSocketContainerScope containerScope, DecoderMetadataSet metadatas)
     {
-        this.metadatas = metadatas;
-        this.activeWrappers = new ConcurrentHashMap<>();
+        this(containerScope,metadatas,null);
+    }
+    
+    public DecoderFactory(WebSocketSessionScope sessionScope, DecoderMetadataSet metadatas, DecoderFactory parentFactory)
+    {
+        this(sessionScope.getContainerScope(),metadatas,parentFactory);
     }
 
-    public DecoderFactory(DecoderMetadataSet metadatas, DecoderFactory parentFactory)
+    protected DecoderFactory(WebSocketContainerScope containerScope, DecoderMetadataSet metadatas, DecoderFactory parentFactory)
     {
-        this(metadatas);
+        Objects.requireNonNull(containerScope,"Container Scope cannot be null");
+        this.containerScope = containerScope;
+        this.metadatas = metadatas;
+        this.activeWrappers = new ConcurrentHashMap<>();
         this.parentFactory = parentFactory;
     }
 
@@ -102,6 +114,7 @@
         {
             LOG.debug("getMetadataFor({})",type);
         }
+        
         DecoderMetadata metadata = metadatas.getMetadataByType(type);
 
         if (metadata != null)
@@ -172,7 +185,7 @@
         Class<? extends Decoder> decoderClass = metadata.getCoderClass();
         try
         {
-            Decoder decoder = decoderClass.newInstance();
+            Decoder decoder = containerScope.getObjectFactory().createInstance(decoderClass);
             return new Wrapper(decoder,metadata);
         }
         catch (InstantiationException | IllegalAccessException e)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/EncoderFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/EncoderFactory.java
index aab32c3..85b2903 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/EncoderFactory.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/EncoderFactory.java
@@ -19,12 +19,16 @@
 package org.eclipse.jetty.websocket.jsr356;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
+
 import javax.websocket.Encoder;
 import javax.websocket.EndpointConfig;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope;
 import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadata;
 import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadataSet;
 
@@ -64,18 +68,26 @@
     private static final Logger LOG = Log.getLogger(EncoderFactory.class);
 
     private final EncoderMetadataSet metadatas;
+    private final WebSocketContainerScope containerScope;
     private EncoderFactory parentFactory;
     private Map<Class<?>, Wrapper> activeWrappers;
 
-    public EncoderFactory(EncoderMetadataSet metadatas)
+    public EncoderFactory(WebSocketContainerScope containerScope, EncoderMetadataSet metadatas)
     {
-        this.metadatas = metadatas;
-        this.activeWrappers = new ConcurrentHashMap<>();
+        this(containerScope,metadatas,null);
     }
 
-    public EncoderFactory(EncoderMetadataSet metadatas, EncoderFactory parentFactory)
+    public EncoderFactory(WebSocketSessionScope sessionScope, EncoderMetadataSet metadatas, EncoderFactory parentFactory)
     {
-        this(metadatas);
+        this(sessionScope.getContainerScope(),metadatas,parentFactory);
+    }
+
+    protected EncoderFactory(WebSocketContainerScope containerScope, EncoderMetadataSet metadatas, EncoderFactory parentFactory)
+    {
+        Objects.requireNonNull(containerScope,"Container Scope cannot be null");
+        this.containerScope = containerScope;
+        this.metadatas = metadatas;
+        this.activeWrappers = new ConcurrentHashMap<>();
         this.parentFactory = parentFactory;
     }
 
@@ -166,7 +178,7 @@
         Class<? extends Encoder> encoderClass = metadata.getCoderClass();
         try
         {
-            Encoder encoder = encoderClass.newInstance();
+            Encoder encoder = containerScope.getObjectFactory().createInstance(encoderClass);
             return new Wrapper(encoder,metadata);
         }
         catch (InstantiationException | IllegalAccessException e)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JettyClientContainerProvider.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JettyClientContainerProvider.java
index c854aec..a451d27 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JettyClientContainerProvider.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JettyClientContainerProvider.java
@@ -22,16 +22,24 @@
 import javax.websocket.WebSocketContainer;
 
 /**
- * Client {@link ContainerProvider} implementation
+ * Client {@link ContainerProvider} implementation.
+ * <p>
+ * Created by a {@link java.util.ServiceLoader} call in the
+ * {@link javax.websocket.ContainerProvider#getWebSocketContainer()} call.
  */
 public class JettyClientContainerProvider extends ContainerProvider
 {
+    /**
+     * Used by {@link ContainerProvider#getWebSocketContainer()} to get a new instance
+     * of the Client {@link WebSocketContainer}.
+     */
     @Override
     protected WebSocketContainer getContainer()
     {
         ClientContainer container = new ClientContainer();
         try
         {
+            // We need to start this container properly.
             container.start();
             return container;
         }
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
index 39d5020..ad5e008 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrExtension.java
@@ -58,6 +58,7 @@
 
     /**
      * A configured extension
+     * @param cfg the configuration for the extension 
      */
     public JsrExtension(ExtensionConfig cfg)
     {
@@ -73,6 +74,7 @@
 
     /**
      * A potential (unconfigured) extension
+     * @param name the name of the extension
      */
     public JsrExtension(String name)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
index 5ad0c5c..bb44774 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java
@@ -29,6 +29,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+
 import javax.websocket.CloseReason;
 import javax.websocket.EndpointConfig;
 import javax.websocket.Extension;
@@ -73,9 +74,9 @@
     private JsrAsyncRemote asyncRemote;
     private JsrBasicRemote basicRemote;
 
-    public JsrSession(URI requestURI, EventDriver websocket, LogicalConnection connection, ClientContainer container, String id, SessionListener... sessionListeners)
+    public JsrSession(ClientContainer container, String id, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
     {
-        super(requestURI, websocket, connection, sessionListeners);
+        super(container, requestURI, websocket, connection, sessionListeners);
         if (!(websocket instanceof AbstractJsrEventDriver))
         {
             throw new IllegalArgumentException("Cannot use, not a JSR WebSocket: " + websocket);
@@ -85,8 +86,8 @@
         this.metadata = jsr.getMetadata();
         this.container = container;
         this.id = id;
-        this.decoderFactory = new DecoderFactory(metadata.getDecoders(),container.getDecoderFactory());
-        this.encoderFactory = new EncoderFactory(metadata.getEncoders(),container.getEncoderFactory());
+        this.decoderFactory = new DecoderFactory(this,metadata.getDecoders(),container.getDecoderFactory());
+        this.encoderFactory = new EncoderFactory(this,metadata.getEncoders(),container.getEncoderFactory());
         this.messageHandlerFactory = new MessageHandlerFactory();
         this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
         this.messageHandlerSet = new HashSet<>();
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
index 6e9bd21..f17734d 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSessionFactory.java
@@ -43,7 +43,7 @@
     @Override
     public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
-        return new JsrSession(requestURI,websocket,connection,container,getNextId(),listeners);
+        return new JsrSession(container,getNextId(),requestURI,websocket,connection,listeners);
     }
 
     public String getNextId()
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrUpgradeListener.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrUpgradeListener.java
index 60f1c52..3e74341 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrUpgradeListener.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrUpgradeListener.java
@@ -21,6 +21,7 @@
 import java.net.HttpCookie;
 import java.util.List;
 import java.util.Map;
+
 import javax.websocket.ClientEndpointConfig.Configurator;
 
 import org.eclipse.jetty.websocket.api.UpgradeRequest;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactory.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactory.java
index f6c9b46..08ba2e1 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactory.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactory.java
@@ -22,6 +22,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+
 import javax.websocket.MessageHandler;
 
 import org.eclipse.jetty.util.log.Log;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerWrapper.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerWrapper.java
index 20922a5..a836616 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerWrapper.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerWrapper.java
@@ -19,6 +19,8 @@
 package org.eclipse.jetty.websocket.jsr356;
 
 import javax.websocket.MessageHandler;
+import javax.websocket.MessageHandler.Partial;
+import javax.websocket.MessageHandler.Whole;
 
 import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
 
@@ -71,7 +73,7 @@
     }
 
     /**
-     * Flag for a onMessage() method that wants MessageHandler.{@link Whole} with a Decoder that is based on {@link TextStream} or {@link BinaryStream}
+     * Flag for a onMessage() method that wants MessageHandler.{@link Whole} with a Decoder that is based on {@link javax.websocket.Decoder.TextStream} or {@link javax.websocket.Decoder.BinaryStream}
      * 
      * @return true for Streaming based Decoder, false for normal decoder for whole messages.
      */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointMetadata.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointMetadata.java
index 0aa3eee..c26690c 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointMetadata.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointMetadata.java
@@ -22,6 +22,10 @@
 import java.util.LinkedList;
 
 import javax.websocket.EndpointConfig;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
 
 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadataSet;
@@ -33,6 +37,8 @@
  * 
  * @param <T>
  *            the annotation this metadata is based off of
+ * @param <C>
+ *            the endpoint configuration this is based off of
  */
 public abstract class AnnotatedEndpointMetadata<T extends Annotation, C extends EndpointConfig> implements EndpointMetadata
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointScanner.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointScanner.java
index 2e2a32a..4686cc4 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointScanner.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/AnnotatedEndpointScanner.java
@@ -22,6 +22,7 @@
 import java.lang.reflect.Method;
 import java.util.LinkedList;
 import java.util.List;
+
 import javax.websocket.EndpointConfig;
 import javax.websocket.OnClose;
 import javax.websocket.OnError;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrMethod.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrMethod.java
index 23edf8a..5a325c9 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrMethod.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/IJsrMethod.java
@@ -21,6 +21,7 @@
 import java.lang.reflect.Method;
 
 import javax.websocket.Decoder;
+import javax.websocket.OnMessage;
 
 import org.eclipse.jetty.websocket.jsr356.MessageType;
 
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java
index 8b727b0..eb46a0b 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java
@@ -57,6 +57,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the JsrCallable to copy from 
      */
     public JsrCallable(JsrCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrEvents.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrEvents.java
index 15d5ccd..827cac2 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrEvents.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrEvents.java
@@ -24,9 +24,14 @@
 import java.lang.annotation.Annotation;
 import java.nio.ByteBuffer;
 import java.util.Map;
+
 import javax.websocket.CloseReason;
 import javax.websocket.DecodeException;
 import javax.websocket.EndpointConfig;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
 import javax.websocket.RemoteEndpoint;
 
 import org.eclipse.jetty.util.log.Log;
@@ -35,6 +40,8 @@
 
 /**
  * The live event methods found for a specific Annotated Endpoint
+ * @param <T> the annotation type
+ * @param <C> the endpoint config type
  */
 public class JsrEvents<T extends Annotation, C extends EndpointConfig>
 {
@@ -148,6 +155,7 @@
     {
         if (onError == null)
         {
+            LOG.warn("Unable to report throwable to websocket (no @OnError handler declared): " + websocket.getClass().getName(), cause);
             return;
         }
         onError.call(websocket,cause);
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdBinary.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdBinary.java
index 71976e4..7f264a2 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdBinary.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdBinary.java
@@ -21,6 +21,8 @@
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 
+import javax.websocket.OnMessage;
+
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
 import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoder.java
index c147abc..0690d21 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdDecoder.java
@@ -18,12 +18,14 @@
 
 package org.eclipse.jetty.websocket.jsr356.annotations;
 
+import javax.websocket.OnMessage;
+
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
 import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
 
 /**
- * Param handling for Text or Binary &#064;{@link OnMessage} parameters declared as {@link Decoder}s
+ * Param handling for Text or Binary &#064;{@link OnMessage} parameters declared as {@link javax.websocket.Decoder}s
  */
 public class JsrParamIdDecoder extends JsrParamIdOnMessage implements IJsrParamId
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnClose.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnClose.java
index 295f454..77a1562 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnClose.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnClose.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.websocket.jsr356.annotations;
 
 import javax.websocket.CloseReason;
+import javax.websocket.OnClose;
 
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnError.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnError.java
index 8392cf0..98b5d52 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnError.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnError.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356.annotations;
 
+import javax.websocket.OnError;
+
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
 
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnOpen.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnOpen.java
index 01f18c6..ea1f10b 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnOpen.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdOnOpen.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.websocket.jsr356.annotations;
 
 import javax.websocket.EndpointConfig;
+import javax.websocket.OnOpen;
 
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdText.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdText.java
index 7fe3600..1d2191a 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdText.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrParamIdText.java
@@ -20,6 +20,8 @@
 
 import java.io.Reader;
 
+import javax.websocket.OnMessage;
+
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
 import org.eclipse.jetty.websocket.jsr356.decoders.BooleanDecoder;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnCloseCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnCloseCallable.java
index 00f8ae0..df38f4c 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnCloseCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnCloseCallable.java
@@ -23,6 +23,7 @@
 import javax.websocket.CloseReason;
 import javax.websocket.CloseReason.CloseCodes;
 import javax.websocket.Decoder;
+import javax.websocket.OnClose;
 
 import org.eclipse.jetty.websocket.common.CloseInfo;
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnErrorCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnErrorCallable.java
index b8adf6c..00e4699 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnErrorCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnErrorCallable.java
@@ -21,6 +21,7 @@
 import java.lang.reflect.Method;
 
 import javax.websocket.Decoder;
+import javax.websocket.OnError;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java
index a93386a..ea15cdd 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryCallable.java
@@ -23,6 +23,7 @@
 
 import javax.websocket.DecodeException;
 import javax.websocket.Decoder;
+import javax.websocket.OnMessage;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
@@ -30,9 +31,9 @@
 /**
  * Callable for {@link OnMessage} annotated methods with a whole or partial binary messages.
  * <p>
- * Not for use with {@link InputStream} based {@link OnMessage} method objects.
+ * Not for use with {@link java.io.InputStream} based {@link OnMessage} method objects.
  * 
- * @see Binary
+ * @see javax.websocket.Decoder.Binary
  */
 public class OnMessageBinaryCallable extends OnMessageCallable
 {
@@ -45,6 +46,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the callable to copy
      */
     public OnMessageBinaryCallable(OnMessageCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryStreamCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryStreamCallable.java
index 8c28ebc..aca1847 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryStreamCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageBinaryStreamCallable.java
@@ -25,6 +25,7 @@
 
 import javax.websocket.DecodeException;
 import javax.websocket.Decoder;
+import javax.websocket.OnMessage;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
@@ -32,7 +33,7 @@
 /**
  * Callable for {@link OnMessage} annotated methods for {@link InputStream} based binary message objects
  * 
- * @see BinaryStream
+ * @see javax.websocket.Decoder.BinaryStream
  */
 public class OnMessageBinaryStreamCallable extends OnMessageCallable
 {
@@ -45,6 +46,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the callable to copy from
      */
     public OnMessageBinaryStreamCallable(OnMessageCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessagePongCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessagePongCallable.java
index c6583a8..c750572 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessagePongCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessagePongCallable.java
@@ -21,6 +21,9 @@
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 
+import javax.websocket.OnMessage;
+import javax.websocket.PongMessage;
+
 import org.eclipse.jetty.websocket.jsr356.JsrPongMessage;
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
@@ -37,6 +40,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the callable to copy from
      */
     public OnMessagePongCallable(OnMessageCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java
index 865d48d..fccf8ff 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextCallable.java
@@ -18,10 +18,12 @@
 
 package org.eclipse.jetty.websocket.jsr356.annotations;
 
+import java.io.Reader;
 import java.lang.reflect.Method;
 
 import javax.websocket.DecodeException;
 import javax.websocket.Decoder;
+import javax.websocket.OnMessage;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
@@ -31,7 +33,7 @@
  * <p>
  * Not for use with {@link Reader} based {@link OnMessage} method objects.
  * 
- * @see Text
+ * @see javax.websocket.Decoder.Text
  */
 public class OnMessageTextCallable extends OnMessageCallable
 {
@@ -44,6 +46,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the callable to copy from
      */
     public OnMessageTextCallable(OnMessageCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextStreamCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextStreamCallable.java
index 2192ced..067795e 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextStreamCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnMessageTextStreamCallable.java
@@ -24,6 +24,7 @@
 
 import javax.websocket.DecodeException;
 import javax.websocket.Decoder;
+import javax.websocket.OnMessage;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
@@ -31,7 +32,7 @@
 /**
  * Callable for {@link OnMessage} annotated methods for {@link Reader} based text message objects
  * 
- * @see TextStream
+ * @see javax.websocket.Decoder.TextStream
  */
 public class OnMessageTextStreamCallable extends OnMessageCallable
 {
@@ -44,6 +45,7 @@
 
     /**
      * Copy Constructor
+     * @param copy the callable to copy from
      */
     public OnMessageTextStreamCallable(OnMessageCallable copy)
     {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnOpenCallable.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnOpenCallable.java
index fe46437..c84dde2 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnOpenCallable.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/OnOpenCallable.java
@@ -22,6 +22,7 @@
 
 import javax.websocket.Decoder;
 import javax.websocket.EndpointConfig;
+import javax.websocket.OnOpen;
 
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/BooleanDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/BooleanDecoder.java
index a473a1e..a72f0df 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/BooleanDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/BooleanDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Boolean} decoder.
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Boolean} decoder.
  * <p>
  * Note: delegates to {@link Boolean#parseBoolean(String)} and will only support "true" and "false" as boolean values.
  */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ByteDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ByteDecoder.java
index 5d2cae7..535fa24 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ByteDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ByteDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Byte} decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Byte} decoder
  */
 public class ByteDecoder extends AbstractDecoder implements Decoder.Text<Byte>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/CharacterDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/CharacterDecoder.java
index 22bd382..5afda92 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/CharacterDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/CharacterDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Character} decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Character} decoder
  */
 public class CharacterDecoder extends AbstractDecoder implements Decoder.Text<Character>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/DoubleDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/DoubleDecoder.java
index 4f0dee3..a4669a4 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/DoubleDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/DoubleDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Double} to decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Double} to decoder
  */
 public class DoubleDecoder extends AbstractDecoder implements Decoder.Text<Double>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/IntegerDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/IntegerDecoder.java
index 6fae470..d175719 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/IntegerDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/IntegerDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Integer} decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Integer} decoder
  */
 public class IntegerDecoder extends AbstractDecoder implements Decoder.Text<Integer>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ShortDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ShortDecoder.java
index 6aed8d0..8749fa7 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ShortDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/ShortDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link Short} decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link Short} decoder
  */
 public class ShortDecoder extends AbstractDecoder implements Decoder.Text<Short>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/StringDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/StringDecoder.java
index c88c539..09dc390 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/StringDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/decoders/StringDecoder.java
@@ -23,7 +23,7 @@
 
 
 /**
- * Default implementation of the {@link Text} Message to {@link String} decoder
+ * Default implementation of the {@link javax.websocket.Decoder.Text} Message to {@link String} decoder
  */
 public class StringDecoder extends AbstractDecoder implements Decoder.Text<String>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/BooleanEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/BooleanEncoder.java
index 62ed527..339f745 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/BooleanEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/BooleanEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Boolean} to {@link Text} Message encoder
+ * Default encoder for {@link Boolean} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class BooleanEncoder extends AbstractEncoder implements Encoder.Text<Boolean>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ByteEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ByteEncoder.java
index e6e27fb..168a437 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ByteEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ByteEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Byte} to {@link Text} Message encoder
+ * Default encoder for {@link Byte} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class ByteEncoder extends AbstractEncoder implements Encoder.Text<Byte>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/CharacterEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/CharacterEncoder.java
index c55c11a..15e75d3 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/CharacterEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/CharacterEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Character} to {@link Text} Message encoder
+ * Default encoder for {@link Character} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class CharacterEncoder extends AbstractEncoder implements Encoder.Text<Character>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/DoubleEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/DoubleEncoder.java
index 68fc9a7..8f4354c 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/DoubleEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/DoubleEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Double} to {@link Text} Message encoder
+ * Default encoder for {@link Double} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class DoubleEncoder extends AbstractEncoder implements Encoder.Text<Double>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/FloatEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/FloatEncoder.java
index 2233149..a9b0cbe 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/FloatEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/FloatEncoder.java
@@ -21,7 +21,7 @@
 import javax.websocket.EncodeException;
 import javax.websocket.Encoder;
 /**
- * Default encoder for {@link Float} to {@link Text} Message encoder
+ * Default encoder for {@link Float} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class FloatEncoder extends AbstractEncoder implements Encoder.Text<Float>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/IntegerEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/IntegerEncoder.java
index a26c5e6..d95ea4a 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/IntegerEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/IntegerEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Integer} to {@link Text} Message encoder
+ * Default encoder for {@link Integer} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class IntegerEncoder extends AbstractEncoder implements Encoder.Text<Integer>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/LongEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/LongEncoder.java
index deea480..b73d974 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/LongEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/LongEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Long} to {@link Text} Message encoder
+ * Default encoder for {@link Long} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class LongEncoder extends AbstractEncoder implements Encoder.Text<Long>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ShortEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ShortEncoder.java
index 2efe74b..e98ca01 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ShortEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/ShortEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link Short} to {@link Text} Message encoder
+ * Default encoder for {@link Short} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class ShortEncoder extends AbstractEncoder implements Encoder.Text<Short>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/StringEncoder.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/StringEncoder.java
index ccec2f8..c8fdaca 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/StringEncoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/encoders/StringEncoder.java
@@ -22,7 +22,7 @@
 import javax.websocket.Encoder;
 
 /**
- * Default encoder for {@link String} to {@link Text} Message encoder
+ * Default encoder for {@link String} to {@link javax.websocket.Encoder.Text} Message encoder
  */
 public class StringEncoder extends AbstractEncoder implements Encoder.Text<String>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrAnnotatedEventDriver.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrAnnotatedEventDriver.java
index adb422f..6de3c66 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrAnnotatedEventDriver.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/endpoints/JsrAnnotatedEventDriver.java
@@ -26,6 +26,7 @@
 
 import javax.websocket.CloseReason;
 import javax.websocket.DecodeException;
+import javax.websocket.MessageHandler.Whole;
 
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialOnMessage.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialOnMessage.java
index f9de209..ed2d425 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialOnMessage.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/BinaryPartialOnMessage.java
@@ -21,6 +21,8 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
+import javax.websocket.OnMessage;
+
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.websocket.common.message.MessageAppender;
 import org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialMessage.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialMessage.java
index 8edca37..8fa24e6 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialMessage.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialMessage.java
@@ -24,8 +24,8 @@
 import javax.websocket.MessageHandler;
 import javax.websocket.MessageHandler.Partial;
 
-import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.websocket.common.message.MessageAppender;
+import org.eclipse.jetty.websocket.common.util.Utf8PartialBuilder;
 import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
 
 /**
@@ -36,19 +36,22 @@
     @SuppressWarnings("unused")
     private final MessageHandlerWrapper msgWrapper;
     private final MessageHandler.Partial<String> partialHandler;
+    private final Utf8PartialBuilder utf8Partial;
 
     @SuppressWarnings("unchecked")
     public TextPartialMessage(MessageHandlerWrapper wrapper)
     {
         this.msgWrapper = wrapper;
         this.partialHandler = (Partial<String>)wrapper.getHandler();
+        this.utf8Partial = new Utf8PartialBuilder();
     }
 
     @Override
     public void appendFrame(ByteBuffer payload, boolean isLast) throws IOException
     {
+        String partialText = utf8Partial.toPartialString(payload);
         // No decoders for Partial messages per JSR-356 (PFD1 spec)
-        partialHandler.onMessage(BufferUtil.toUTF8String(payload.slice()),isLast);
+        partialHandler.onMessage(partialText,isLast);
     }
 
     @Override
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialOnMessage.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialOnMessage.java
index 5b13fb4..c91ab58 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialOnMessage.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/messages/TextPartialOnMessage.java
@@ -21,8 +21,10 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
-import org.eclipse.jetty.util.BufferUtil;
+import javax.websocket.OnMessage;
+
 import org.eclipse.jetty.websocket.common.message.MessageAppender;
+import org.eclipse.jetty.websocket.common.util.Utf8PartialBuilder;
 import org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver;
 
 /**
@@ -31,12 +33,14 @@
 public class TextPartialOnMessage implements MessageAppender
 {
     private final JsrAnnotatedEventDriver driver;
+    private final Utf8PartialBuilder utf8Partial;
     private boolean finished;
 
     public TextPartialOnMessage(JsrAnnotatedEventDriver driver)
     {
         this.driver = driver;
         this.finished = false;
+        this.utf8Partial = new Utf8PartialBuilder();
     }
 
     @Override
@@ -46,15 +50,9 @@
         {
             throw new IOException("Cannot append to finished buffer");
         }
-        if (payload == null)
-        {
-            driver.onPartialTextMessage("",isLast);
-        }
-        else
-        {
-            String text = BufferUtil.toUTF8String(payload);
-            driver.onPartialTextMessage(text,isLast);
-        }
+        
+        String text = utf8Partial.toPartialString(payload);
+        driver.onPartialTextMessage(text,isLast);
     }
 
     @Override
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadata.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadata.java
index 196995e..26314cd 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadata.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadata.java
@@ -21,10 +21,10 @@
 import org.eclipse.jetty.websocket.jsr356.MessageType;
 
 /**
- * The immutable base metadata for a coder ({@link Decoder} or {@link Encoder}
+ * The immutable base metadata for a coder ({@link javax.websocket.Decoder} or {@link javax.websocket.Encoder}
  * 
  * @param <T>
- *            the specific type of coder ({@link Decoder} or {@link Encoder}
+ *            the specific type of coder ({@link javax.websocket.Decoder} or {@link javax.websocket.Encoder}
  */
 public abstract class CoderMetadata<T>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java
index f431bd9..f202250 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/CoderMetadataSet.java
@@ -24,13 +24,15 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
+
 /**
  * An durable collection of {@link CoderMetadata}.
  * <p>
  * This is a write-only collection, and cannot be modified once initialized.
  * 
  * @param <T>
- *            The type of coder ({@link Decoder} or {@link Encoder}
+ *            The type of coder ({@link javax.websocket.Decoder} or {@link javax.websocket.Encoder}
  * @param <M>
  *            The metadata for the coder
  */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DuplicateCoderException.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DuplicateCoderException.java
index cd8b7be..d0571b9 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DuplicateCoderException.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/metadata/DuplicateCoderException.java
@@ -21,7 +21,7 @@
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
 
 /**
- * Thrown when a duplicate coder is encountered when attempting to identify a Endpoint's metadata ( {@link Decoder} or {@link Encoder})
+ * Thrown when a duplicate coder is encountered when attempting to identify a Endpoint's metadata ({@link javax.websocket.Decoder} or {@link javax.websocket.Encoder})
  */
 public class DuplicateCoderException extends InvalidWebSocketException
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointConfigTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointConfigTest.java
index dffba55..3bc1aa8 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointConfigTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/AnnotatedEndpointConfigTest.java
@@ -18,7 +18,10 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.net.URI;
 import java.util.List;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/ConfiguratorTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/ConfiguratorTest.java
index 895b952..0fc8cb2 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/ConfiguratorTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/ConfiguratorTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.net.URI;
 import java.util.List;
@@ -40,7 +40,7 @@
 import org.junit.Test;
 
 /**
- * Tests of {@link Configurator}
+ * Tests of {@link javax.websocket.ClientEndpointConfig.Configurator}
  */
 public class ConfiguratorTest
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/CookiesTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/CookiesTest.java
index 9f48f17..82ee44d 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/CookiesTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/CookiesTest.java
@@ -23,6 +23,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.ContainerProvider;
 import javax.websocket.Endpoint;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderFactoryTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderFactoryTest.java
index b32ce9d..9f2395b 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderFactoryTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderFactoryTest.java
@@ -25,6 +25,9 @@
 
 import javax.websocket.Decoder;
 
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
 import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
 import org.eclipse.jetty.websocket.jsr356.decoders.DateDecoder;
@@ -56,9 +59,11 @@
     @Before
     public void initDecoderFactory()
     {
-        DecoderFactory primitivesFactory = new DecoderFactory(PrimitiveDecoderMetadataSet.INSTANCE);
+        WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+        
+        DecoderFactory primitivesFactory = new DecoderFactory(containerScope,PrimitiveDecoderMetadataSet.INSTANCE);
         metadatas = new DecoderMetadataSet();
-        factory = new DecoderFactory(metadatas,primitivesFactory);
+        factory = new DecoderFactory(containerScope,metadatas,primitivesFactory);
     }
 
     @Test
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderManySmallTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderManySmallTest.java
index 94b2cb9..8a49dc6 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderManySmallTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderManySmallTest.java
@@ -42,13 +42,15 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
+@Ignore("Not working atm")
 public class DecoderReaderManySmallTest
 {
     public static class EventId
@@ -111,7 +113,7 @@
     private static class EventIdServer implements Runnable
     {
         private BlockheadServer server;
-        private ServerConnection sconnection;
+        private IBlockheadServerConnection sconnection;
         private CountDownLatch connectLatch = new CountDownLatch(1);
 
         public EventIdServer(BlockheadServer server)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java
index 9efa4eb..feeacb7 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/DecoderReaderTest.java
@@ -50,7 +50,7 @@
 import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -135,13 +135,14 @@
         }
 
         @OnMessage
-        public void onMessage(Quotes msg)
+        public synchronized void onMessage(Quotes msg)
         {
+            Integer h=hashCode();
             messageQueue.add(msg);
-            System.out.printf("Quotes from: %s%n",msg.author);
+            System.out.printf("%x: Quotes from: %s%n",h,msg.author);
             for (String quote : msg.quotes)
             {
-                System.out.printf(" - %s%n",quote);
+                System.out.printf("%x: - %s%n",h,quote);
             }
         }
 
@@ -154,7 +155,7 @@
     private static class QuoteServer implements Runnable
     {
         private BlockheadServer server;
-        private ServerConnection sconnection;
+        private IBlockheadServerConnection sconnection;
         private CountDownLatch connectLatch = new CountDownLatch(1);
 
         public QuoteServer(BlockheadServer server)
@@ -271,8 +272,8 @@
     }
 
     // TODO analyse and fix 
-    @Ignore
     @Test
+    @Ignore ("Quotes appear to be able to arrive in any order?")
     public void testTwoQuotes() throws Exception
     {
         QuotesSocket quoter = new QuotesSocket();
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderFactoryTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderFactoryTest.java
index 6fbd49e..7d1dc01 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderFactoryTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderFactoryTest.java
@@ -22,6 +22,9 @@
 
 import javax.websocket.Encoder;
 
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.encoders.IntegerEncoder;
 import org.eclipse.jetty.websocket.jsr356.encoders.LongEncoder;
 import org.eclipse.jetty.websocket.jsr356.encoders.PrimitiveEncoderMetadataSet;
@@ -53,9 +56,11 @@
     @Before
     public void initEncoderFactory()
     {
-        EncoderFactory primitivesFactory = new EncoderFactory(PrimitiveEncoderMetadataSet.INSTANCE);
+        WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+        
+        EncoderFactory primitivesFactory = new EncoderFactory(containerScope,PrimitiveEncoderMetadataSet.INSTANCE);
         metadatas = new EncoderMetadataSet();
-        factory = new EncoderFactory(metadatas,primitivesFactory);
+        factory = new EncoderFactory(containerScope,metadatas,primitivesFactory);
     }
 
     @Test
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java
index 67d9358..4cbe073 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
+import static org.hamcrest.Matchers.containsString;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
@@ -26,6 +28,7 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.ContainerProvider;
 import javax.websocket.EncodeException;
@@ -42,22 +45,20 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.containsString;
-
 public class EncoderTest
 {
     private static class EchoServer implements Runnable
     {
         private Thread thread;
         private BlockheadServer server;
-        private ServerConnection sconnection;
+        private IBlockheadServerConnection sconnection;
         private CountDownLatch connectLatch = new CountDownLatch(1);
 
         public EchoServer(BlockheadServer server)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoClient.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoClient.java
index aa0c14a..515e65f 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoClient.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoClient.java
@@ -18,7 +18,10 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
+import static org.hamcrest.Matchers.notNullValue;
+
 import java.io.IOException;
+
 import javax.websocket.CloseReason;
 import javax.websocket.Endpoint;
 import javax.websocket.EndpointConfig;
@@ -28,8 +31,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.notNullValue;
-
 /**
  * Basic Echo Client from extended Endpoint
  */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoTest.java
index 7aaa920..1c84d37 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EndpointEchoTest.java
@@ -18,8 +18,11 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
+import static org.hamcrest.Matchers.instanceOf;
+
 import java.net.URI;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.ContainerProvider;
 import javax.websocket.Session;
 import javax.websocket.WebSocketContainer;
@@ -35,8 +38,6 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.instanceOf;
-
 public class EndpointEchoTest
 {
     private static final Logger LOG = Log.getLogger(EndpointEchoTest.class);
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
index cc83384..0d8de52 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java
@@ -18,14 +18,18 @@
 
 package org.eclipse.jetty.websocket.jsr356;
 
+import static org.hamcrest.Matchers.*;
+
 import java.net.URI;
 import java.nio.ByteBuffer;
+
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.DeploymentException;
 import javax.websocket.MessageHandler;
 
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
+import org.eclipse.jetty.websocket.common.test.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
 import org.eclipse.jetty.websocket.jsr356.client.SimpleEndpointMetadata;
 import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
@@ -34,14 +38,11 @@
 import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
 import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
 import org.eclipse.jetty.websocket.jsr356.handlers.StringWholeHandler;
-import org.eclipse.jetty.websocket.jsr356.samples.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.samples.DummyEndpoint;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.instanceOf;
-
 public class JsrSessionTest
 {
     private ClientContainer container;
@@ -60,10 +61,10 @@
         // Executor executor = null;
 
         EndpointInstance ei = new EndpointInstance(websocket,config,metadata);
-
+        
         EventDriver driver = new JsrEndpointEventDriver(policy,ei);
         DummyConnection connection = new DummyConnection();
-        session = new JsrSession(requestURI,driver,connection,container,id);
+        session = new JsrSession(container,id,requestURI,driver,connection);
     }
 
     @Test
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactoryTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactoryTest.java
index dae79da..bd6df22 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactoryTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/MessageHandlerFactoryTest.java
@@ -25,6 +25,9 @@
 
 import javax.websocket.DeploymentException;
 
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.decoders.PrimitiveDecoderMetadataSet;
 import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayPartialHandler;
 import org.eclipse.jetty.websocket.jsr356.handlers.StringPartialHandler;
@@ -44,9 +47,11 @@
     @Before
     public void init() throws DeploymentException
     {
-        DecoderFactory primitivesFactory = new DecoderFactory(PrimitiveDecoderMetadataSet.INSTANCE);
+        WebSocketContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+        
+        DecoderFactory primitivesFactory = new DecoderFactory(containerScope,PrimitiveDecoderMetadataSet.INSTANCE);
         metadatas = new DecoderMetadataSet();
-        decoders = new DecoderFactory(metadatas,primitivesFactory);
+        decoders = new DecoderFactory(containerScope,metadatas,primitivesFactory);
         factory = new MessageHandlerFactory();
     }
 
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_InvalidSignaturesTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_InvalidSignaturesTest.java
index f53995a..c4fee09 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_InvalidSignaturesTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/ClientAnnotatedEndpointScanner_InvalidSignaturesTest.java
@@ -18,10 +18,13 @@
 
 package org.eclipse.jetty.websocket.jsr356.endpoints;
 
+import static org.hamcrest.Matchers.containsString;
+
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+
 import javax.websocket.ClientEndpoint;
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.DeploymentException;
@@ -48,8 +51,6 @@
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
-import static org.hamcrest.Matchers.containsString;
-
 /**
  * Test {@link AnnotatedEndpointScanner} against various simple, 1 method, {@link ClientEndpoint} annotated classes with invalid signatures.
  */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/TrackingSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/TrackingSocket.java
index e49277d..63f0ae7 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/TrackingSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/TrackingSocket.java
@@ -18,8 +18,13 @@
 
 package org.eclipse.jetty.websocket.jsr356.endpoints;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.CloseReason;
 import javax.websocket.CloseReason.CloseCode;
 
@@ -28,10 +33,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-
 /**
  * Abstract base socket used for tracking state and events within the socket for testing reasons.
  */
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidCloseIntSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidCloseIntSocket.java
index 3d48cb6..a3a587f 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidCloseIntSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidCloseIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Close Method Declaration (parameter type int)
+     * @param statusCode the status code
      */
     @OnClose
     public void onClose(int statusCode)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorErrorSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorErrorSocket.java
index 403a385..01f0d64 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorErrorSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorErrorSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type Error)
+     * @param error the error
      */
     @OnError
     public void onError(Error error)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorExceptionSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorExceptionSocket.java
index 26f5dcd..5ceb692 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorExceptionSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorExceptionSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type Exception)
+     * @param e the extension
      */
     @OnError
     public void onError(Exception e)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorIntSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorIntSocket.java
index 6718290..2a319c0 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorIntSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidErrorIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type int)
+     * @param errorCount the error count
      */
     @OnError
     public void onError(int errorCount)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenCloseReasonSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenCloseReasonSocket.java
index b5b4a8f..411ab95 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenCloseReasonSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenCloseReasonSocket.java
@@ -29,6 +29,7 @@
 {
     /**
      * Invalid Open Method Declaration (parameter type CloseReason)
+     * @param reason the close reason
      */
     @OnOpen
     public void onOpen(CloseReason reason)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenIntSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenIntSocket.java
index bff6558..5769108 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenIntSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Open Method Declaration (parameter type int)
+     * @param value the open value
      */
     @OnOpen
     public void onOpen(int value)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenSessionIntSocket.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenSessionIntSocket.java
index 9ed034b..adc3fe2 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenSessionIntSocket.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/endpoints/samples/InvalidOpenSessionIntSocket.java
@@ -29,6 +29,8 @@
 {
     /**
      * Invalid Open Method Declaration (parameter of type int)
+     * @param session the session for the open
+     * @param count the open count
      */
     @OnOpen
     public void onOpen(Session session, int count)
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/misbehaving/MisbehavingClassTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/misbehaving/MisbehavingClassTest.java
index 13a46fc..7c91094 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/misbehaving/MisbehavingClassTest.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/misbehaving/MisbehavingClassTest.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.websocket.jsr356.misbehaving;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.net.URI;
 import java.util.concurrent.TimeUnit;
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java
deleted file mode 100644
index 2775789..0000000
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/DummyConnection.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.samples;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.websocket.api.BatchMode;
-import org.eclipse.jetty.websocket.api.SuspendToken;
-import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.api.extensions.Frame;
-import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
-import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
-import org.eclipse.jetty.websocket.common.io.IOState;
-
-public class DummyConnection implements LogicalConnection
-{
-    private IOState iostate;
-
-    public DummyConnection()
-    {
-        this.iostate = new IOState();
-    }
-
-    @Override
-    public void close()
-    {
-    }
-
-    @Override
-    public void close(int statusCode, String reason)
-    {
-    }
-
-    @Override
-    public void disconnect()
-    {
-    }
-
-    @Override
-    public ByteBufferPool getBufferPool()
-    {
-        return null;
-    }
-
-    @Override
-    public Executor getExecutor()
-    {
-        return null;
-    }
-
-    @Override
-    public long getIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public IOState getIOState()
-    {
-        return this.iostate;
-    }
-
-    @Override
-    public InetSocketAddress getLocalAddress()
-    {
-        return null;
-    }
-
-    @Override
-    public long getMaxIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public WebSocketPolicy getPolicy()
-    {
-        return null;
-    }
-
-    @Override
-    public InetSocketAddress getRemoteAddress()
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public WebSocketSession getSession()
-    {
-        return null;
-    }
-
-    @Override
-    public boolean isOpen()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean isReading()
-    {
-        return false;
-    }
-
-    @Override
-    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
-    {
-    }
-
-    @Override
-    public void resume()
-    {
-    }
-
-    @Override
-    public void setMaxIdleTimeout(long ms)
-    {
-    }
-
-    @Override
-    public void setNextIncomingFrames(IncomingFrames incoming)
-    {
-    }
-
-    @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
-    public SuspendToken suspend()
-    {
-        return null;
-    }
-}
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/ExtDecoder.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/ExtDecoder.java
index 747ba66..751ce60 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/ExtDecoder.java
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/samples/ExtDecoder.java
@@ -22,6 +22,7 @@
 
 /**
  * Testing scenario of an extended Decoder interface
+ * @param <T> the decoder type
  */
 public interface ExtDecoder<T> extends Decoder.Text<T>
 {
diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/resources/jetty-logging.properties b/jetty-websocket/javax-websocket-client-impl/src/test/resources/jetty-logging.properties
index 6c5baae..3acadb6 100644
--- a/jetty-websocket/javax-websocket-client-impl/src/test/resources/jetty-logging.properties
+++ b/jetty-websocket/javax-websocket-client-impl/src/test/resources/jetty-logging.properties
@@ -1,5 +1,6 @@
 org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
 org.eclipse.jetty.LEVEL=WARN
 
-# org.eclipse.jetty.websocket.LEVEL=WARN
+# org.eclipse.jetty.websocket.LEVEL=INFO
+# org.eclipse.jetty.websocket.LEVEL=ALL
 # org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml
index 5abe579..65f52c5 100644
--- a/jetty-websocket/javax-websocket-server-impl/pom.xml
+++ b/jetty-websocket/javax-websocket-server-impl/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty.websocket</groupId>
     <artifactId>websocket-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
 
   <modelVersion>4.0.0</modelVersion>
@@ -70,23 +70,6 @@
               </execution>
           </executions>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-            <configuration>
-              <descriptorRefs>
-                <descriptorRef>config</descriptorRef>
-              </descriptorRefs>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointConfig.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointConfig.java
index 0981bfb..62e60d3 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointConfig.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointConfig.java
@@ -32,6 +32,8 @@
 import javax.websocket.server.ServerEndpoint;
 import javax.websocket.server.ServerEndpointConfig;
 
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+
 public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
 {
     private final Class<?> endpointClass;
@@ -44,12 +46,12 @@
     private Map<String, Object> userProperties;
     private List<Extension> extensions;
 
-    public AnnotatedServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno) throws DeploymentException
+    public AnnotatedServerEndpointConfig(WebSocketContainerScope containerScope, Class<?> endpointClass, ServerEndpoint anno) throws DeploymentException
     {
-        this(endpointClass,anno,null);
+        this(containerScope,endpointClass,anno,null);
     }
 
-    public AnnotatedServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno, ServerEndpointConfig baseConfig) throws DeploymentException
+    public AnnotatedServerEndpointConfig(WebSocketContainerScope containerScope, Class<?> endpointClass, ServerEndpoint anno, ServerEndpointConfig baseConfig) throws DeploymentException
     {
         ServerEndpointConfig.Configurator configr = null;
 
@@ -109,23 +111,25 @@
         {
             userProperties.putAll(baseConfig.getUserProperties());
         }
+        
+        ServerEndpointConfig.Configurator cfgr;
 
         if (anno.configurator() == ServerEndpointConfig.Configurator.class)
         {
             if (configr != null)
             {
-                this.configurator = configr;
+                cfgr = configr;
             }
             else
             {
-                this.configurator = BasicServerEndpointConfigurator.INSTANCE;
+                cfgr = new ContainerDefaultConfigurator();
             }
         }
         else
         {
             try
             {
-                this.configurator = anno.configurator().newInstance();
+                cfgr = anno.configurator().newInstance();
             }
             catch (InstantiationException | IllegalAccessException e)
             {
@@ -137,6 +141,9 @@
                 throw new DeploymentException(err.toString(),e);
             }
         }
+        
+        // Make sure all Configurators obtained are decorated
+        this.configurator = containerScope.getObjectFactory().decorate(cfgr);
     }
 
     @Override
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointMetadata.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointMetadata.java
index 39087e9..913d17c 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointMetadata.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointMetadata.java
@@ -25,6 +25,7 @@
 import javax.websocket.server.ServerEndpointConfig;
 
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointMetadata;
 import org.eclipse.jetty.websocket.jsr356.annotations.IJsrParamId;
 
@@ -33,7 +34,7 @@
     private final ServerEndpoint endpoint;
     private final AnnotatedServerEndpointConfig config;
 
-    protected AnnotatedServerEndpointMetadata(Class<?> websocket, ServerEndpointConfig baseConfig) throws DeploymentException
+    protected AnnotatedServerEndpointMetadata(WebSocketContainerScope containerScope, Class<?> websocket, ServerEndpointConfig baseConfig) throws DeploymentException
     {
         super(websocket);
 
@@ -44,9 +45,9 @@
         }
 
         this.endpoint = anno;
-        this.config = new AnnotatedServerEndpointConfig(websocket,anno,baseConfig);
+        this.config = new AnnotatedServerEndpointConfig(containerScope,websocket,anno,baseConfig);
         
-        getDecoders().addAll(anno.decoders());
+        getDecoders().addAll(anno.decoders());  
         getEncoders().addAll(anno.encoders());
     }
 
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfig.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfig.java
index fb2c154..02c42ad 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfig.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfig.java
@@ -28,6 +28,8 @@
 import javax.websocket.Extension;
 import javax.websocket.server.ServerEndpointConfig;
 
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+
 public class BasicServerEndpointConfig implements ServerEndpointConfig
 {
     private final List<Class<? extends Decoder>> decoders;
@@ -39,7 +41,7 @@
     private final String path;
     private Map<String, Object> userProperties;
 
-    public BasicServerEndpointConfig(Class<?> endpointClass, String path)
+    public BasicServerEndpointConfig(WebSocketContainerScope containerScope, Class<?> endpointClass, String path)
     {
         this.endpointClass = endpointClass;
         this.path = path;
@@ -49,10 +51,10 @@
         this.subprotocols = new ArrayList<>();
         this.extensions = new ArrayList<>();
         this.userProperties = new HashMap<>();
-        this.configurator = BasicServerEndpointConfigurator.INSTANCE;
+        this.configurator = new ContainerDefaultConfigurator();
     }
 
-    public BasicServerEndpointConfig(ServerEndpointConfig copy)
+    public BasicServerEndpointConfig(WebSocketContainerScope containerScope, ServerEndpointConfig copy)
     {
         // immutable concepts
         this.endpointClass = copy.getEndpointClass();
@@ -62,15 +64,21 @@
         this.encoders = copy.getEncoders();
         this.subprotocols = copy.getSubprotocols();
         this.extensions = copy.getExtensions();
+
+        ServerEndpointConfig.Configurator cfgr;
+
         if (copy.getConfigurator() != null)
         {
-            this.configurator = copy.getConfigurator();
+            cfgr = copy.getConfigurator();
         }
         else
         {
-            this.configurator = BasicServerEndpointConfigurator.INSTANCE;
+            cfgr = new ContainerDefaultConfigurator();
         }
 
+        // Make sure all Configurators obtained are decorated
+        this.configurator = containerScope.getObjectFactory().decorate(cfgr);
+
         // mutable concepts
         this.userProperties = new HashMap<>(copy.getUserProperties());
     }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java
deleted file mode 100644
index ca911a6..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/BasicServerEndpointConfigurator.java
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server;
-
-import java.util.List;
-import javax.websocket.Extension;
-import javax.websocket.HandshakeResponse;
-import javax.websocket.server.HandshakeRequest;
-import javax.websocket.server.ServerEndpointConfig;
-
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.util.QuoteUtil;
-
-public class BasicServerEndpointConfigurator extends ServerEndpointConfig.Configurator
-{
-    private static final Logger LOG = Log.getLogger(BasicServerEndpointConfigurator.class);
-    private static final String NO_SUBPROTOCOL = "";
-    public static final ServerEndpointConfig.Configurator INSTANCE = new BasicServerEndpointConfigurator();
-
-    @Override
-    public boolean checkOrigin(String originHeaderValue)
-    {
-        return true;
-    }
-
-    @Override
-    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
-    {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug(".getEndpointInstance({})",endpointClass);
-        }
-        try
-        {
-            return endpointClass.newInstance();
-        }
-        catch (IllegalAccessException e)
-        {
-            throw new InstantiationException(String.format("%s: %s",e.getClass().getName(),e.getMessage()));
-        }
-    }
-
-    @Override
-    public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
-    {
-        return requested;
-    }
-
-    @Override
-    public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
-    {
-        if ((requested == null) || (requested.size() == 0))
-        {
-            // nothing requested, don't return anything
-            return NO_SUBPROTOCOL;
-        }
-
-        // Nothing specifically called out as being supported by the endpoint
-        if ((supported == null) || (supported.isEmpty()))
-        {
-            // Just return the first hit in this case
-            LOG.warn("Client requested Subprotocols on endpoint with none supported: {}",QuoteUtil.join(requested,","));
-            return NO_SUBPROTOCOL;
-        }
-
-        // Return the first matching hit from the list of supported protocols.
-        for (String possible : requested)
-        {
-            if (possible == null)
-            {
-                // skip null
-                continue;
-            }
-
-            if (supported.contains(possible))
-            {
-                return possible;
-            }
-        }
-
-        LOG.warn("Client requested subprotocols {} do not match any endpoint supported subprotocols {}",QuoteUtil.join(requested,","),
-                QuoteUtil.join(supported,","));
-        return NO_SUBPROTOCOL;
-    }
-
-    @Override
-    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
-    {
-        /* do nothing */
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ContainerDefaultConfigurator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ContainerDefaultConfigurator.java
new file mode 100644
index 0000000..9a75fbd
--- /dev/null
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ContainerDefaultConfigurator.java
@@ -0,0 +1,128 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.jsr356.server;
+
+import java.util.List;
+import java.util.ServiceLoader;
+
+import javax.websocket.Extension;
+import javax.websocket.HandshakeResponse;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerEndpointConfig;
+import javax.websocket.server.ServerEndpointConfig.Configurator;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.util.QuoteUtil;
+
+/**
+ * The "Container Default Configurator" per the JSR-356 spec.
+ * 
+ * @see ServiceLoader behavior of {@link javax.websocket.server.ServerEndpointConfig.Configurator}
+ */
+public final class ContainerDefaultConfigurator extends Configurator
+{
+    private static final Logger LOG = Log.getLogger(ContainerDefaultConfigurator.class);
+    private static final String NO_SUBPROTOCOL = "";
+    
+    /**
+     * Default Constructor required, as
+     * javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator()
+     * will be the one that instantiates this class in most cases.
+     */
+    public ContainerDefaultConfigurator()
+    {
+        super();
+    }
+
+    @Override
+    public boolean checkOrigin(String originHeaderValue)
+    {
+        return true;
+    }
+
+    @Override
+    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug(".getEndpointInstance({})",endpointClass);
+        }
+        
+        try
+        {
+            // Since this is started via a ServiceLoader, this class has no Scope or context
+            // that can be used to obtain a ObjectFactory from.
+            return endpointClass.newInstance();
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new InstantiationException(String.format("%s: %s",e.getClass().getName(),e.getMessage()));
+        }
+    }
+
+    @Override
+    public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
+    {
+        return requested;
+    }
+
+    @Override
+    public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
+    {
+        if ((requested == null) || (requested.size() == 0))
+        {
+            // nothing requested, don't return anything
+            return NO_SUBPROTOCOL;
+        }
+
+        // Nothing specifically called out as being supported by the endpoint
+        if ((supported == null) || (supported.isEmpty()))
+        {
+            // Just return the first hit in this case
+            LOG.warn("Client requested Subprotocols on endpoint with none supported: {}",QuoteUtil.join(requested,","));
+            return NO_SUBPROTOCOL;
+        }
+
+        // Return the first matching hit from the list of supported protocols.
+        for (String possible : requested)
+        {
+            if (possible == null)
+            {
+                // skip null
+                continue;
+            }
+
+            if (supported.contains(possible))
+            {
+                return possible;
+            }
+        }
+
+        LOG.warn("Client requested subprotocols {} do not match any endpoint supported subprotocols {}",QuoteUtil.join(requested,","),
+                QuoteUtil.join(supported,","));
+        return NO_SUBPROTOCOL;
+    }
+
+    @Override
+    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
+    {
+        /* do nothing */
+    }
+}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
index 7bd8ca2..5392dfc 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java
@@ -27,16 +27,18 @@
 import javax.websocket.Extension;
 import javax.websocket.Extension.Parameter;
 import javax.websocket.server.ServerEndpointConfig;
+import javax.websocket.server.ServerEndpointConfig.Configurator;
 
+import org.eclipse.jetty.http.pathmap.PathSpec;
+import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.JsrExtension;
 import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
-import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
@@ -47,11 +49,13 @@
     public static final String PROP_LOCAL_ADDRESS = "javax.websocket.endpoint.localAddress";
     public static final String PROP_LOCALES = "javax.websocket.upgrade.locales";
     private static final Logger LOG = Log.getLogger(JsrCreator.class);
+    private final WebSocketContainerScope containerScope;
     private final ServerEndpointMetadata metadata;
     private final ExtensionFactory extensionFactory;
 
-    public JsrCreator(ServerEndpointMetadata metadata, ExtensionFactory extensionFactory)
+    public JsrCreator(WebSocketContainerScope containerScope, ServerEndpointMetadata metadata, ExtensionFactory extensionFactory)
     {
+        this.containerScope = containerScope;
         this.metadata = metadata;
         this.extensionFactory = extensionFactory;
     }
@@ -64,11 +68,11 @@
 
         // Get raw config, as defined when the endpoint was added to the container
         ServerEndpointConfig config = metadata.getConfig();
-
+        
         // Establish a copy of the config, so that the UserProperties are unique
         // per upgrade request.
-        config = new BasicServerEndpointConfig(config);
-
+        config = new BasicServerEndpointConfig(containerScope, config);
+        
         // Bug 444617 - Expose localAddress and remoteAddress for jsr modify handshake to use
         // This is being implemented as an optional set of userProperties so that
         // it is not JSR api breaking.  A few users on #jetty and a few from cometd
@@ -139,15 +143,18 @@
         try
         {
             Class<?> endpointClass = config.getEndpointClass();
-            Object endpoint = config.getConfigurator().getEndpointInstance(endpointClass);
+            Configurator configr = config.getConfigurator();
+            Object endpoint = configr.getEndpointInstance(endpointClass);
+            // Do not decorate here (let the Connection and Session start first)
+            // This will allow CDI to see Session for injection into Endpoint classes.
             PathSpec pathSpec = hsreq.getRequestPathSpec();
-            if (pathSpec instanceof WebSocketPathSpec)
+            if (pathSpec instanceof UriTemplatePathSpec)
             {
                 // We have a PathParam path spec
-                WebSocketPathSpec wspathSpec = (WebSocketPathSpec)pathSpec;
+                UriTemplatePathSpec wspathSpec = (UriTemplatePathSpec)pathSpec;
                 String requestPath = req.getRequestPath();
                 // Wrap the config with the path spec information
-                config = new PathParamServerEndpointConfig(config,wspathSpec,requestPath);
+                config = new PathParamServerEndpointConfig(containerScope,config,wspathSpec,requestPath);
             }
             return new EndpointInstance(endpoint,config,metadata);
         }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java
index f4c6b3d..b740a6c 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java
@@ -25,7 +25,7 @@
 
 import javax.websocket.server.HandshakeRequest;
 
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
+import org.eclipse.jetty.http.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
 
 public class JsrHandshakeRequest implements HandshakeRequest
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java
index df92b76..9c476f6 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/PathParamServerEndpointConfig.java
@@ -23,7 +23,8 @@
 
 import javax.websocket.server.ServerEndpointConfig;
 
-import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
+import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 
 /**
  * Wrapper for a {@link ServerEndpointConfig} where there PathParm information from the incoming request.
@@ -32,9 +33,9 @@
 {
     private final Map<String, String> pathParamMap;
 
-    public PathParamServerEndpointConfig(ServerEndpointConfig config, WebSocketPathSpec pathSpec, String requestPath)
+    public PathParamServerEndpointConfig(WebSocketContainerScope containerScope, ServerEndpointConfig config, UriTemplatePathSpec pathSpec, String requestPath)
     {
-        super(config);
+        super(containerScope, config);
 
         Map<String, String> pathMap = pathSpec.getPathParams(requestPath);
         pathParamMap = new HashMap<String, String>();
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
index 8bbffef..2128e8e 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 import javax.websocket.DeploymentException;
@@ -25,6 +27,7 @@
 import javax.websocket.server.ServerEndpoint;
 import javax.websocket.server.ServerEndpointConfig;
 
+import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
@@ -33,7 +36,6 @@
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
 import org.eclipse.jetty.websocket.jsr356.endpoints.EndpointInstance;
 import org.eclipse.jetty.websocket.jsr356.metadata.EndpointMetadata;
-import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
 import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
 import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
 
@@ -43,16 +45,19 @@
 
     private final MappedWebSocketCreator mappedCreator;
     private final WebSocketServerFactory webSocketServerFactory;
+    private List<Class<?>> deferredEndpointClasses;
+    private List<ServerEndpointConfig> deferredEndpointConfigs;
 
     public ServerContainer(MappedWebSocketCreator creator, WebSocketServerFactory factory, Executor executor)
     {
-        super(executor);
+        super(factory);
         this.mappedCreator = creator;
         this.webSocketServerFactory = factory;
         EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();
         eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
         eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
         this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this));
+        addBean(webSocketServerFactory);
     }
     
     public EndpointInstance newClientEndpointInstance(Object endpoint, ServerEndpointConfig config, String path)
@@ -67,7 +72,7 @@
             }
             else
             {
-                cec = new BasicServerEndpointConfig(endpoint.getClass(),path);
+                cec = new BasicServerEndpointConfig(this,endpoint.getClass(),path);
             }
         }
         return new EndpointInstance(endpoint,cec,metadata);
@@ -76,25 +81,73 @@
     @Override
     public void addEndpoint(Class<?> endpointClass) throws DeploymentException
     {
-        ServerEndpointMetadata metadata = getServerEndpointMetadata(endpointClass,null);
-        addEndpoint(metadata);
+        if (isStarted() || isStarting())
+        {
+            ServerEndpointMetadata metadata = getServerEndpointMetadata(endpointClass,null);
+            addEndpoint(metadata);
+        }
+        else
+        {
+            if (deferredEndpointClasses == null)
+            {
+                deferredEndpointClasses = new ArrayList<Class<?>>();
+            }
+            deferredEndpointClasses.add(endpointClass);
+        }
     }
 
-    public void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
+    private void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
     {
-        JsrCreator creator = new JsrCreator(metadata,webSocketServerFactory.getExtensionFactory());
-        mappedCreator.addMapping(new WebSocketPathSpec(metadata.getPath()),creator);
+        JsrCreator creator = new JsrCreator(this,metadata,webSocketServerFactory.getExtensionFactory());
+        mappedCreator.addMapping(new UriTemplatePathSpec(metadata.getPath()),creator);
     }
 
     @Override
     public void addEndpoint(ServerEndpointConfig config) throws DeploymentException
     {
-        if (LOG.isDebugEnabled())
+        if (isStarted() || isStarting())
         {
-            LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
+            }
+            ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
+            addEndpoint(metadata);
         }
-        ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
-        addEndpoint(metadata);
+        else
+        {
+            if (deferredEndpointConfigs == null)
+            {
+                deferredEndpointConfigs = new ArrayList<ServerEndpointConfig>();
+            }
+            deferredEndpointConfigs.add(config);
+        }
+    }
+    
+    @Override
+    protected void doStart() throws Exception
+    {
+        // Proceed with Normal Startup
+        super.doStart();
+        
+        // Process Deferred Endpoints
+        if (deferredEndpointClasses != null)
+        {
+            for (Class<?> endpointClass : deferredEndpointClasses)
+            {
+                addEndpoint(endpointClass);
+            }
+            deferredEndpointClasses.clear();
+        }
+        
+        if (deferredEndpointConfigs != null)
+        {
+            for (ServerEndpointConfig config : deferredEndpointConfigs)
+            {
+                addEndpoint(config);
+            }
+            deferredEndpointConfigs.clear();
+        }
     }
 
     public ServerEndpointMetadata getServerEndpointMetadata(final Class<?> endpoint, final ServerEndpointConfig config) throws DeploymentException
@@ -105,7 +158,7 @@
         if (anno != null)
         {
             // Annotated takes precedence here
-            AnnotatedServerEndpointMetadata ametadata = new AnnotatedServerEndpointMetadata(endpoint,config);
+            AnnotatedServerEndpointMetadata ametadata = new AnnotatedServerEndpointMetadata(this,endpoint,config);
             AnnotatedEndpointScanner<ServerEndpoint, ServerEndpointConfig> scanner = new AnnotatedEndpointScanner<>(ametadata);
             metadata = ametadata;
             scanner.scan();
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
index db343c3..f98c536 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java
@@ -20,6 +20,7 @@
 
 import java.util.HashSet;
 import java.util.Set;
+
 import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
@@ -32,6 +33,7 @@
 
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -49,6 +51,10 @@
      * Jetty Native approach.
      * <p>
      * Note: this will add the Upgrade filter to the existing list, with no regard for order.  It will just be tacked onto the end of the list.
+     * 
+     * @param context the servlet context handler
+     * @return the created websocket server container
+     * @throws ServletException if unable to create the websocket server container
      */
     public static ServerContainer configureContext(ServletContextHandler context) throws ServletException
     {
@@ -69,6 +75,11 @@
      * Servlet 3.1 approach.
      * <p>
      * This will use Servlet 3.1 techniques on the {@link ServletContext} to add a filter at the start of the filter chain.
+     * 
+     * @param context the servlet context
+     * @param jettyContext the jetty servlet context handler
+     * @return the created websocket server container
+     * @throws ServletException if unable to create the websocket server container
      */
     public static ServerContainer configureContext(ServletContext context, ServletContextHandler jettyContext) throws ServletException
     {
@@ -163,7 +174,16 @@
 
             // Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
             context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
-
+            
+            // Establish the DecoratedObjectFactory thread local 
+            // for various ServiceLoader initiated components to use.
+            DecoratedObjectFactory instantiator = (DecoratedObjectFactory)context.getAttribute(DecoratedObjectFactory.ATTR);
+            if (instantiator == null)
+            {
+                LOG.info("Using WebSocket local DecoratedObjectFactory - none found in ServletContext");
+                instantiator = new DecoratedObjectFactory();
+            }
+            
             if (LOG.isDebugEnabled())
             {
                 LOG.debug("Found {} classes",c.size());
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java
deleted file mode 100644
index b6e23e2..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java
+++ /dev/null
@@ -1,344 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server.pathmap;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.util.TypeUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpecGroup;
-import org.eclipse.jetty.websocket.server.pathmap.RegexPathSpec;
-
-/**
- * PathSpec for WebSocket &#064;{@link ServerEndpoint} declarations with support for URI templates and &#064;{@link PathParam} annotations
- * 
- * @see javax.websocket spec (JSR-356) Section 3.1.1 URI Mapping
- * @see <a href="https://tools.ietf.org/html/rfc6570">URI Templates (Level 1)</a>
- */
-public class WebSocketPathSpec extends RegexPathSpec
-{
-    private static final Logger LOG = Log.getLogger(WebSocketPathSpec.class);
-    
-    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{(.*)\\}");
-    /** Reserved Symbols in URI Template variable */
-    private static final String VARIABLE_RESERVED = ":/?#[]@" + // gen-delims
-                                                    "!$&'()*+,;="; // sub-delims
-    /** Allowed Symboles in a URI Template variable */
-    private static final String VARIABLE_SYMBOLS="-._";
-    private static final Set<String> FORBIDDEN_SEGMENTS;
-
-    static
-    {
-        FORBIDDEN_SEGMENTS = new HashSet<>();
-        FORBIDDEN_SEGMENTS.add("/./");
-        FORBIDDEN_SEGMENTS.add("/../");
-        FORBIDDEN_SEGMENTS.add("//");
-    }
-
-    private String variables[];
-
-    public WebSocketPathSpec(String pathParamSpec)
-    {
-        super();
-        Objects.requireNonNull(pathParamSpec,"Path Param Spec cannot be null");
-
-        if ("".equals(pathParamSpec) || "/".equals(pathParamSpec))
-        {
-            super.pathSpec = "/";
-            super.pattern = Pattern.compile("^/$");
-            super.pathDepth = 1;
-            this.specLength = 1;
-            this.variables = new String[0];
-            this.group = PathSpecGroup.EXACT;
-            return;
-        }
-
-        if (pathParamSpec.charAt(0) != '/')
-        {
-            // path specs must start with '/'
-            StringBuilder err = new StringBuilder();
-            err.append("Syntax Error: path spec \"");
-            err.append(pathParamSpec);
-            err.append("\" must start with '/'");
-            throw new IllegalArgumentException(err.toString());
-        }
-
-        for (String forbidden : FORBIDDEN_SEGMENTS)
-        {
-            if (pathParamSpec.contains(forbidden))
-            {
-                StringBuilder err = new StringBuilder();
-                err.append("Syntax Error: segment ");
-                err.append(forbidden);
-                err.append(" is forbidden in path spec: ");
-                err.append(pathParamSpec);
-                throw new IllegalArgumentException(err.toString());
-            }
-        }
-
-        this.pathSpec = pathParamSpec;
-
-        StringBuilder regex = new StringBuilder();
-        regex.append('^');
-
-        List<String> varNames = new ArrayList<>();
-        // split up into path segments (ignoring the first slash that will always be empty)
-        String segments[] = pathParamSpec.substring(1).split("/");
-        char segmentSignature[] = new char[segments.length];
-        this.pathDepth = segments.length;
-        for (int i = 0; i < segments.length; i++)
-        {
-            String segment = segments[i];
-            Matcher mat = VARIABLE_PATTERN.matcher(segment);
-
-            if (mat.matches())
-            {
-                // entire path segment is a variable.
-                String variable = mat.group(1);
-                if (varNames.contains(variable))
-                {
-                    // duplicate variable names
-                    StringBuilder err = new StringBuilder();
-                    err.append("Syntax Error: variable ");
-                    err.append(variable);
-                    err.append(" is duplicated in path spec: ");
-                    err.append(pathParamSpec);
-                    throw new IllegalArgumentException(err.toString());
-                }
-
-                assertIsValidVariableLiteral(variable);
-
-                segmentSignature[i] = 'v'; // variable
-                // valid variable name
-                varNames.add(variable);
-                // build regex
-                regex.append("/([^/]+)");
-            }
-            else if (mat.find(0))
-            {
-                // variable exists as partial segment
-                StringBuilder err = new StringBuilder();
-                err.append("Syntax Error: variable ");
-                err.append(mat.group());
-                err.append(" must exist as entire path segment: ");
-                err.append(pathParamSpec);
-                throw new IllegalArgumentException(err.toString());
-            }
-            else if ((segment.indexOf('{') >= 0) || (segment.indexOf('}') >= 0))
-            {
-                // variable is split with a path separator
-                StringBuilder err = new StringBuilder();
-                err.append("Syntax Error: invalid path segment /");
-                err.append(segment);
-                err.append("/ variable declaration incomplete: ");
-                err.append(pathParamSpec);
-                throw new IllegalArgumentException(err.toString());
-            }
-            else if (segment.indexOf('*') >= 0)
-            {
-                // glob segment
-                StringBuilder err = new StringBuilder();
-                err.append("Syntax Error: path segment /");
-                err.append(segment);
-                err.append("/ contains a wildcard symbol (not supported by javax.websocket): ");
-                err.append(pathParamSpec);
-                throw new IllegalArgumentException(err.toString());
-            }
-            else
-            {
-                // valid path segment
-                segmentSignature[i] = 'e'; // exact
-                // build regex
-                regex.append('/');
-                // escape regex special characters
-                for (char c : segment.toCharArray())
-                {
-                    if ((c == '.') || (c == '[') || (c == ']') || (c == '\\'))
-                    {
-                        regex.append('\\');
-                    }
-                    regex.append(c);
-                }
-            }
-        }
-        
-        // Handle trailing slash (which is not picked up during split)
-        if(pathParamSpec.charAt(pathParamSpec.length()-1) == '/')
-        {
-            regex.append('/');
-        }
-
-        regex.append('$');
-
-        this.pattern = Pattern.compile(regex.toString());
-
-        int varcount = varNames.size();
-        this.variables = varNames.toArray(new String[varcount]);
-
-        // Convert signature to group
-        String sig = String.valueOf(segmentSignature);
-
-        if (Pattern.matches("^e*$",sig))
-        {
-            this.group = PathSpecGroup.EXACT;
-        }
-        else if (Pattern.matches("^e*v+",sig))
-        {
-            this.group = PathSpecGroup.PREFIX_GLOB;
-        }
-        else if (Pattern.matches("^v+e+",sig))
-        {
-            this.group = PathSpecGroup.SUFFIX_GLOB;
-        }
-        else
-        {
-            this.group = PathSpecGroup.MIDDLE_GLOB;
-        }
-    }
-
-    /**
-     * Validate variable literal name, per RFC6570, Section 2.1 Literals
-     * @param variable
-     * @param pathParamSpec
-     */
-    private void assertIsValidVariableLiteral(String variable)
-    {
-        int len = variable.length();
-        
-        int i = 0;
-        int codepoint;
-        boolean valid = (len > 0); // must not be zero length
-        
-        while (valid && i < len)
-        {
-            codepoint = variable.codePointAt(i);
-            i += Character.charCount(codepoint);
-
-            // basic letters, digits, or symbols
-            if (isValidBasicLiteralCodepoint(codepoint))
-            {
-                continue;
-            }
-
-            // The ucschar and iprivate pieces
-            if (Character.isSupplementaryCodePoint(codepoint))
-            {
-                continue;
-            }
-
-            // pct-encoded
-            if (codepoint == '%')
-            {
-                if (i + 2 > len)
-                {
-                    // invalid percent encoding, missing extra 2 chars
-                    valid = false;
-                    continue;
-                }
-                codepoint = TypeUtil.convertHexDigit(variable.codePointAt(i++)) << 4;
-                codepoint |= TypeUtil.convertHexDigit(variable.codePointAt(i++));
-
-                // validate basic literal
-                if (isValidBasicLiteralCodepoint(codepoint))
-                {
-                    continue;
-                }
-            }
-            
-            valid = false;
-        }
-
-        if (!valid)
-        {
-            // invalid variable name
-            StringBuilder err = new StringBuilder();
-            err.append("Syntax Error: variable {");
-            err.append(variable);
-            err.append("} an invalid variable name: ");
-            err.append(pathSpec);
-            throw new IllegalArgumentException(err.toString());
-        }
-    }
-    
-    private boolean isValidBasicLiteralCodepoint(int codepoint)
-    {
-        // basic letters or digits
-        if((codepoint >= 'a' && codepoint <= 'z') ||
-           (codepoint >= 'A' && codepoint <= 'Z') ||
-           (codepoint >= '0' && codepoint <= '9'))
-        {
-            return true;
-        }
-        
-        // basic allowed symbols
-        if(VARIABLE_SYMBOLS.indexOf(codepoint) >= 0)
-        {
-            return true; // valid simple value
-        }
-        
-        // basic reserved symbols
-        if(VARIABLE_RESERVED.indexOf(codepoint) >= 0)
-        {
-            LOG.warn("Detected URI Template reserved symbol [{}] in path spec \"{}\"",(char)codepoint,pathSpec);
-            return false; // valid simple value
-        }
-
-        return false;
-    }
-
-    public Map<String, String> getPathParams(String path)
-    {
-        Matcher matcher = getMatcher(path);
-        if (matcher.matches())
-        {
-            if (group == PathSpecGroup.EXACT)
-            {
-                return Collections.emptyMap();
-            }
-            Map<String, String> ret = new HashMap<>();
-            int groupCount = matcher.groupCount();
-            for (int i = 1; i <= groupCount; i++)
-            {
-                ret.put(this.variables[i - 1],matcher.group(i));
-            }
-            return ret;
-        }
-        return null;
-    }
-
-    public int getVariableCount()
-    {
-        return variables.length;
-    }
-
-    public String[] getVariables()
-    {
-        return this.variables;
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
index 57e3ef3..7f67aa0 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
+++ b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator
@@ -1 +1 @@
-org.eclipse.jetty.websocket.jsr356.server.BasicServerEndpointConfigurator
\ No newline at end of file
+org.eclipse.jetty.websocket.jsr356.server.ContainerDefaultConfigurator
\ No newline at end of file
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java
index 556d63e..4fa3ebb 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/AnnotatedServerEndpointTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
 
 import java.io.File;
 import java.net.URI;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java
index e5ed848..40ef7d9 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java
@@ -35,7 +35,7 @@
 import org.junit.Test;
 
 /**
- * Example of an {@link Endpoint} extended echo server added programmatically via the
+ * Example of an {@link javax.websocket.Endpoint} extended echo server added programmatically via the
  * {@link ServerContainer#addEndpoint(javax.websocket.server.ServerEndpointConfig)}
  */
 public class BasicEndpointTest
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java
index 8f20e6a..8917868 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BinaryStreamTest.java
@@ -26,6 +26,7 @@
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.ClientEndpoint;
 import javax.websocket.ContainerProvider;
 import javax.websocket.OnMessage;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java
index 1123495..7258fd9 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -50,6 +51,7 @@
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
 import org.eclipse.jetty.websocket.common.test.HttpResponse;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
 import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -302,7 +304,7 @@
     {
         URI uri = baseServerUri.resolve("/empty");
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addExtensions("identity");
             client.connect();
@@ -317,7 +319,7 @@
     {
         URI uri = baseServerUri.resolve("/no-extensions");
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addExtensions("identity");
             client.connect();
@@ -332,7 +334,7 @@
     {
         URI uri = baseServerUri.resolve("/capture-request-headers");
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addHeader("X-Dummy: Bogus\r\n");
             client.connect();
@@ -352,7 +354,7 @@
         URI uri = baseServerUri.resolve("/unique-user-props");
 
         // First request
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.connect();
             client.sendStandardRequest();
@@ -365,7 +367,7 @@
         }
         
         // Second request
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.connect();
             client.sendStandardRequest();
@@ -389,7 +391,7 @@
         URI uri = baseServerUri.resolve("/addr");
 
         // First request
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.connect();
             client.sendStandardRequest();
@@ -416,6 +418,7 @@
     
     /**
      * Test of Sec-WebSocket-Protocol, as seen in RFC-6455, 1 protocol
+     * @throws Exception on test failure
      */
     @Test
     public void testProtocol_Single() throws Exception
@@ -423,7 +426,7 @@
         URI uri = baseServerUri.resolve("/protocols");
         ProtocolsConfigurator.seenProtocols.set(null);
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addHeader("Sec-WebSocket-Protocol: echo\r\n");
             client.connect();
@@ -439,6 +442,7 @@
     
     /**
      * Test of Sec-WebSocket-Protocol, as seen in RFC-6455, 3 protocols
+     * @throws Exception on test failure
      */
     @Test
     public void testProtocol_Triple() throws Exception
@@ -446,7 +450,7 @@
         URI uri = baseServerUri.resolve("/protocols");
         ProtocolsConfigurator.seenProtocols.set(null);
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addHeader("Sec-WebSocket-Protocol: echo, chat, status\r\n");
             client.connect();
@@ -462,6 +466,7 @@
     
     /**
      * Test of Sec-WebSocket-Protocol, using all lowercase header
+     * @throws Exception on test failure
      */
     @Test
     public void testProtocol_LowercaseHeader() throws Exception
@@ -469,7 +474,7 @@
         URI uri = baseServerUri.resolve("/protocols");
         ProtocolsConfigurator.seenProtocols.set(null);
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addHeader("sec-websocket-protocol: echo, chat, status\r\n");
             client.connect();
@@ -485,6 +490,7 @@
     
     /**
      * Test of Sec-WebSocket-Protocol, using non-spec case header
+     * @throws Exception on test failure
      */
     @Test
     public void testProtocol_AltHeaderCase() throws Exception
@@ -492,7 +498,7 @@
         URI uri = baseServerUri.resolve("/protocols");
         ProtocolsConfigurator.seenProtocols.set(null);
 
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.addHeader("Sec-Websocket-Protocol: echo, chat, status\r\n");
             client.connect();
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java
deleted file mode 100644
index 1b99a03..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyConnection.java
+++ /dev/null
@@ -1,162 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server;
-
-import java.net.InetSocketAddress;
-import java.util.concurrent.Executor;
-
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.BatchMode;
-import org.eclipse.jetty.websocket.api.SuspendToken;
-import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.api.extensions.Frame;
-import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
-import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
-import org.eclipse.jetty.websocket.common.io.IOState;
-
-public class DummyConnection implements LogicalConnection
-{
-    private static final Logger LOG = Log.getLogger(DummyConnection.class);
-    private IOState iostate;
-
-    public DummyConnection()
-    {
-        this.iostate = new IOState();
-    }
-
-    @Override
-    public void close()
-    {
-    }
-
-    @Override
-    public void close(int statusCode, String reason)
-    {
-    }
-
-    @Override
-    public void disconnect()
-    {
-    }
-
-    @Override
-    public ByteBufferPool getBufferPool()
-    {
-        return null;
-    }
-
-    @Override
-    public Executor getExecutor()
-    {
-        return null;
-    }
-
-    @Override
-    public long getIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public IOState getIOState()
-    {
-        return this.iostate;
-    }
-
-    @Override
-    public InetSocketAddress getLocalAddress()
-    {
-        return null;
-    }
-
-    @Override
-    public long getMaxIdleTimeout()
-    {
-        return 0;
-    }
-
-    @Override
-    public WebSocketPolicy getPolicy()
-    {
-        return null;
-    }
-
-    @Override
-    public InetSocketAddress getRemoteAddress()
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public WebSocketSession getSession()
-    {
-        return null;
-    }
-
-    @Override
-    public boolean isOpen()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean isReading()
-    {
-        return false;
-    }
-
-    @Override
-    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
-    {
-        callback.writeSuccess();
-    }
-
-    @Override
-    public void resume()
-    {
-    }
-
-    @Override
-    public void setMaxIdleTimeout(long ms)
-    {
-    }
-
-    @Override
-    public void setNextIncomingFrames(IncomingFrames incoming)
-    {
-        if (LOG.isDebugEnabled())
-            LOG.debug("setNextIncomingFrames({})",incoming);
-    }
-
-    @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
-    public SuspendToken suspend()
-    {
-        return null;
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyCreator.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyCreator.java
index e7e4914..eb92738 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyCreator.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/DummyCreator.java
@@ -18,9 +18,9 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import org.eclipse.jetty.http.pathmap.PathMappings;
+import org.eclipse.jetty.http.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
 
 public class DummyCreator implements MappedWebSocketCreator
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java
index a8ea544..3eda083 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/IdleTimeoutTest.java
@@ -18,6 +18,10 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
 import java.io.IOException;
 import java.net.URI;
 import java.util.Queue;
@@ -42,10 +46,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
 public class IdleTimeoutTest
 {
     private static final Logger LOG = Log.getLogger(IdleTimeoutTest.class);
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java
index 0d0134c..876dc77 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java
@@ -48,6 +48,6 @@
 
         ServerEndpointConfig.Configurator configr = iter.next();
         assertThat("Configurator",configr,notNullValue());
-        assertThat("COnfigurator type",configr,instanceOf(BasicServerEndpointConfigurator.class));
+        assertThat("Configurator type",configr,instanceOf(ContainerDefaultConfigurator.class));
     }
 }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JsrBatchModeTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JsrBatchModeTest.java
index 84e7aab..4f2c90b 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JsrBatchModeTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JsrBatchModeTest.java
@@ -22,6 +22,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.ClientEndpointConfig;
 import javax.websocket.ContainerProvider;
 import javax.websocket.Endpoint;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/MemoryUsageTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/MemoryUsageTest.java
index 6118b5c..6ecbb2c 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/MemoryUsageTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/MemoryUsageTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.lessThan;
 
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
@@ -114,8 +114,8 @@
         long heapUsed = heapAfter.getUsed() - heapBefore.getUsed();
         long nonHeapUsed = nonHeapAfter.getUsed() - nonHeapBefore.getUsed();
 
-//        System.out.println("heapUsed = " + heapUsed);
-//        System.out.println("nonHeapUsed = " + nonHeapUsed);
+        System.out.println("heapUsed = " + heapUsed);
+        System.out.println("nonHeapUsed = " + nonHeapUsed);
 //        new CountDownLatch(1).await();
 
         // Assume no more than 25 KiB per session pair (client and server).
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
index c89ed26..e8bb104 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
@@ -18,9 +18,13 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
+
 import javax.websocket.server.ServerEndpoint;
 import javax.websocket.server.ServerEndpointConfig;
 
@@ -31,6 +35,9 @@
 import org.eclipse.jetty.websocket.common.events.EventDriverImpl;
 import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.test.DummyConnection;
 import org.eclipse.jetty.websocket.jsr356.ClientContainer;
 import org.eclipse.jetty.websocket.jsr356.JsrSession;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
@@ -41,9 +48,6 @@
 import org.junit.Test;
 import org.junit.rules.TestName;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-
 public class OnPartialTest
 {
     @Rule
@@ -65,8 +69,11 @@
         Class<?> endpoint = websocket.getClass();
         ServerEndpoint anno = endpoint.getAnnotation(ServerEndpoint.class);
         Assert.assertThat("Endpoint: " + endpoint + " should be annotated with @ServerEndpoint",anno,notNullValue());
-        ServerEndpointConfig config = new BasicServerEndpointConfig(endpoint,"/");
-        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(endpoint,config);
+        
+        WebSocketContainerScope containerScope = new SimpleContainerScope(policy);
+        
+        ServerEndpointConfig config = new BasicServerEndpointConfig(containerScope,endpoint,"/");
+        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(containerScope,endpoint,config);
         AnnotatedEndpointScanner<ServerEndpoint, ServerEndpointConfig> scanner = new AnnotatedEndpointScanner<>(metadata);
         scanner.scan();
         EndpointInstance ei = new EndpointInstance(websocket,config,metadata);
@@ -79,7 +86,7 @@
         DummyConnection connection = new DummyConnection();
         ClientContainer container = new ClientContainer();
         @SuppressWarnings("resource")
-        JsrSession session = new JsrSession(requestURI,driver,connection,container,id);
+        JsrSession session = new JsrSession(container,id,requestURI,driver,connection);
         session.setPolicy(policy);
         session.open();
         return driver;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/PingPongTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/PingPongTest.java
index 7e4d8fb..9423b1f 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/PingPongTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/PingPongTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
 
 import java.io.File;
 import java.net.URI;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_GoodSignaturesTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_GoodSignaturesTest.java
index c00362a..491846b 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_GoodSignaturesTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_GoodSignaturesTest.java
@@ -34,6 +34,9 @@
 import javax.websocket.server.ServerEndpoint;
 import javax.websocket.server.ServerEndpointConfig;
 
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
 import org.eclipse.jetty.websocket.jsr356.annotations.JsrCallable;
 import org.eclipse.jetty.websocket.jsr356.server.samples.BasicBinaryMessageByteBufferSocket;
@@ -182,7 +185,8 @@
     @Test
     public void testScan_Basic() throws Exception
     {
-        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(testcase.pojo,null);
+        WebSocketContainerScope container = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(container,testcase.pojo,null);
         AnnotatedEndpointScanner<ServerEndpoint, ServerEndpointConfig> scanner = new AnnotatedEndpointScanner<>(metadata);
         scanner.scan();
 
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_InvalidSignaturesTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_InvalidSignaturesTest.java
index 2260b28..29a31e1 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_InvalidSignaturesTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ServerAnnotatedEndpointScanner_InvalidSignaturesTest.java
@@ -18,10 +18,13 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.containsString;
+
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+
 import javax.websocket.DeploymentException;
 import javax.websocket.OnClose;
 import javax.websocket.OnError;
@@ -31,7 +34,10 @@
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
 import org.eclipse.jetty.websocket.jsr356.server.samples.InvalidCloseIntSocket;
 import org.eclipse.jetty.websocket.jsr356.server.samples.InvalidErrorErrorSocket;
@@ -46,8 +52,6 @@
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
-import static org.hamcrest.Matchers.containsString;
-
 /**
  * Test {@link AnnotatedEndpointScanner} against various simple, 1 method {@link ServerEndpoint} annotated classes with invalid signatures.
  */
@@ -93,7 +97,8 @@
     @Test
     public void testScan_InvalidSignature() throws DeploymentException
     {
-        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(pojo,null);
+        WebSocketContainerScope container = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+        AnnotatedServerEndpointMetadata metadata = new AnnotatedServerEndpointMetadata(container,pojo,null);
         AnnotatedEndpointScanner<ServerEndpoint,ServerEndpointConfig> scanner = new AnnotatedEndpointScanner<>(metadata);
 
         try
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java
index d539635..76e1f47 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.net.URI;
 import java.util.ArrayList;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/StreamTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/StreamTest.java
index e4f062f..4b59658 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/StreamTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/StreamTest.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.equalToIgnoringCase;
+import static org.hamcrest.Matchers.is;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -25,13 +28,9 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import javax.websocket.ClientEndpoint;
 import javax.websocket.CloseReason;
@@ -60,7 +59,7 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
-import org.eclipse.jetty.websocket.common.util.Hex;
+import org.eclipse.jetty.websocket.common.util.Sha1Sum;
 import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -68,9 +67,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.equalToIgnoringCase;
-import static org.hamcrest.Matchers.is;
-
 public class StreamTest
 {
     private static final Logger LOG = Log.getLogger(StreamTest.class);
@@ -176,33 +172,12 @@
         Assert.assertThat("Path should exist: " + file,file.exists(),is(true));
         Assert.assertThat("Path should not be a directory:" + file,file.isDirectory(),is(false));
 
-        String expectedSha1 = loadExpectedSha1Sum(sha1File);
-        String actualSha1 = calculateSha1Sum(file);
+        String expectedSha1 = Sha1Sum.loadSha1(sha1File);
+        String actualSha1 = Sha1Sum.calculate(file);
 
         Assert.assertThat("SHA1Sum of content: " + file,expectedSha1,equalToIgnoringCase(actualSha1));
     }
 
-    private String calculateSha1Sum(File file) throws IOException, NoSuchAlgorithmException
-    {
-        MessageDigest digest = MessageDigest.getInstance("SHA1");
-        try (FileInputStream fis = new FileInputStream(file);
-                NoOpOutputStream noop = new NoOpOutputStream();
-                DigestOutputStream digester = new DigestOutputStream(noop,digest))
-        {
-            IO.copy(fis,digester);
-            return Hex.asHex(digest.digest());
-        }
-    }
-
-    private String loadExpectedSha1Sum(File sha1File) throws IOException
-    {
-        String contents = IO.readToString(sha1File);
-        Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
-        Matcher mat = pat.matcher(contents);
-        Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
-        return mat.group();
-    }
-
     @ClientEndpoint
     public static class ClientSocket
     {
@@ -317,32 +292,4 @@
             t.printStackTrace(System.err);
         }
     }
-
-    private static class NoOpOutputStream extends OutputStream
-    {
-        @Override
-        public void write(byte[] b) throws IOException
-        {
-        }
-
-        @Override
-        public void write(byte[] b, int off, int len) throws IOException
-        {
-        }
-
-        @Override
-        public void flush() throws IOException
-        {
-        }
-
-        @Override
-        public void close() throws IOException
-        {
-        }
-
-        @Override
-        public void write(int b) throws IOException
-        {
-        }
-    }
 }
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java
index 2d05c27..6f1b3ad 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TextStreamTest.java
@@ -25,6 +25,7 @@
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.ClientEndpoint;
 import javax.websocket.ContainerProvider;
 import javax.websocket.OnMessage;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TrackingSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TrackingSocket.java
index 0984f85..14bfb38 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TrackingSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/TrackingSocket.java
@@ -18,8 +18,13 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+
 import javax.websocket.CloseReason;
 import javax.websocket.CloseReason.CloseCode;
 
@@ -28,10 +33,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-
 /**
  * Abstract base socket used for tracking state and events within the socket for testing reasons.
  */
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
index e974ea7..126d9f8 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.jsr356.server;
 
+import static org.hamcrest.Matchers.notNullValue;
+
 import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
@@ -47,8 +49,6 @@
 import org.eclipse.jetty.webapp.WebXmlConfiguration;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.notNullValue;
-
 /**
  * Utility to build out exploded directory WebApps, in the /target/tests/ directory, for testing out servers that use javax.websocket endpoints.
  * <p>
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserSocket.java
index f179e25..3b17bdb 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserSocket.java
@@ -23,6 +23,7 @@
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.Random;
+
 import javax.websocket.CloseReason;
 import javax.websocket.OnClose;
 import javax.websocket.OnMessage;
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java
deleted file mode 100644
index 0cad822..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server.pathmap;
-
-import static org.hamcrest.Matchers.notNullValue;
-
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
-import org.eclipse.jetty.websocket.server.pathmap.ServletPathSpec;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PathMappingsTest
-{
-    private void assertMatch(PathMappings<String> pathmap, String path, String expectedValue)
-    {
-        String msg = String.format(".getMatch(\"%s\")",path);
-        MappedResource<String> match = pathmap.getMatch(path);
-        Assert.assertThat(msg,match,notNullValue());
-        String actualMatch = match.getResource();
-        Assert.assertEquals(msg,expectedValue,actualMatch);
-    }
-
-    public void dumpMappings(PathMappings<String> p)
-    {
-        for (MappedResource<String> res : p)
-        {
-            System.out.printf("  %s%n",res);
-        }
-    }
-
-    /**
-     * Test the match order rules with a mixed Servlet and WebSocket path specs
-     * <p>
-     * <ul>
-     * <li>Exact match</li>
-     * <li>Longest prefix match</li>
-     * <li>Longest suffix match</li>
-     * </ul>
-     */
-    @Test
-    public void testMixedMatchOrder()
-    {
-        PathMappings<String> p = new PathMappings<>();
-
-        p.put(new ServletPathSpec("/"),"default");
-        p.put(new ServletPathSpec("/animal/bird/*"),"birds");
-        p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
-        p.put(new ServletPathSpec("/animal/*"),"animals");
-        p.put(new WebSocketPathSpec("/animal/{type}/{name}/chat"),"animalChat");
-        p.put(new WebSocketPathSpec("/animal/{type}/{name}/cam"),"animalCam");
-        p.put(new WebSocketPathSpec("/entrance/cam"),"entranceCam");
-
-        // dumpMappings(p);
-
-        assertMatch(p,"/animal/bird/eagle","birds");
-        assertMatch(p,"/animal/fish/bass/sea","fishes");
-        assertMatch(p,"/animal/peccary/javalina/evolution","animals");
-        assertMatch(p,"/","default");
-        assertMatch(p,"/animal/bird/eagle/chat","animalChat");
-        assertMatch(p,"/animal/bird/penguin/chat","animalChat");
-        assertMatch(p,"/animal/fish/trout/cam","animalCam");
-        assertMatch(p,"/entrance/cam","entranceCam");
-    }
-
-    /**
-     * Test the match order rules imposed by the WebSocket API (JSR-356)
-     * <p>
-     * <ul>
-     * <li>Exact match</li>
-     * <li>Longest prefix match</li>
-     * <li>Longest suffix match</li>
-     * </ul>
-     */
-    @Test
-    public void testWebsocketMatchOrder()
-    {
-        PathMappings<String> p = new PathMappings<>();
-
-        p.put(new WebSocketPathSpec("/a/{var}/c"),"endpointA");
-        p.put(new WebSocketPathSpec("/a/b/c"),"endpointB");
-        p.put(new WebSocketPathSpec("/a/{var1}/{var2}"),"endpointC");
-        p.put(new WebSocketPathSpec("/{var1}/d"),"endpointD");
-        p.put(new WebSocketPathSpec("/b/{var2}"),"endpointE");
-
-        // dumpMappings(p);
-
-        assertMatch(p,"/a/b/c","endpointB");
-        assertMatch(p,"/a/d/c","endpointA");
-        assertMatch(p,"/a/x/y","endpointC");
-
-        assertMatch(p,"/b/d","endpointE");
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecBadSpecsTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecBadSpecsTest.java
deleted file mode 100644
index 1ec6ee8..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecBadSpecsTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server.pathmap;
-
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Tests for bad path specs on ServerEndpoint Path Param / URI Template
- */
-@RunWith(Parameterized.class)
-public class WebSocketPathSpecBadSpecsTest
-{
-    private static void bad(List<String[]> data, String str)
-    {
-        data.add(new String[]
-        { str });
-    }
-
-    @Parameters
-    public static Collection<String[]> data()
-    {
-        List<String[]> data = new ArrayList<>();
-        bad(data,"/a/b{var}"); // bad syntax - variable does not encompass whole path segment
-        bad(data,"a/{var}"); // bad syntax - no start slash
-        bad(data,"/a/{var/b}"); // path segment separator in variable name
-        bad(data,"/{var}/*"); // bad syntax - no globs allowed
-        bad(data,"/{var}.do"); // bad syntax - variable does not encompass whole path segment
-        bad(data,"/a/{var*}"); // use of glob character not allowed in variable name
-        bad(data,"/a/{}"); // bad syntax - no variable name
-        // MIGHT BE ALLOWED bad(data,"/a/{---}"); // no alpha in variable name
-        bad(data,"{var}"); // bad syntax - no start slash
-        bad(data,"/a/{my special variable}"); // bad syntax - space in variable name
-        bad(data,"/a/{var}/{var}"); // variable name duplicate
-        // MIGHT BE ALLOWED bad(data,"/a/{var}/{Var}/{vAR}"); // variable name duplicated (diff case)
-        bad(data,"/a/../../../{var}"); // path navigation not allowed
-        bad(data,"/a/./{var}"); // path navigation not allowed
-        bad(data,"/a//{var}"); // bad syntax - double path slash (no path segment)
-        return data;
-    }
-
-    private String pathSpec;
-
-    public WebSocketPathSpecBadSpecsTest(String pathSpec)
-    {
-        this.pathSpec = pathSpec;
-    }
-
-    @Test
-    public void testBadPathSpec()
-    {
-        try
-        {
-            new WebSocketPathSpec(this.pathSpec);
-            fail("Expected IllegalArgumentException for a bad PathParam pathspec on: " + pathSpec);
-        }
-        catch (IllegalArgumentException e)
-        {
-            // expected path
-            System.out.println(e.getMessage());
-        }
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java
deleted file mode 100644
index 2ff81fd..0000000
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java
+++ /dev/null
@@ -1,286 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.jsr356.server.pathmap;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.util.Map;
-
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpecGroup;
-import org.junit.Test;
-
-/**
- * Tests for ServerEndpoint Path Param / URI Template Path Specs
- */
-public class WebSocketPathSpecTest
-{
-    private void assertDetectedVars(WebSocketPathSpec spec, String... expectedVars)
-    {
-        String prefix = String.format("Spec(\"%s\")",spec.getPathSpec());
-        assertEquals(prefix + ".variableCount",expectedVars.length,spec.getVariableCount());
-        assertEquals(prefix + ".variable.length",expectedVars.length,spec.getVariables().length);
-        for (int i = 0; i < expectedVars.length; i++)
-        {
-            assertEquals(String.format("%s.variable[%d]",prefix,i),expectedVars[i],spec.getVariables()[i]);
-        }
-    }
-
-    private void assertMatches(PathSpec spec, String path)
-    {
-        String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(true));
-    }
-
-    private void assertNotMatches(PathSpec spec, String path)
-    {
-        String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(false));
-    }
-
-    @Test
-    public void testDefaultPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/");
-        assertEquals("Spec.pathSpec","/",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",1,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup());
-
-        assertEquals("Spec.variableCount",0,spec.getVariableCount());
-        assertEquals("Spec.variable.length",0,spec.getVariables().length);
-    }
-
-    @Test
-    public void testExactOnePathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a");
-        assertEquals("Spec.pathSpec","/a",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",1,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup());
-        
-        assertMatches(spec,"/a");
-        assertMatches(spec,"/a?type=other");
-        assertNotMatches(spec,"/a/b");
-        assertNotMatches(spec,"/a/");
-
-        assertEquals("Spec.variableCount",0,spec.getVariableCount());
-        assertEquals("Spec.variable.length",0,spec.getVariables().length);
-    }
-    
-    @Test
-    public void testExactPathSpec_TestWebapp()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/javax.websocket/");
-        assertEquals("Spec.pathSpec","/javax.websocket/",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/javax\\.websocket/$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",1,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup());
-        
-        assertMatches(spec,"/javax.websocket/");
-        assertNotMatches(spec,"/javax.websocket");
-
-        assertEquals("Spec.variableCount",0,spec.getVariableCount());
-        assertEquals("Spec.variable.length",0,spec.getVariables().length);
-    }
-    
-    @Test
-    public void testExactTwoPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a/b");
-        assertEquals("Spec.pathSpec","/a/b",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/b$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",2,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup());
-
-        assertEquals("Spec.variableCount",0,spec.getVariableCount());
-        assertEquals("Spec.variable.length",0,spec.getVariables().length);
-
-        assertMatches(spec,"/a/b");
-
-        assertNotMatches(spec,"/a/b/");
-        assertNotMatches(spec,"/a/");
-        assertNotMatches(spec,"/a/bb");
-    }
-
-    @Test
-    public void testMiddleVarPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a/{var}/c");
-        assertEquals("Spec.pathSpec","/a/{var}/c",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/([^/]+)/c$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",3,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var");
-
-        assertMatches(spec,"/a/b/c");
-        assertMatches(spec,"/a/zz/c");
-        assertMatches(spec,"/a/hello+world/c");
-        assertNotMatches(spec,"/a/bc");
-        assertNotMatches(spec,"/a/b/");
-        assertNotMatches(spec,"/a/b");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b/c");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(1));
-        assertEquals("Spec.pathParams[var]","b",mapped.get("var"));
-    }
-
-    @Test
-    public void testOneVarPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a/{foo}");
-        assertEquals("Spec.pathSpec","/a/{foo}",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/([^/]+)$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",2,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"foo");
-
-        assertMatches(spec,"/a/b");
-        assertNotMatches(spec,"/a/");
-        assertNotMatches(spec,"/a");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(1));
-        assertEquals("Spec.pathParams[foo]","b",mapped.get("foo"));
-    }
-
-    @Test
-    public void testOneVarSuffixPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/{var}/b/c");
-        assertEquals("Spec.pathSpec","/{var}/b/c",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/([^/]+)/b/c$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",3,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.SUFFIX_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var");
-
-        assertMatches(spec,"/a/b/c");
-        assertMatches(spec,"/az/b/c");
-        assertMatches(spec,"/hello+world/b/c");
-        assertNotMatches(spec,"/a/bc");
-        assertNotMatches(spec,"/a/b/");
-        assertNotMatches(spec,"/a/b");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b/c");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(1));
-        assertEquals("Spec.pathParams[var]","a",mapped.get("var"));
-    }
-
-    @Test
-    public void testTwoVarComplexInnerPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a/{var1}/c/{var2}/e");
-        assertEquals("Spec.pathSpec","/a/{var1}/c/{var2}/e",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/([^/]+)/c/([^/]+)/e$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",5,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var1","var2");
-
-        assertMatches(spec,"/a/b/c/d/e");
-        assertNotMatches(spec,"/a/bc/d/e");
-        assertNotMatches(spec,"/a/b/d/e");
-        assertNotMatches(spec,"/a/b//d/e");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b/c/d/e");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(2));
-        assertEquals("Spec.pathParams[var1]","b",mapped.get("var1"));
-        assertEquals("Spec.pathParams[var2]","d",mapped.get("var2"));
-    }
-
-    @Test
-    public void testTwoVarComplexOuterPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/{var1}/b/{var2}/{var3}");
-        assertEquals("Spec.pathSpec","/{var1}/b/{var2}/{var3}",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/([^/]+)/b/([^/]+)/([^/]+)$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",4,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var1","var2","var3");
-
-        assertMatches(spec,"/a/b/c/d");
-        assertNotMatches(spec,"/a/bc/d/e");
-        assertNotMatches(spec,"/a/c/d/e");
-        assertNotMatches(spec,"/a//d/e");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b/c/d");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(3));
-        assertEquals("Spec.pathParams[var1]","a",mapped.get("var1"));
-        assertEquals("Spec.pathParams[var2]","c",mapped.get("var2"));
-        assertEquals("Spec.pathParams[var3]","d",mapped.get("var3"));
-    }
-
-    @Test
-    public void testTwoVarPrefixPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/a/{var1}/{var2}");
-        assertEquals("Spec.pathSpec","/a/{var1}/{var2}",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/([^/]+)/([^/]+)$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",3,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var1","var2");
-
-        assertMatches(spec,"/a/b/c");
-        assertNotMatches(spec,"/a/bc");
-        assertNotMatches(spec,"/a/b/");
-        assertNotMatches(spec,"/a/b");
-
-        Map<String, String> mapped = spec.getPathParams("/a/b/c");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(2));
-        assertEquals("Spec.pathParams[var1]","b",mapped.get("var1"));
-        assertEquals("Spec.pathParams[var2]","c",mapped.get("var2"));
-    }
-
-    @Test
-    public void testVarOnlyPathSpec()
-    {
-        WebSocketPathSpec spec = new WebSocketPathSpec("/{var1}");
-        assertEquals("Spec.pathSpec","/{var1}",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/([^/]+)$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",1,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup());
-
-        assertDetectedVars(spec,"var1");
-
-        assertMatches(spec,"/a");
-        assertNotMatches(spec,"/");
-        assertNotMatches(spec,"/a/b");
-        assertNotMatches(spec,"/a/b/c");
-
-        Map<String, String> mapped = spec.getPathParams("/a");
-        assertThat("Spec.pathParams",mapped,notNullValue());
-        assertThat("Spec.pathParams.size",mapped.size(),is(1));
-        assertEquals("Spec.pathParams[var1]","a",mapped.get("var1"));
-    }
-}
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidCloseIntSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidCloseIntSocket.java
index 02e68e2..571213f 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidCloseIntSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidCloseIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Close Method Declaration (parameter type int)
+     * @param statusCode the status code
      */
     @OnClose
     public void onClose(int statusCode)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorErrorSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorErrorSocket.java
index c3b36ad..f8f78f0 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorErrorSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorErrorSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type Error)
+     * @param error the error
      */
     @OnError
     public void onError(Error error)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorExceptionSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorExceptionSocket.java
index 83c8491..3db16e4 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorExceptionSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorExceptionSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type Exception)
+     * @param e the exception
      */
     @OnError
     public void onError(Exception e)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorIntSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorIntSocket.java
index 48a3c64..69ffc07 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorIntSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidErrorIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Error Method Declaration (parameter type int)
+     * @param errorCount the error count
      */
     @OnError
     public void onError(int errorCount)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenCloseReasonSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenCloseReasonSocket.java
index 677cf7a..1a272e7 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenCloseReasonSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenCloseReasonSocket.java
@@ -29,6 +29,7 @@
 {
     /**
      * Invalid Open Method Declaration (parameter type CloseReason)
+     * @param reason the close reason
      */
     @OnOpen
     public void onOpen(CloseReason reason)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenIntSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenIntSocket.java
index fd07fb4..4e76221 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenIntSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenIntSocket.java
@@ -28,6 +28,7 @@
 {
     /**
      * Invalid Open Method Declaration (parameter type int)
+     * @param value the value
      */
     @OnOpen
     public void onOpen(int value)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenSessionIntSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenSessionIntSocket.java
index 6c906b8..df892b2 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenSessionIntSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/InvalidOpenSessionIntSocket.java
@@ -29,6 +29,8 @@
 {
     /**
      * Invalid Open Method Declaration (parameter of type int)
+     * @param session the sesion
+     * @param count the count
      */
     @OnOpen
     public void onOpen(Session session, int count)
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java
index c56585a..6b2a6b3 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java
@@ -25,7 +25,7 @@
 import javax.websocket.server.ServerEndpointConfig;
 
 /**
- * Example of adding a server WebSocket (extending {@link Endpoint}) programmatically via config
+ * Example of adding a server WebSocket (extending {@link javax.websocket.Endpoint}) programmatically via config
  */
 public class BasicEchoEndpointConfigContextListener implements ServletContextListener
 {
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java
index 83f4568..b40e9fb 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java
@@ -27,7 +27,7 @@
 import org.eclipse.jetty.websocket.jsr356.server.samples.pong.PongMessageEndpoint;
 
 /**
- * Example of adding a server WebSocket (extending {@link Endpoint}) programmatically directly.
+ * Example of adding a server WebSocket (extending {@link javax.websocket.Endpoint}) programmatically directly.
  * <p>
  * NOTE: this shouldn't work as the endpoint has no path associated with it.
  */
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java
index 9a737f7..0189355 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java
@@ -25,7 +25,7 @@
 import javax.websocket.server.ServerEndpointConfig;
 
 /**
- * Example of adding a server socket (which extends {@link Endpoint}) programmatically via the {@link ServerContainer#addEndpoint(ServerEndpointConfig)}
+ * Example of adding a server socket (which extends {@link javax.websocket.Endpoint}) programmatically via the {@link ServerContainer#addEndpoint(ServerEndpointConfig)}
  */
 public class BasicEchoSocketConfigContextListener implements ServletContextListener
 {
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoDefaultSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoDefaultSocket.java
index b9d1b45..33e18ea 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoDefaultSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoDefaultSocket.java
@@ -20,6 +20,7 @@
 
 import javax.websocket.OnMessage;
 import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
 import javax.websocket.server.ServerEndpoint;
 
 /**
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/idletimeout/IdleTimeoutContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/idletimeout/IdleTimeoutContextListener.java
index a747a93..96442cc 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/idletimeout/IdleTimeoutContextListener.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/idletimeout/IdleTimeoutContextListener.java
@@ -25,7 +25,7 @@
 import javax.websocket.server.ServerEndpointConfig;
 
 /**
- * Example of adding a server WebSocket (extending {@link Endpoint}) programmatically via config
+ * Example of adding a server WebSocket (extending {@link javax.websocket.Endpoint}) programmatically via config
  */
 public class IdleTimeoutContextListener implements ServletContextListener
 {
diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/pong/PongSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/pong/PongSocket.java
index 60b0431..4b30851 100644
--- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/pong/PongSocket.java
+++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/pong/PongSocket.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.websocket.jsr356.server.samples.pong;
 
 import java.nio.charset.StandardCharsets;
+
 import javax.websocket.EndpointConfig;
 import javax.websocket.OnMessage;
 import javax.websocket.OnOpen;
diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml
index 054a2bf..cc57deb 100644
--- a/jetty-websocket/pom.xml
+++ b/jetty-websocket/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <artifactId>jetty-project</artifactId>
         <groupId>org.eclipse.jetty</groupId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -33,34 +33,6 @@
                 </configuration>
             </plugin>
             <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>manifest</goal>
-                        </goals>
-                        <configuration>
-                            <instructions>
-                                <Export-Package>${bundle-symbolic-name}.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
-                                <Import-Package>javax.servlet.*;version="[3.1,4.0)",org.eclipse.jetty.*;version="[9.0,10.0)",*</Import-Package>
-                                <_nouses>true</_nouses>
-                            </instructions>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <configuration>
-                    <archive>
-                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-                    </archive>
-                </configuration>
-            </plugin>
-            <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>clirr-maven-plugin</artifactId>
                 <version>2.5</version>
diff --git a/jetty-websocket/websocket-api/pom.xml b/jetty-websocket/websocket-api/pom.xml
index 425cab0..79cadd1 100644
--- a/jetty-websocket/websocket-api/pom.xml
+++ b/jetty-websocket/websocket-api/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.websocket</groupId>
         <artifactId>websocket-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/BatchMode.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/BatchMode.java
index af49f42..cbd4c92 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/BatchMode.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/BatchMode.java
@@ -18,8 +18,10 @@
 
 package org.eclipse.jetty.websocket.api;
 
+import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
+
 /**
- * The possible batch modes when invoking {@link OutgoingFrames#outgoingFrame(Frame, WriteCallback, BatchMode)}.
+ * The possible batch modes when invoking {@link OutgoingFrames#outgoingFrame(org.eclipse.jetty.websocket.api.extensions.Frame, WriteCallback, BatchMode)}.
  */
 public enum BatchMode
 {
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/InvalidWebSocketException.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/InvalidWebSocketException.java
index 1f6acc8..a67d5db 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/InvalidWebSocketException.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/InvalidWebSocketException.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.api;
 
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
+
 /**
  * Indicating that the provided Class is not a valid WebSocket as defined by the API.
  * <p>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/RemoteEndpoint.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/RemoteEndpoint.java
index 6a10d8b..a4b2f2d 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/RemoteEndpoint.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/RemoteEndpoint.java
@@ -31,11 +31,14 @@
      * 
      * @param data
      *            the message to be sent
+     * @throws IOException
+     *             if unable to send the bytes
      */
     void sendBytes(ByteBuffer data) throws IOException;
 
     /**
-     * Initiates the asynchronous transmission of a binary message. This method returns before the message is transmitted. Developers may use the returned
+     * Initiates the asynchronous transmission of a binary message. This method returns before the message is
+     * transmitted. Developers may use the returned
      * Future object to track progress of the transmission.
      * 
      * @param data
@@ -45,7 +48,8 @@
     Future<Void> sendBytesByFuture(ByteBuffer data);
 
     /**
-     * Initiates the asynchronous transmission of a binary message. This method returns before the message is transmitted. Developers may provide a callback to
+     * Initiates the asynchronous transmission of a binary message. This method returns before the message is
+     * transmitted. Developers may provide a callback to
      * be notified when the message has been transmitted or resulted in an error.
      * 
      * @param data
@@ -56,38 +60,54 @@
     void sendBytes(ByteBuffer data, WriteCallback callback);
 
     /**
-     * Send a binary message in pieces, blocking until all of the message has been transmitted. The runtime reads the message in order. Non-final pieces are
+     * Send a binary message in pieces, blocking until all of the message has been transmitted. The runtime reads the
+     * message in order. Non-final pieces are
      * sent with isLast set to false. The final piece must be sent with isLast set to true.
      * 
      * @param fragment
      *            the piece of the message being sent
+     * @param isLast
+     *            true if this is the last piece of the partial bytes
+     * @throws IOException
+     *             if unable to send the partial bytes
      */
     void sendPartialBytes(ByteBuffer fragment, boolean isLast) throws IOException;
 
     /**
-     * Send a text message in pieces, blocking until all of the message has been transmitted. The runtime reads the message in order. Non-final pieces are sent
+     * Send a text message in pieces, blocking until all of the message has been transmitted. The runtime reads the
+     * message in order. Non-final pieces are sent
      * with isLast set to false. The final piece must be sent with isLast set to true.
      * 
      * @param fragment
      *            the piece of the message being sent
+     * @param isLast
+     *            true if this is the last piece of the partial bytes
+     * @throws IOException
+     *             if unable to send the partial bytes
      */
     void sendPartialString(String fragment, boolean isLast) throws IOException;
 
     /**
-     * Send a Ping message containing the given application data to the remote endpoint. The corresponding Pong message may be picked up using the
+     * Send a Ping message containing the given application data to the remote endpoint. The corresponding Pong message
+     * may be picked up using the
      * MessageHandler.Pong handler.
      * 
      * @param applicationData
      *            the data to be carried in the ping request
+     * @throws IOException
+     *             if unable to send the ping
      */
     void sendPing(ByteBuffer applicationData) throws IOException;
 
     /**
-     * Allows the developer to send an unsolicited Pong message containing the given application data in order to serve as a unidirectional heartbeat for the
+     * Allows the developer to send an unsolicited Pong message containing the given application data in order to serve
+     * as a unidirectional heartbeat for the
      * session.
      * 
      * @param applicationData
      *            the application data to be carried in the pong response.
+     * @throws IOException
+     *             if unable to send the pong
      */
     void sendPong(ByteBuffer applicationData) throws IOException;
 
@@ -98,11 +118,14 @@
      * 
      * @param text
      *            the message to be sent
+     * @throws IOException
+     *             if unable to send the text message
      */
     void sendString(String text) throws IOException;
 
     /**
-     * Initiates the asynchronous transmission of a text message. This method may return before the message is transmitted. Developers may use the returned
+     * Initiates the asynchronous transmission of a text message. This method may return before the message is
+     * transmitted. Developers may use the returned
      * Future object to track progress of the transmission.
      * 
      * @param text
@@ -112,7 +135,8 @@
     Future<Void> sendStringByFuture(String text);
 
     /**
-     * Initiates the asynchronous transmission of a text message. This method may return before the message is transmitted. Developers may provide a callback to
+     * Initiates the asynchronous transmission of a text message. This method may return before the message is
+     * transmitted. Developers may provide a callback to
      * be notified when the message has been transmitted or resulted in an error.
      * 
      * @param text
@@ -139,7 +163,9 @@
     
     /**
      * Flushes messages that may have been batched by the implementation.
-     * @throws IOException if the flush fails
+     * 
+     * @throws IOException
+     *             if the flush fails
      * @see #getBatchMode()
      */
     void flush() throws IOException;
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/Session.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/Session.java
index dea71d6..9c16c7b 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/Session.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/Session.java
@@ -22,9 +22,10 @@
 import java.io.IOException;
 import java.net.InetSocketAddress;
 
+import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
+
 /**
  * Session represents an active link of communications with a Remote WebSocket Endpoint.
- * <p>
  */
 public interface Session extends Closeable
 {
@@ -80,7 +81,11 @@
      * Once called, any read/write activity on the websocket from this point will be indeterminate.
      * <p>
      * Once the underlying connection has been determined to be closed, the various onClose() events (either
-     * {@link WebSocketListener#onWebSocketClose(int, String)} or {@link OnWebSocketClose}) will be called on your websocket.
+     * {@link WebSocketListener#onWebSocketClose(int, String)} or {@link OnWebSocketClose}) will be called on your
+     * websocket.
+     * 
+     * @throws IOException
+     *             if unable to disconnect
      * 
      * @see #close()
      * @see #close(CloseStatus)
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeResponse.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeResponse.java
index e83aa7d..afdc0a4 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeResponse.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeResponse.java
@@ -136,13 +136,15 @@
     /**
      * Issue a forbidden upgrade response.
      * <p>
-     * This means that the websocket endpoint was valid, but the conditions to use a WebSocket resulted in a forbidden access.
+     * This means that the websocket endpoint was valid, but the conditions to use a WebSocket resulted in a forbidden
+     * access.
      * <p>
      * Use this when the origin or authentication is invalid.
      * 
      * @param message
      *            the short 1 line detail message about the forbidden response
      * @throws IOException
+     *             if unable to send the forbidden
      */
     public void sendForbidden(String message) throws IOException
     {
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java
new file mode 100644
index 0000000..35734d5
--- /dev/null
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketConnectionListener.java
@@ -0,0 +1,61 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.api;
+
+/**
+ * Core WebSocket Connection Listener
+ */
+public interface WebSocketConnectionListener
+{
+    /**
+     * A Close Event was received.
+     * <p>
+     * The underlying Connection will be considered closed at this point.
+     * 
+     * @param statusCode
+     *            the close status code. (See {@link StatusCode})
+     * @param reason
+     *            the optional reason for the close.
+     */
+    void onWebSocketClose(int statusCode, String reason);
+
+    /**
+     * A WebSocket {@link Session} has connected successfully and is ready to be used.
+     * <p>
+     * Note: It is a good idea to track this session as a field in your object so that you can write messages back via the {@link RemoteEndpoint}
+     * 
+     * @param session
+     *            the websocket session.
+     */
+    void onWebSocketConnect(Session session);
+
+    /**
+     * A WebSocket exception has occurred.
+     * <p>
+     * This is a way for the internal implementation to notify of exceptions occured during the processing of websocket.
+     * <p>
+     * Usually this occurs from bad / malformed incoming packets. (example: bad UTF8 data, frames that are too big, violations of the spec)
+     * <p>
+     * This will result in the {@link Session} being closed by the implementing side.
+     * 
+     * @param cause
+     *            the error that occurred.
+     */
+    void onWebSocketError(Throwable cause);
+}
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketFrameListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketFrameListener.java
new file mode 100644
index 0000000..b417867
--- /dev/null
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketFrameListener.java
@@ -0,0 +1,34 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.api;
+
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+
+/**
+ * WebSocket Frame Listener interface for incoming WebSocket frames.
+ */
+public interface WebSocketFrameListener extends WebSocketConnectionListener
+{
+    /**
+     * A WebSocket frame has been received.
+     * 
+     * @param frame the immutable frame received
+     */
+    void onWebSocketFrame(Frame frame);
+}
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java
index 827db96..2710a0b 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketListener.java
@@ -19,9 +19,9 @@
 package org.eclipse.jetty.websocket.api;
 
 /**
- * Basic WebSocket Listener interface for incoming WebSocket events.
+ * Basic WebSocket Listener interface for incoming WebSocket message events.
  */
-public interface WebSocketListener
+public interface WebSocketListener extends WebSocketConnectionListener
 {
     /**
      * A WebSocket binary frame has been received.
@@ -36,45 +36,9 @@
     void onWebSocketBinary(byte payload[], int offset, int len);
 
     /**
-     * A Close Event was received.
-     * <p>
-     * The underlying Connection will be considered closed at this point.
-     * 
-     * @param statusCode
-     *            the close status code. (See {@link StatusCode})
-     * @param reason
-     *            the optional reason for the close.
-     */
-    void onWebSocketClose(int statusCode, String reason);
-
-    /**
-     * A WebSocket {@link Session} has connected successfully and is ready to be used.
-     * <p>
-     * Note: It is a good idea to track this session as a field in your object so that you can write messages back via the {@link RemoteEndpoint}
-     * 
-     * @param session
-     *            the websocket session.
-     */
-    void onWebSocketConnect(Session session);
-
-    /**
-     * A WebSocket exception has occurred.
-     * <p>
-     * This is a way for the internal implementation to notify of exceptions occured during the processing of websocket.
-     * <p>
-     * Usually this occurs from bad / malformed incoming packets. (example: bad UTF8 data, frames that are too big, violations of the spec)
-     * <p>
-     * This will result in the {@link Session} being closed by the implementing side.
-     * 
-     * @param error
-     *            the error that occurred.
-     */
-    void onWebSocketError(Throwable cause);
-
-    /**
      * A WebSocket Text frame was received.
      * 
-     * @param message
+     * @param message the message
      */
     void onWebSocketText(String message);
 }
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java
new file mode 100644
index 0000000..246da10
--- /dev/null
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPartialListener.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.websocket.api;
+
+import java.nio.ByteBuffer;
+
+/**
+ * WebSocket Partial Message Listener interface for incoming WebSocket TEXT/BINARY/CONTINUATION frames.
+ */
+public interface WebSocketPartialListener extends WebSocketConnectionListener
+{
+    /**
+     * A WebSocket BINARY (or associated CONTINUATION) frame has been received.
+     * <p>
+     * <b>Important Note</b>: The payload <code>ByteBuffer</code> cannot be modified, and the ByteBuffer object itself
+     * will be recycled on completion of this method call, make a copy of the data contained within if you want to
+     * retain it between calls.
+     * 
+     * @param payload
+     *            the binary message frame payload
+     * @param fin
+     *            true if this is the final frame, false otherwise
+     */
+    void onWebSocketPartialBinary(ByteBuffer payload, boolean fin);
+
+    /**
+     * A WebSocket TEXT (or associated CONTINUATION) frame has been received.
+     * 
+     * @param payload
+     *            the text message payload
+     *            <p>
+     *            Note that due to framing, there is a above average chance of any UTF8 sequences being split on the
+     *            border between two frames will result in either the previous frame, or the next frame having an
+     *            invalid UTF8 sequence, but the combined frames having a valid UTF8 sequence.
+     *            <p>
+     *            The String being provided here will not end in a split UTF8 sequence. Instead this partial sequence
+     *            will be held over until the next frame is received.
+     * @param fin
+     *            true if this is the final frame, false otherwise
+     */
+    void onWebSocketPartialText(String payload, boolean fin);
+}
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPingPongListener.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPingPongListener.java
new file mode 100644
index 0000000..6a0c894
--- /dev/null
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WebSocketPingPongListener.java
@@ -0,0 +1,43 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.api;
+
+import java.nio.ByteBuffer;
+
+/**
+ * WebSocket PING/PONG Listener interface for incoming WebSocket PING/PONG frames.
+ */
+public interface WebSocketPingPongListener extends WebSocketConnectionListener
+{
+    /**
+     * A WebSocket PING has been received.
+     * 
+     * @param payload
+     *            the ping payload
+     */
+    void onWebSocketPing(ByteBuffer payload);
+
+    /**
+     * A WebSocket PONG has been received.
+     * 
+     * @param payload
+     *            the pong payload
+     */
+    void onWebSocketPong(ByteBuffer payload);
+}
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketClose.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketClose.java
index 0fcd8fc..5305451 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketClose.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketClose.java
@@ -24,6 +24,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.eclipse.jetty.websocket.api.Session;
+
 /**
  * Annotation for tagging methods to receive connection close events.
  * <p>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketConnect.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketConnect.java
index e571177..c99daf7 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketConnect.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketConnect.java
@@ -24,6 +24,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.eclipse.jetty.websocket.api.Session;
+
 /**
  * Annotation for tagging methods to receive connection open events.
  * <p>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketError.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketError.java
index 08335a0..acfb23c 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketError.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketError.java
@@ -24,12 +24,13 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.eclipse.jetty.websocket.api.Session;
+
 /**
  * Annotation for receiving websocket errors (exceptions) that have occurred internally in the websocket implementation.
  * <p>
  * Acceptable method patterns.<br>
  * Note: <code>methodName</code> can be any name you want to use.
- * <p>
  * <ol>
  * <li><code>public void methodName({@link Throwable} error)</code></li>
  * <li><code>public void methodName({@link Session} session, {@link Throwable} error)</code></li>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketFrame.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketFrame.java
index b1011e6..27b0d44 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketFrame.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketFrame.java
@@ -24,14 +24,16 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.eclipse.jetty.websocket.api.Session;
+
 /**
  * (ADVANCED) Annotation for tagging methods to receive frame events.
  * <p>
  * Acceptable method patterns.<br>
  * Note: <code>methodName</code> can be any name you want to use.
  * <ol>
- * <li><code>public void methodName({@link Frame} frame)</code></li>
- * <li><code>public void methodName({@link Session} session, {@link Frame} frame)</code></li>
+ * <li><code>public void methodName({@link org.eclipse.jetty.websocket.api.extensions.Frame} frame)</code></li>
+ * <li><code>public void methodName({@link Session} session, {@link org.eclipse.jetty.websocket.api.extensions.Frame} frame)</code></li>
  * </ol>
  */
 @Documented
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketMessage.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketMessage.java
index bb3ea1a..a9148d4 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketMessage.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/annotations/OnWebSocketMessage.java
@@ -18,12 +18,15 @@
 
 package org.eclipse.jetty.websocket.api.annotations;
 
+import java.io.Reader;
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.eclipse.jetty.websocket.api.Session;
+
 /**
  * Annotation for tagging methods to receive Binary or Text Message events.
  * <p>
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Extension.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Extension.java
index 18a2459..47c60f7 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Extension.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Extension.java
@@ -36,6 +36,7 @@
      * The <code>Sec-WebSocket-Extensions</code> name for this extension.
      * <p>
      * Also known as the <a href="https://tools.ietf.org/html/rfc6455#section-9.1"><code>extension-token</code> per Section 9.1. Negotiating Extensions</a>.
+     * @return the name of the extension
      */
     public String getName();
 
@@ -81,9 +82,4 @@
      *            the next outgoing extension
      */
     public void setNextOutgoingFrames(OutgoingFrames nextOutgoing);
-    
-    // TODO: Extension should indicate if it requires boundary of fragments to be preserved
-    
-    // TODO: Extension should indicate if it uses the Extension data field of frame for its own reasons.
-    
 }
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
index 195401b..d560bcf 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
@@ -128,6 +128,7 @@
 
     /**
      * Copy constructor
+     * @param copy the extension config to copy
      */
     public ExtensionConfig(ExtensionConfig copy)
     {
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Frame.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Frame.java
index 0325cf3..74deefd 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Frame.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/Frame.java
@@ -103,8 +103,9 @@
      * Same as {@link #isFin()}
      * 
      * @return true if final frame.
+     * @deprecated use {@link #isFin()} instead
      */
-    // FIXME: remove
+    @Deprecated
     public boolean isLast();
 
     public boolean isMasked();
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/OutgoingFrames.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/OutgoingFrames.java
index 6916c6d..2a9f392 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/OutgoingFrames.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/OutgoingFrames.java
@@ -28,10 +28,10 @@
 {
     /**
      * A frame, and optional callback, intended for the network layer.
-     * <p/>
+     * <p>
      * Note: the frame can undergo many transformations in the various
      * layers and extensions present in the implementation.
-     * <p/>
+     * <p>
      * If you are implementing a mutation, you are obliged to handle
      * the incoming WriteCallback appropriately.
      *
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
index ca3800b..abc2adb 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/QuoteUtil.java
@@ -27,7 +27,6 @@
  * Provide some consistent Http header value and Extension configuration parameter quoting support.
  * <p>
  * While QuotedStringTokenizer exists in jetty-util, and works great with http header values, using it in websocket-api is undesired.
- * <p>
  * <ul>
  * <li>Using QuotedStringTokenizer would introduce a dependency to jetty-util that would need to be exposed via the WebAppContext classloader</li>
  * <li>ABNF defined extension parameter parsing requirements of RFC-6455 (WebSocket) ABNF, is slightly different than the ABNF parsing defined in RFC-2616
@@ -48,8 +47,6 @@
             QUOTE_DOUBLE
         }
 
-        private static final boolean DEBUG = false;
-
         private final String input;
         private final String delims;
         private StringBuilder token;
@@ -84,14 +81,6 @@
             }
         }
 
-        private void debug(String format, Object... args)
-        {
-            if (DEBUG)
-            {
-                System.out.printf(format,args);
-            }
-        }
-
         @Override
         public boolean hasNext()
         {
@@ -134,7 +123,7 @@
                     {
                         if (delims.indexOf(c) >= 0)
                         {
-                            debug("hasNext/t: %b [%s]%n",hasToken,token);
+                            // System.out.printf("hasNext/t: %b [%s]%n",hasToken,token);
                             return hasToken;
                         }
                         else if (c == '\'')
@@ -193,10 +182,9 @@
                         break;
                     }
                 }
-                debug("%s <%s> : [%s]%n",state,c,token);
+                // System.out.printf("%s <%s> : [%s]%n",state,c,token);
             }
-
-            debug("hasNext/e: %b [%s]%n",hasToken,token);
+            // System.out.printf("hasNext/e: %b [%s]%n",hasToken,token);
             return hasToken;
         }
 
diff --git a/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtilTest.java b/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtilTest.java
index c25b1a1..d1ec440 100644
--- a/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtilTest.java
+++ b/jetty-websocket/websocket-api/src/test/java/org/eclipse/jetty/websocket/api/util/QuoteUtilTest.java
@@ -18,8 +18,8 @@
 
 package org.eclipse.jetty.websocket.api.util;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/jetty-websocket/websocket-client/pom.xml b/jetty-websocket/websocket-client/pom.xml
index 06bf844..98af497 100644
--- a/jetty-websocket/websocket-client/pom.xml
+++ b/jetty-websocket/websocket-client/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.websocket</groupId>
         <artifactId>websocket-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java
index 600e8c7..d0e613e 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeRequest.java
@@ -46,7 +46,6 @@
 public class ClientUpgradeRequest extends UpgradeRequest
 {
     private static final Logger LOG = Log.getLogger(ClientUpgradeRequest.class);
-    private static final int MAX_KEYS = -1; // maximum number of parameter keys to decode
     private static final Set<String> FORBIDDEN_HEADERS;
 
     static
@@ -249,7 +248,7 @@
         if (StringUtil.isNotBlank(query))
         {
             MultiMap<String> params = new MultiMap<String>();
-            UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8,MAX_KEYS);
+            UrlEncoded.decodeTo(uri.getQuery(),params,StandardCharsets.UTF_8);
 
             for (String key : params.keySet())
             {
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeResponse.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeResponse.java
index bbeb3ba..e16ffc4 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeResponse.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/ClientUpgradeResponse.java
@@ -21,11 +21,15 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.UpgradeResponse;
 import org.eclipse.jetty.websocket.common.io.http.HttpResponseHeaderParseListener;
 
 public class ClientUpgradeResponse extends UpgradeResponse implements HttpResponseHeaderParseListener
 {
+    private static final Logger LOG = Log.getLogger(ClientUpgradeResponse.class);
     private ByteBuffer remainingBuffer;
 
     public ClientUpgradeResponse()
@@ -47,6 +51,10 @@
     @Override
     public void setRemainingBuffer(ByteBuffer remainingBuffer)
     {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Saving remaining header: {}",BufferUtil.toDetailString(remainingBuffer));
+        }
         this.remainingBuffer = remainingBuffer;
     }
 }
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
index dc45c27..bdd37a2 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
@@ -22,9 +22,8 @@
 import java.net.CookieStore;
 import java.net.SocketAddress;
 import java.net.URI;
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -33,6 +32,7 @@
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.io.SelectorManager;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
 import org.eclipse.jetty.util.HttpCookieStore;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
@@ -45,7 +45,6 @@
 import org.eclipse.jetty.util.thread.ShutdownThread;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.api.extensions.Extension;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
 import org.eclipse.jetty.websocket.client.io.ConnectPromise;
@@ -60,15 +59,16 @@
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
 import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 
 /**
  * WebSocketClient provides a means of establishing connections to remote websocket endpoints.
  */
-public class WebSocketClient extends ContainerLifeCycle implements SessionListener
+public class WebSocketClient extends ContainerLifeCycle implements SessionListener, WebSocketContainerScope
 {
     private static final Logger LOG = Log.getLogger(WebSocketClient.class);
 
-    private final WebSocketPolicy policy;
+    private final WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
     private final SslContextFactory sslContextFactory;
     private final WebSocketExtensionFactory extensionRegistry;
     private boolean daemon = false;
@@ -76,18 +76,20 @@
     private SessionFactory sessionFactory;
     private ByteBufferPool bufferPool;
     private Executor executor;
+    private DecoratedObjectFactory objectFactory;
     private Scheduler scheduler;
     private CookieStore cookieStore;
     private ConnectionManager connectionManager;
     private Masker masker;
     private SocketAddress bindAddress;
     private long connectTimeout = SelectorManager.DEFAULT_CONNECT_TIMEOUT;
+    private boolean dispatchIO = true;
 
     public WebSocketClient()
     {
-        this(null,null);
+        this((SslContextFactory)null,null);
     }
-
+    
     public WebSocketClient(Executor executor)
     {
         this(null,executor);
@@ -108,28 +110,37 @@
         this(sslContextFactory,executor,new MappedByteBufferPool());
     }
     
+    public WebSocketClient(WebSocketContainerScope scope)
+    {
+        this(scope.getSslContextFactory(), scope.getExecutor(), scope.getBufferPool(), scope.getObjectFactory());
+    }
+    
+    public WebSocketClient(WebSocketContainerScope scope, SslContextFactory sslContextFactory)
+    {
+        this(sslContextFactory, scope.getExecutor(), scope.getBufferPool(), scope.getObjectFactory());
+    }
+
     public WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool)
     {
+        this(sslContextFactory, executor, bufferPool, new DecoratedObjectFactory());
+    }
+
+    public WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory)
+    {
         this.executor = executor;
         this.sslContextFactory = sslContextFactory;
-        this.policy = WebSocketPolicy.newClientPolicy();
         this.bufferPool = bufferPool;
-        this.extensionRegistry = new WebSocketExtensionFactory(policy,bufferPool);
-        
-        // Bug #431459 - unregistering compression extensions till they are more stable
-        this.extensionRegistry.unregister("deflate-frame");
-        this.extensionRegistry.unregister("permessage-deflate");
-        this.extensionRegistry.unregister("x-webkit-deflate-frame");
+        this.objectFactory = objectFactory;
+        this.extensionRegistry = new WebSocketExtensionFactory(this);
         
         this.masker = new RandomMasker();
         this.eventDriverFactory = new EventDriverFactory(policy);
-        this.sessionFactory = new WebSocketSessionFactory(this);
         
         addBean(this.executor);
         addBean(this.sslContextFactory);
         addBean(this.bufferPool);
     }
-
+    
     public Future<Session> connect(Object websocket, URI toUri) throws IOException
     {
         ClientUpgradeRequest request = new ClientUpgradeRequest(toUri);
@@ -184,7 +195,7 @@
             LOG.debug("connect websocket {} to {}",websocket,toUri);
 
         // Grab Connection Manager
-        initialiseClient();
+        initializeClient();
         ConnectionManager manager = getConnectionManager();
 
         // Setup Driver for user provided websocket
@@ -253,8 +264,18 @@
             cookieStore = new HttpCookieStore.Empty();
         }
 
-        super.doStart();
+        if(this.sessionFactory == null)
+        {
+            this.sessionFactory = new WebSocketSessionFactory(this);
+        }
+        
+        if(this.objectFactory == null)
+        {
+            this.objectFactory = new DecoratedObjectFactory();
+        }
 
+        super.doStart();
+        
         if (LOG.isDebugEnabled())
             LOG.debug("Started {}",this);
     }
@@ -277,11 +298,16 @@
         }
 
         super.doStop();
-
+        
         if (LOG.isDebugEnabled())
             LOG.debug("Stopped {}",this);
     }
 
+    public boolean isDispatchIO()
+    {
+        return dispatchIO;
+    }
+
     /**
      * Return the number of milliseconds for a timeout of an attempted write operation.
      * 
@@ -387,9 +413,15 @@
         return this.policy.getMaxTextMessageSize();
     }
 
+    @Override
+    public DecoratedObjectFactory getObjectFactory()
+    {
+        return this.objectFactory;
+    }
+
     public Set<WebSocketSession> getOpenSessions()
     {
-        return new HashSet<>(getBeans(WebSocketSession.class));
+        return Collections.unmodifiableSet(new HashSet<>(getBeans(WebSocketSession.class)));
     }
 
     public WebSocketPolicy getPolicy()
@@ -401,7 +433,7 @@
     {
         return scheduler;
     }
-
+    
     public SessionFactory getSessionFactory()
     {
         return sessionFactory;
@@ -416,29 +448,7 @@
         return sslContextFactory;
     }
 
-    public List<Extension> initExtensions(List<ExtensionConfig> requested)
-    {
-        List<Extension> extensions = new ArrayList<Extension>();
-
-        for (ExtensionConfig cfg : requested)
-        {
-            Extension extension = extensionRegistry.newInstance(cfg);
-
-            if (extension == null)
-            {
-                continue;
-            }
-
-            if (LOG.isDebugEnabled())
-                LOG.debug("added {}",extension);
-            extensions.add(extension);
-        }
-        if (LOG.isDebugEnabled())
-            LOG.debug("extensions={}",extensions);
-        return extensions;
-    }
-
-    private synchronized void initialiseClient() throws IOException
+    private synchronized void initializeClient() throws IOException
     {
         if (!ShutdownThread.isRegistered(this))
         {
@@ -489,15 +499,26 @@
     {
         if (LOG.isDebugEnabled())
             LOG.debug("Session Opened: {}",session);
+        addManaged(session);
     }
-
+    
     public void setAsyncWriteTimeout(long ms)
     {
         this.policy.setAsyncWriteTimeout(ms);
     }
 
+    /**
+     * @param bindAddress the address to bind to
+     * @deprecated use {@link #setBindAddress(SocketAddress)} instead
+     */
+    @Deprecated
     public void setBindAdddress(SocketAddress bindAddress)
     {
+        setBindAddress(bindAddress);
+    }
+
+    public void setBindAddress(SocketAddress bindAddress)
+    {
         this.bindAddress = bindAddress;
     }
 
@@ -531,6 +552,11 @@
         this.daemon = daemon;
     }
 
+    public void setDispatchIO(boolean dispatchIO)
+    {
+        this.dispatchIO = dispatchIO;
+    }
+
     public void setEventDriverFactory(EventDriverFactory factory)
     {
         this.eventDriverFactory = factory;
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
index 24de073..00d3b51 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectPromise.java
@@ -19,6 +19,8 @@
 package org.eclipse.jetty.websocket.client.io;
 
 import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.ClientUpgradeResponse;
@@ -32,12 +34,14 @@
  */
 public abstract class ConnectPromise extends FuturePromise<Session> implements Runnable
 {
+    private static final Logger LOG = Log.getLogger(ConnectPromise.class);
     private final WebSocketClient client;
     private final EventDriver driver;
     private final ClientUpgradeRequest request;
     private final Masker masker;
     private UpgradeListener upgradeListener;
     private ClientUpgradeResponse response;
+    private WebSocketSession session;
 
     public ConnectPromise(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
     {
@@ -97,11 +101,18 @@
         this.upgradeListener = upgradeListener;
     }
 
-    public void succeeded(WebSocketSession session)
+    public void succeeded()
     {
+        if(LOG.isDebugEnabled())
+            LOG.debug("{}.succeeded()",this.getClass().getSimpleName());
         session.setUpgradeRequest(request);
         session.setUpgradeResponse(response);
-        session.open();
+        // session.open();
         super.succeeded(session);
     }
+
+    public void setSession(WebSocketSession session)
+    {
+        this.session = session;
+    }
 }
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
index 6905fd3..06a51b9 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java
@@ -23,20 +23,13 @@
 import java.net.SocketAddress;
 import java.net.URI;
 import java.nio.channels.SocketChannel;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Locale;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.StatusCode;
-import org.eclipse.jetty.websocket.api.WebSocketException;
 import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
 import org.eclipse.jetty.websocket.client.WebSocketClient;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 
 /**
@@ -104,20 +97,6 @@
         }
     }
 
-    private class VirtualConnect extends ConnectPromise
-    {
-        public VirtualConnect(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
-        {
-            super(client,driver,request);
-        }
-
-        @Override
-        public void run()
-        {
-            failed(new WebSocketException("MUX Not yet supported"));
-        }
-    }
-
     private static final Logger LOG = Log.getLogger(ConnectionManager.class);
 
     public static InetSocketAddress toSocketAddress(URI uri)
@@ -151,7 +130,6 @@
         return new InetSocketAddress(uri.getHost(),port);
     }
 
-    private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
     private final WebSocketClient client;
     private WebSocketClientSelectorManager selector;
 
@@ -160,41 +138,8 @@
         this.client = client;
     }
 
-    public void addSession(WebSocketSession session)
-    {
-        sessions.add(session);
-    }
-
-    private void shutdownAllConnections()
-    {
-        for (WebSocketSession session : sessions)
-        {
-            if (session.getConnection() != null)
-            {
-                try
-                {
-                    session.getConnection().close(
-                            StatusCode.SHUTDOWN,
-                            "Shutdown");
-                }
-                catch (Throwable t)
-                {
-                    LOG.debug("During Shutdown All Connections",t);
-                }
-            }
-        }
-    }
-
     public ConnectPromise connect(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
     {
-        URI toUri = request.getRequestURI();
-        String hostname = toUri.getHost();
-
-        if (isVirtualConnectionPossibleTo(hostname))
-        {
-            return new VirtualConnect(client,driver,request);
-        }
-
         return new PhysicalConnect(client,driver,request);
     }
 
@@ -212,8 +157,6 @@
     @Override
     protected void doStop() throws Exception
     {
-        shutdownAllConnections();
-        sessions.clear();
         super.doStop();
         removeBean(selector);
     }
@@ -223,17 +166,6 @@
         return selector;
     }
 
-    public Collection<WebSocketSession> getSessions()
-    {
-        return Collections.unmodifiableCollection(sessions);
-    }
-
-    public boolean isVirtualConnectionPossibleTo(String hostname)
-    {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
     /**
      * Factory method for new WebSocketClientSelectorManager (used by other projects like cometd)
      * 
@@ -245,9 +177,4 @@
     {
         return new WebSocketClientSelectorManager(client);
     }
-
-    public void removeSession(WebSocketSession session)
-    {
-        sessions.remove(session);
-    }
 }
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
index 38a40d5..f8eb9bd 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/UpgradeConnection.java
@@ -29,6 +29,7 @@
 
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.FutureCallback;
@@ -49,14 +50,18 @@
 import org.eclipse.jetty.websocket.common.io.http.HttpResponseHeaderParser.ParseException;
 
 /**
- * This is the initial connection handling that exists immediately after physical connection is established to destination server.
+ * This is the initial connection handling that exists immediately after physical connection is established to
+ * destination server.
  * <p>
- * Eventually, upon successful Upgrade request/response, this connection swaps itself out for the WebSocektClientConnection handler.
+ * Eventually, upon successful Upgrade request/response, this connection swaps itself out for the
+ * WebSocektClientConnection handler.
  */
-public class UpgradeConnection extends AbstractConnection
+public class UpgradeConnection extends AbstractConnection implements Connection.UpgradeFrom
 {
     public class SendUpgradeRequest extends FutureCallback implements Runnable
     {
+        private final Logger LOG = Log.getLogger(UpgradeConnection.SendUpgradeRequest.class);
+        
         @Override
         public void run()
         {
@@ -71,16 +76,20 @@
 
             String rawRequest = request.generate();
 
-            ByteBuffer buf = BufferUtil.toBuffer(rawRequest, StandardCharsets.UTF_8);
+            ByteBuffer buf = BufferUtil.toBuffer(rawRequest,StandardCharsets.UTF_8);
             getEndPoint().write(this,buf);
         }
 
         @Override
         public void succeeded()
         {
-            LOG.debug("Upgrade Request Write Success");
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Upgrade Request Write Success");
+            }
             // Writing the request header is complete.
             super.succeeded();
+            state = State.RESPONSE;
             // start the interest in fill
             fillInterested();
         }
@@ -88,8 +97,12 @@
         @Override
         public void failed(Throwable cause)
         {
-            LOG.warn("Upgrade Request Write Failure", cause);
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Upgrade Request Write Failure",cause);
+            }
             super.failed(cause);
+            state = State.FAILURE;
             // Fail the connect promise when a fundamental exception during connect occurs.
             connectPromise.failed(cause);
         }
@@ -98,11 +111,21 @@
     /** HTTP Response Code: 101 Switching Protocols */
     private static final int SWITCHING_PROTOCOLS = 101;
 
+    private enum State
+    {
+        REQUEST,
+        RESPONSE,
+        FAILURE,
+        UPGRADE
+    }
+
     private static final Logger LOG = Log.getLogger(UpgradeConnection.class);
     private final ByteBufferPool bufferPool;
     private final ConnectPromise connectPromise;
     private final HttpResponseHeaderParser parser;
+    private State state = State.REQUEST;
     private ClientUpgradeRequest request;
+    private ClientUpgradeResponse response;
 
     public UpgradeConnection(EndPoint endp, Executor executor, ConnectPromise connectPromise)
     {
@@ -121,12 +144,17 @@
         // We need to gently close first, to allow
         // SSL close alerts to be sent by Jetty
         if (LOG.isDebugEnabled())
+        {
             LOG.debug("Shutting down output {}",endPoint);
+        }
+        
         endPoint.shutdownOutput();
         if (!onlyOutput)
         {
             if (LOG.isDebugEnabled())
+            {
                 LOG.debug("Closing {}",endPoint);
+            }
             endPoint.close();
         }
     }
@@ -147,6 +175,12 @@
             handshakeListener.onHandshakeResponse(response);
         }
     }
+    
+    @Override
+    public ByteBuffer onUpgradeFrom()
+    {
+        return connectPromise.getResponse().getRemainingBuffer();
+    }
 
     @Override
     public void onFillable()
@@ -157,20 +191,25 @@
         }
         ByteBuffer buffer = bufferPool.acquire(getInputBufferSize(),false);
         BufferUtil.clear(buffer);
-        boolean readMore = false;
         try
         {
-            readMore = read(buffer);
+            read(buffer);
         }
         finally
         {
             bufferPool.release(buffer);
         }
 
-        if (readMore)
+        if (state == State.RESPONSE)
         {
+            // Continue Reading
             fillInterested();
         }
+        else if (state == State.UPGRADE)
+        {
+            // Stop Reading, upgrade the connection now
+            upgradeConnection(response);
+        }
     }
 
     @Override
@@ -179,27 +218,27 @@
         super.onOpen();
         getExecutor().execute(new SendUpgradeRequest());
     }
-    
+
     @Override
     public void onClose()
     {
         if (LOG.isDebugEnabled())
         {
-            LOG.warn("Closed connection {}",this);
+            LOG.debug("Closed connection {}",this);
         }
         super.onClose();
     }
-    
+
     @Override
     protected boolean onReadTimeout()
     {
         if (LOG.isDebugEnabled())
         {
-            LOG.warn("Timeout on connection {}",this);
+            LOG.debug("Timeout on connection {}",this);
         }
-        
+
         failUpgrade(new IOException("Timeout while performing WebSocket Upgrade"));
-        
+
         return super.onReadTimeout();
     }
 
@@ -208,9 +247,8 @@
      * 
      * @param buffer
      *            the buffer to fill into from the endpoint
-     * @return true if there is more to read, false if reading should stop
      */
-    private boolean read(ByteBuffer buffer)
+    private void read(ByteBuffer buffer)
     {
         EndPoint endPoint = getEndPoint();
         try
@@ -220,13 +258,14 @@
                 int filled = endPoint.fill(buffer);
                 if (filled == 0)
                 {
-                    return true;
+                    return;
                 }
                 else if (filled < 0)
                 {
                     LOG.warn("read - EOF Reached");
+                    state = State.FAILURE;
                     failUpgrade(new EOFException("Reading WebSocket Upgrade response"));
-                    return false;
+                    return;
                 }
                 else
                 {
@@ -234,34 +273,32 @@
                     {
                         LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
                     }
-                    ClientUpgradeResponse resp = (ClientUpgradeResponse)parser.parse(buffer);
-                    if (resp != null)
+                    response = (ClientUpgradeResponse)parser.parse(buffer);
+                    if (response != null)
                     {
                         // Got a response!
-                        validateResponse(resp);
-                        notifyConnect(resp);
-                        upgradeConnection(resp);
-                        if (buffer.hasRemaining())
-                        {
-                            LOG.debug("Has remaining client bytebuffer of {}",buffer.remaining());
-                        }
-                        return false; // do no more reading
+                        validateResponse(response);
+                        notifyConnect(response);
+                        state = State.UPGRADE;
+                        return; // do no more reading
                     }
                 }
             }
         }
         catch (IOException | ParseException e)
         {
+            LOG.ignore(e);
+            state = State.FAILURE;
             UpgradeException ue = new UpgradeException(request.getRequestURI(),e);
             connectPromise.failed(ue);
             disconnect(false);
-            return false;
         }
         catch (UpgradeException e)
         {
+            LOG.ignore(e);
+            state = State.FAILURE;
             connectPromise.failed(e);
             disconnect(false);
-            return false;
         }
     }
 
@@ -269,7 +306,7 @@
     {
         EndPoint endp = getEndPoint();
         Executor executor = getExecutor();
-        
+
         EventDriver websocket = connectPromise.getDriver();
         WebSocketPolicy policy = websocket.getPolicy();
 
@@ -278,9 +315,10 @@
         SessionFactory sessionFactory = connectPromise.getClient().getSessionFactory();
         WebSocketSession session = sessionFactory.createSession(request.getRequestURI(),websocket,connection);
         session.setPolicy(policy);
+        session.setUpgradeRequest(request);
         session.setUpgradeResponse(response);
-
-        connection.setSession(session);
+        connection.addListener(session);
+        connectPromise.setSession(session);
 
         // Initialize / Negotiate Extensions
         ExtensionStack extensionStack = new ExtensionStack(connectPromise.getClient().getExtensionFactory());
@@ -297,13 +335,11 @@
         session.setOutgoingHandler(extensionStack);
         extensionStack.setNextOutgoing(connection);
 
-        session.addBean(extensionStack);
+        session.addManaged(extensionStack);
         connectPromise.getClient().addManaged(session);
 
         // Now swap out the connection
-        // TODO use endp.upgrade ???
-        endp.setConnection(connection);
-        connection.onOpen();
+        endp.upgrade(connection);
     }
 
     private void validateResponse(ClientUpgradeResponse response)
@@ -311,7 +347,9 @@
         // Validate Response Status Code
         if (response.getStatusCode() != SWITCHING_PROTOCOLS)
         {
-            throw new UpgradeException(request.getRequestURI(),response.getStatusCode(),"Didn't switch protocols");
+            // TODO: use jetty-http and org.eclipse.jetty.http.HttpStatus for more meaningful exception messages 
+            throw new UpgradeException(request.getRequestURI(),response.getStatusCode(),"Didn't switch protocols, expected status <" + SWITCHING_PROTOCOLS
+                    + ">, but got <" + response.getStatusCode() + ">");
         }
 
         // Validate Connection header
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
index 63be07e..2d1bd3b 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientConnection.java
@@ -19,13 +19,10 @@
 package org.eclipse.jetty.websocket.client.io;
 
 import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.BatchMode;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.WriteCallback;
@@ -33,7 +30,6 @@
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
 import org.eclipse.jetty.websocket.client.masks.Masker;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
 
 /**
@@ -41,7 +37,6 @@
  */
 public class WebSocketClientConnection extends AbstractWebSocketConnection
 {
-    private static final Logger LOG = Log.getLogger(WebSocketClientConnection.class);
     private final ConnectPromise connectPromise;
     private final Masker masker;
     private final AtomicBoolean opened = new AtomicBoolean(false);
@@ -67,32 +62,14 @@
     }
 
     @Override
-    public void onClose()
-    {
-        super.onClose();
-        ConnectionManager connectionManager = connectPromise.getClient().getConnectionManager();
-        connectionManager.removeSession(getSession());
-    }
-
-    @Override
     public void onOpen()
     {
+        super.onOpen();
         boolean beenOpened = opened.getAndSet(true);
         if (!beenOpened)
         {
-            WebSocketSession session = getSession();
-            ConnectionManager connectionManager = connectPromise.getClient().getConnectionManager();
-            connectionManager.addSession(session);
-            connectPromise.succeeded(session);
-
-            ByteBuffer extraBuf = connectPromise.getResponse().getRemainingBuffer();
-            if (extraBuf.hasRemaining())
-            {
-                LOG.debug("Parsing extra remaining buffer from UpgradeConnection");
-                getParser().parse(extraBuf);
-            }
+            connectPromise.succeeded();
         }
-        super.onOpen();
     }
 
     /**
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java
index 42fd31c..9adf88d 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/WebSocketClientSelectorManager.java
@@ -22,11 +22,13 @@
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.concurrent.Executor;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectorManager;
 import org.eclipse.jetty.io.ssl.SslConnection;
diff --git a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/package-info.java b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/package-info.java
index 88cd296..ff2ae42 100644
--- a/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/package-info.java
+++ b/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/package-info.java
@@ -20,14 +20,15 @@
  * Jetty WebSocket Client API
  * <p>
  * The core class is {@link org.eclipse.jetty.websocket.client.WebSocketClient}, which acts as a central configuration object (for example
- * for {@link org.eclipse.jetty.websocket.client.WebSocketClient#setConnectTimeout(int) connect timeouts}, {@link WebSocketClient#setCookieStore(CookieStore)
- * request cookie store}, etc.) and as a factory for WebSocket {@link org.eclipse.jetty.websocket.api.Session} objects.
+ * for {@link org.eclipse.jetty.websocket.client.WebSocketClient#setConnectTimeout(long)}, 
+ * {@link org.eclipse.jetty.websocket.client.WebSocketClient#setCookieStore(java.net.CookieStore)}, 
+ * etc.) and as a factory for WebSocket {@link org.eclipse.jetty.websocket.api.Session} objects.
  * <p>
  * The <a href="https://tools.ietf.org/html/rfc6455">WebSocket protocol</a> is based on a framing protocol built
  * around an upgraded HTTP connection.  It is primarily focused on the sending of messages (text or binary), with an
  * occasional control frame (close, ping, pong) that this implementation uses.  
- * <p />
- * {@link org.eclipse.jetty.websocket.client.WebSocketClient} holds a number of {@link org.eclipse.jetty.websocket.api.Session Sessions}, which in turn
+ * <p>
+ * {@link org.eclipse.jetty.websocket.client.WebSocketClient} holds a number of {@link org.eclipse.jetty.websocket.api.Session}, which in turn
  * is used to manage physical vs virtual connection handling (mux extension).
  */
 package org.eclipse.jetty.websocket.client;
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/BadNetworkTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/BadNetworkTest.java
index 8d358d9..ed88414 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/BadNetworkTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/BadNetworkTest.java
@@ -26,7 +26,7 @@
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
 import org.junit.After;
 import org.junit.Before;
@@ -82,7 +82,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection ssocket = server.accept();
+        IBlockheadServerConnection ssocket = server.accept();
         ssocket.upgrade();
 
         // Validate that we are connected
@@ -110,7 +110,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection ssocket = server.accept();
+        IBlockheadServerConnection ssocket = server.accept();
         ssocket.upgrade();
 
         // Validate that we are connected
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java
index 2f198b0..bf2eaca 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientCloseTest.java
@@ -35,8 +35,8 @@
 
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.EofException;
+import org.eclipse.jetty.io.ManagedSelector;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
 import org.eclipse.jetty.toolchain.test.EventQueue;
 import org.eclipse.jetty.toolchain.test.TestTracker;
 import org.eclipse.jetty.util.BufferUtil;
@@ -58,7 +58,7 @@
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.eclipse.jetty.websocket.common.test.IncomingFramesCapture;
 import org.eclipse.jetty.websocket.common.test.RawFrameBuilder;
 import org.hamcrest.Matcher;
@@ -187,7 +187,7 @@
     private BlockheadServer server;
     private WebSocketClient client;
 
-    private void confirmConnection(CloseTrackingSocket clientSocket, Future<Session> clientFuture, ServerConnection serverConn) throws Exception
+    private void confirmConnection(CloseTrackingSocket clientSocket, Future<Session> clientFuture, IBlockheadServerConnection serverConns) throws Exception
     {
         // Wait for client connect on via future
         clientFuture.get(500,TimeUnit.MILLISECONDS);
@@ -205,7 +205,7 @@
             testFut.get(500,TimeUnit.MILLISECONDS);
 
             // Read Frame on server side
-            IncomingFramesCapture serverCapture = serverConn.readFrames(1,500,TimeUnit.MILLISECONDS);
+            IncomingFramesCapture serverCapture = serverConns.readFrames(1,500,TimeUnit.MILLISECONDS);
             serverCapture.assertNoErrors();
             serverCapture.assertFrameCount(1);
             WebSocketFrame frame = serverCapture.getFrames().poll();
@@ -213,7 +213,7 @@
             Assert.assertThat("Server received frame payload",frame.getPayloadAsUTF8(),is(echoMsg));
 
             // Server send echo reply
-            serverConn.write(new TextFrame().setPayload(echoMsg));
+            serverConns.write(new TextFrame().setPayload(echoMsg));
 
             // Wait for received echo
             clientSocket.messageQueue.awaitEventCount(1,1,TimeUnit.SECONDS);
@@ -231,7 +231,7 @@
         }
     }
 
-    private void confirmServerReceivedCloseFrame(ServerConnection serverConn, int expectedCloseCode, Matcher<String> closeReasonMatcher) throws IOException,
+    private void confirmServerReceivedCloseFrame(IBlockheadServerConnection serverConn, int expectedCloseCode, Matcher<String> closeReasonMatcher) throws IOException,
             TimeoutException
     {
         IncomingFramesCapture serverCapture = serverConn.readFrames(1,500,TimeUnit.MILLISECONDS);
@@ -348,7 +348,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
@@ -397,7 +397,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
@@ -448,7 +448,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
@@ -496,7 +496,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
@@ -532,7 +532,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
@@ -564,7 +564,7 @@
 
         int clientCount = 3;
         CloseTrackingSocket clientSockets[] = new CloseTrackingSocket[clientCount];
-        ServerConnection serverConns[] = new ServerConnection[clientCount];
+        IBlockheadServerConnection serverConns[] = new IBlockheadServerConnection[clientCount];
 
         // Connect Multiple Clients
         for (int i = 0; i < clientCount; i++)
@@ -610,7 +610,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.upgrade();
 
         // client confirms connection via echo
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java
index 3f8c35a..84b6ba3 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.websocket.client;
 
 import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
 
 import java.io.IOException;
 import java.net.ConnectException;
@@ -36,7 +37,7 @@
 import org.eclipse.jetty.websocket.api.UpgradeException;
 import org.eclipse.jetty.websocket.common.AcceptHash;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
 import org.junit.After;
 import org.junit.Assert;
@@ -111,6 +112,25 @@
     }
 
     @Test
+    public void testUpgradeRequest() throws Exception
+    {
+        JettyTrackingSocket wsocket = new JettyTrackingSocket();
+
+        URI wsUri = server.getWsUri();
+        Future<Session> future = client.connect(wsocket,wsUri);
+
+        IBlockheadServerConnection connection = server.accept();
+        connection.upgrade();
+
+        Session sess = future.get(500,TimeUnit.MILLISECONDS);
+        
+        sess.close();
+        
+        assertThat("Connect.UpgradeRequest", wsocket.connectUpgradeRequest, notNullValue());
+        assertThat("Connect.UpgradeResponse", wsocket.connectUpgradeResponse, notNullValue());
+    }
+
+    @Test
     public void testBadHandshake() throws Exception
     {
         JettyTrackingSocket wsocket = new JettyTrackingSocket();
@@ -118,7 +138,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         connection.readRequest();
         // no upgrade, just fail with a 404 error
         connection.respond("HTTP/1.1 404 NOT FOUND\r\n\r\n");
@@ -147,7 +167,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         connection.readRequest();
         // Send OK to GET but not upgrade
         connection.respond("HTTP/1.1 200 OK\r\n\r\n");
@@ -176,7 +196,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         List<String> requestLines = connection.readRequestLines();
         String key = connection.parseWebSocketKey(requestLines);
 
@@ -212,7 +232,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         List<String> requestLines = connection.readRequestLines();
         String key = connection.parseWebSocketKey(requestLines);
 
@@ -248,7 +268,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         List<String> requestLines = connection.readRequestLines();
         String key = connection.parseWebSocketKey(requestLines);
 
@@ -284,7 +304,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection connection = server.accept();
+        IBlockheadServerConnection connection = server.accept();
         connection.readRequest();
         // Upgrade badly
         connection.respond("HTTP/1.1 101 Upgrade\r\n" + "Sec-WebSocket-Accept: rubbish\r\n" + "\r\n");
@@ -378,7 +398,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(wsocket,wsUri);
 
-        ServerConnection ssocket = server.accept();
+        IBlockheadServerConnection ssocket = server.accept();
         Assert.assertNotNull(ssocket);
         // Intentionally don't upgrade
         // ssocket.upgrade();
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/CookieTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/CookieTest.java
index 23b90ce..0fef309 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/CookieTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/CookieTest.java
@@ -37,7 +37,7 @@
 import org.eclipse.jetty.websocket.api.util.QuoteUtil;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -119,7 +119,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
 
         // client confirms upgrade and receipt of frame
         String serverCookies = confirmClientUpgradeAndCookies(clientSocket,clientConnectFuture,serverConn);
@@ -144,7 +144,7 @@
         Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri(),request);
 
         // Server accepts connect
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
 
         // client confirms upgrade and receipt of frame
         String serverCookies = confirmClientUpgradeAndCookies(clientSocket,clientConnectFuture,serverConn);
@@ -152,7 +152,7 @@
         Assert.assertThat("Cookies seen at server side",serverCookies,containsString("hello=\"world\""));
     }
 
-    private String confirmClientUpgradeAndCookies(CookieTrackingSocket clientSocket, Future<Session> clientConnectFuture, ServerConnection serverConn)
+    private String confirmClientUpgradeAndCookies(CookieTrackingSocket clientSocket, Future<Session> clientConnectFuture, IBlockheadServerConnection serverConn)
             throws Exception
     {
         // Server upgrades
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/JettyTrackingSocket.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/JettyTrackingSocket.java
index 6e75ad0..0714fc7 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/JettyTrackingSocket.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/JettyTrackingSocket.java
@@ -30,6 +30,8 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.api.UpgradeResponse;
 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
 import org.junit.Assert;
 
@@ -42,6 +44,8 @@
 
     public int closeCode = -1;
     public Exchanger<String> messageExchanger;
+    public UpgradeRequest connectUpgradeRequest;
+    public UpgradeResponse connectUpgradeResponse;
     public StringBuilder closeMessage = new StringBuilder();
     public CountDownLatch openLatch = new CountDownLatch(1);
     public CountDownLatch closeLatch = new CountDownLatch(1);
@@ -124,6 +128,8 @@
     public void onWebSocketConnect(Session session)
     {
         super.onWebSocketConnect(session);
+        connectUpgradeRequest = session.getUpgradeRequest();
+        connectUpgradeResponse = session.getUpgradeResponse();
         openLatch.countDown();
     }
 
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerReadThread.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerReadThread.java
index 1a6b0ff..2f172d5 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerReadThread.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerReadThread.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.client;
 
+import static org.hamcrest.Matchers.*;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Queue;
@@ -32,24 +34,22 @@
 import org.eclipse.jetty.websocket.common.CloseInfo;
 import org.eclipse.jetty.websocket.common.OpCode;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.is;
-
 public class ServerReadThread extends Thread
 {
     private static final int BUFFER_SIZE = 8192;
     private static final Logger LOG = Log.getLogger(ServerReadThread.class);
-    private final ServerConnection conn;
+    private final IBlockheadServerConnection conn;
     private boolean active = true;
     private int slowness = -1; // disabled is default
     private final AtomicInteger frameCount = new AtomicInteger();
     private final CountDownLatch expectedMessageCount;
 
-    public ServerReadThread(ServerConnection conn, int expectedMessages)
+    public ServerReadThread(IBlockheadServerConnection sconnection, int expectedMessages)
     {
-        this.conn = conn;
+        this.conn = sconnection;
         this.expectedMessageCount = new CountDownLatch(expectedMessages);
     }
 
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerWriteThread.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerWriteThread.java
index d36e1ed..160e320 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerWriteThread.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ServerWriteThread.java
@@ -25,17 +25,17 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 
 public class ServerWriteThread extends Thread
 {
     private static final Logger LOG = Log.getLogger(ServerWriteThread.class);
-    private final ServerConnection conn;
+    private final IBlockheadServerConnection conn;
     private int slowness = -1;
     private int messageCount = 100;
     private String message = "Hello";
 
-    public ServerWriteThread(ServerConnection conn)
+    public ServerWriteThread(IBlockheadServerConnection conn)
     {
         this.conn = conn;
     }
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
index 2eb0c80..3d24992 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SessionTest.java
@@ -18,7 +18,10 @@
 
 package org.eclipse.jetty.websocket.client;
 
+import static org.hamcrest.Matchers.*;
+
 import java.net.URI;
+import java.util.Collection;
 import java.util.Set;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -28,15 +31,12 @@
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-
 public class SessionTest
 {
     private BlockheadServer server;
@@ -70,7 +70,7 @@
             request.setSubProtocols("echo");
             Future<Session> future = client.connect(cliSock,wsUri,request);
 
-            final ServerConnection srvSock = server.accept();
+            final IBlockheadServerConnection srvSock = server.accept();
             srvSock.upgrade();
 
             Session sess = future.get(500,TimeUnit.MILLISECONDS);
@@ -82,18 +82,21 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             RemoteEndpoint remote = cliSock.getSession().getRemote();
             remote.sendStringByFuture("Hello World!");
             if (remote.getBatchMode() == BatchMode.ON)
+            {
                 remote.flush();
+            }
             srvSock.echoMessage(1,500,TimeUnit.MILLISECONDS);
             // wait for response from server
             cliSock.waitForMessage(500,TimeUnit.MILLISECONDS);
             
             Set<WebSocketSession> open = client.getOpenSessions();
-            Assert.assertThat("Open Sessions.size", open.size(), is(1));
+            Assert.assertThat("(Before Close) Open Sessions.size", open.size(), is(1));
 
             cliSock.assertMessage("Hello World!");
             cliSock.close();
@@ -101,7 +104,7 @@
             
             cliSock.waitForClose(500,TimeUnit.MILLISECONDS);
             open = client.getOpenSessions();
-            Assert.assertThat("Open Sessions.size", open.size(), is(0));
+            Assert.assertThat("(After Close) Open Sessions.size", open.size(), is(0));
         }
         finally
         {
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowClientTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowClientTest.java
index 5983b24..7ea2d5d 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowClientTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowClientTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.client;
 
+import static org.hamcrest.Matchers.*;
+
 import java.net.URI;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -27,15 +29,13 @@
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class SlowClientTest
 {
     @Rule
@@ -81,7 +81,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(tsocket, wsUri);
 
-        ServerConnection sconnection = server.accept();
+        IBlockheadServerConnection sconnection = server.accept();
         sconnection.setSoTimeout(60000);
         sconnection.upgrade();
 
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowServerTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowServerTest.java
index 82df9cf62..4307df3 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowServerTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/SlowServerTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.client;
 
+import static org.hamcrest.Matchers.*;
+
 import java.net.URI;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -28,15 +30,13 @@
 import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.client.masks.ZeroMasker;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class SlowServerTest
 {
     @Rule
@@ -83,7 +83,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> future = client.connect(tsocket,wsUri);
 
-        ServerConnection sconnection = server.accept();
+        IBlockheadServerConnection sconnection = server.accept();
         sconnection.setSoTimeout(60000);
         sconnection.upgrade();
 
@@ -130,7 +130,7 @@
         URI wsUri = server.getWsUri();
         Future<Session> clientConnectFuture = client.connect(clientSocket,wsUri);
 
-        ServerConnection serverConn = server.accept();
+        IBlockheadServerConnection serverConn = server.accept();
         serverConn.setSoTimeout(60000);
         serverConn.upgrade();
 
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java
index 1f0dc21..fd56b14 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/TomcatServerQuirksTest.java
@@ -28,7 +28,7 @@
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -66,7 +66,7 @@
      * <li><a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=54067">Apache Tomcat Bug #54067</a></li>
      * </ul>
      * 
-     * @throws IOException
+     * @throws Exception on test failure
      */
     @Test
     public void testTomcat7_0_32_WithTransferEncoding() throws Exception
@@ -91,7 +91,7 @@
             client.connect(websocket,wsURI);
 
             // Accept incoming connection
-            ServerConnection socket = server.accept();
+            IBlockheadServerConnection socket = server.accept();
             socket.setSoTimeout(2000); // timeout
 
             // Issue upgrade
@@ -113,8 +113,7 @@
             serverFrame.put((byte)(payload.length & 0xFF)); // second length byte
             serverFrame.put(payload);
             BufferUtil.flipToFlush(serverFrame,0);
-            byte buf[] = BufferUtil.toArray(serverFrame);
-            socket.write(buf,0,buf.length);
+            socket.write(serverFrame);
             socket.flush();
 
             Assert.assertTrue(websocket.dataLatch.await(1000,TimeUnit.SECONDS));
diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
index 024e7dd..0fce1fe 100644
--- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
+++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/WebSocketClientTest.java
@@ -18,9 +18,12 @@
 
 package org.eclipse.jetty.websocket.client;
 
+import static org.hamcrest.Matchers.*;
+
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Future;
@@ -32,21 +35,17 @@
 import org.eclipse.jetty.websocket.api.RemoteEndpoint;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.UpgradeRequest;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.io.FutureWriteCallback;
 import org.eclipse.jetty.websocket.common.test.BlockheadServer;
-import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection;
+import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
-
 @RunWith(AdvancedRunner.class)
 public class WebSocketClientTest
 {
@@ -106,7 +105,7 @@
             request.setSubProtocols("echo");
             Future<Session> future = client.connect(cliSock,wsUri,request);
 
-            final ServerConnection srvSock = server.accept();
+            final IBlockheadServerConnection srvSock = server.accept();
             srvSock.upgrade();
 
             Session sess = future.get(500,TimeUnit.MILLISECONDS);
@@ -118,7 +117,8 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             RemoteEndpoint remote = cliSock.getSession().getRemote();
             remote.sendStringByFuture("Hello World!");
@@ -152,7 +152,7 @@
             request.setSubProtocols("echo");
             Future<Session> future = client.connect(cliSock,wsUri,request);
 
-            final ServerConnection srvSock = server.accept();
+            final IBlockheadServerConnection srvSock = server.accept();
             srvSock.upgrade();
 
             Session sess = future.get(500,TimeUnit.MILLISECONDS);
@@ -164,7 +164,8 @@
             cliSock.assertWasOpened();
             cliSock.assertNotClosed();
 
-            Assert.assertThat("client.connectionManager.sessions.size",client.getConnectionManager().getSessions().size(),is(1));
+            Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
+            Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
 
             FutureWriteCallback callback = new FutureWriteCallback();
 
@@ -188,7 +189,7 @@
             Future<Session> future = client.connect(wsocket,server.getWsUri());
 
             // Server
-            final ServerConnection srvSock = server.accept();
+            final IBlockheadServerConnection srvSock = server.accept();
             srvSock.upgrade();
 
             // Validate connect
@@ -226,7 +227,7 @@
             URI wsUri = server.getWsUri();
             Future<Session> future = fact.connect(wsocket,wsUri);
 
-            ServerConnection ssocket = server.accept();
+            IBlockheadServerConnection ssocket = server.accept();
             ssocket.upgrade();
 
             future.get(500,TimeUnit.MILLISECONDS);
@@ -266,7 +267,7 @@
             URI wsUri = server.getWsUri();
             Future<Session> future = factSmall.connect(wsocket,wsUri);
 
-            ServerConnection ssocket = server.accept();
+            IBlockheadServerConnection ssocket = server.accept();
             ssocket.upgrade();
 
             future.get(500,TimeUnit.MILLISECONDS);
@@ -304,7 +305,7 @@
             URI wsUri = server.getWsUri();
             Future<Session> future = client.connect(wsocket,wsUri);
 
-            ServerConnection ssocket = server.accept();
+            IBlockheadServerConnection ssocket = server.accept();
             ssocket.upgrade();
 
             wsocket.awaitConnect(1,TimeUnit.SECONDS);
@@ -346,7 +347,7 @@
             URI wsUri = server.getWsUri().resolve("/test?snack=cashews&amount=handful&brand=off");
             Future<Session> future = fact.connect(wsocket,wsUri);
 
-            ServerConnection ssocket = server.accept();
+            IBlockheadServerConnection ssocket = server.accept();
             ssocket.upgrade();
 
             future.get(500,TimeUnit.MILLISECONDS);
diff --git a/jetty-websocket/websocket-common/pom.xml b/jetty-websocket/websocket-common/pom.xml
index 56c1859..e8bcaca 100644
--- a/jetty-websocket/websocket-common/pom.xml
+++ b/jetty-websocket/websocket-common/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <groupId>org.eclipse.jetty.websocket</groupId>
     <artifactId>websocket-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
 
   <modelVersion>4.0.0</modelVersion>
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java
index a635c94..469249a 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java
@@ -24,9 +24,8 @@
 import org.eclipse.jetty.util.SharedBlockingCallback;
 import org.eclipse.jetty.websocket.api.WriteCallback;
 
-
-/* ------------------------------------------------------------ */
-/** extend a SharedlBlockingCallback to an websocket WriteCallback
+/**
+ * Extends a {@link SharedBlockingCallback} to a WebSocket {@link WriteCallback}
  */
 public class BlockingWriteCallback extends SharedBlockingCallback
 {
@@ -39,11 +38,11 @@
         return new WriteBlocker(acquire());
     }
     
-    public static class WriteBlocker implements WriteCallback, Callback, AutoCloseable
+    public static class WriteBlocker implements WriteCallback, Callback.NonBlocking, AutoCloseable
     {
-        Blocker blocker;
+        private final Blocker blocker;
         
-        WriteBlocker(Blocker blocker)
+        protected WriteBlocker(Blocker blocker)
         {
             this.blocker=blocker;
         }
@@ -73,7 +72,7 @@
         }
         
         @Override
-        public void close() throws IOException
+        public void close()
         {
             blocker.close();
         }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/ConnectionState.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/ConnectionState.java
index 3ee635a..8afb698 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/ConnectionState.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/ConnectionState.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.websocket.common;
 
+import org.eclipse.jetty.websocket.common.io.IOState;
+import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
+
 /**
  * Connection states as outlined in <a href="https://tools.ietf.org/html/rfc6455">RFC6455</a>.
  */
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
index 0d45367..4eda6fd 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
@@ -22,6 +22,7 @@
 import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.api.SuspendToken;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
@@ -60,11 +61,13 @@
 
     /**
      * Get the ByteBufferPool in use by the connection
+     * @return the buffer pool
      */
     ByteBufferPool getBufferPool();
     
     /**
      * Get the Executor used by this connection.
+     * @return the executor
      */
     Executor getExecutor();
 
@@ -113,13 +116,6 @@
     InetSocketAddress getRemoteAddress();
 
     /**
-     * Get the Session for this connection
-     * 
-     * @return the Session for this connection
-     */
-    WebSocketSession getSession();
-
-    /**
      * Test if logical connection is still open
      * 
      *  @return true if connection is open
@@ -155,15 +151,8 @@
     void setNextIncomingFrames(IncomingFrames incoming);
 
     /**
-     * Set the session associated with this connection
-     * 
-     * @param session
-     *            the session
-     */
-    void setSession(WebSocketSession session);
-
-    /**
      * Suspend a the incoming read events on the connection.
+     * @return the suspend token
      */
     SuspendToken suspend();
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/OpCode.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/OpCode.java
index e65cd97..a56989a 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/OpCode.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/OpCode.java
@@ -99,7 +99,8 @@
                 return "CONTINUATION";
             case TEXT:
                 return "TEXT";
-            case BINARY: return "BINARY";
+            case BINARY:
+                return "BINARY";
             case CLOSE:
                 return "CLOSE";
             case PING:
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java
index 8d30345..e259d5b 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java
@@ -248,8 +248,6 @@
         }
         try
         {
-            // TODO: create DebugBuffer
-
             // parse through all the frames in the buffer
             while (parseFrame(buffer))
             {
@@ -332,9 +330,9 @@
                                 policy.getBehavior(),
                                 OpCode.name(opcode),
                                 fin,
-                                (isRsv1InUse()?'1':'.'),
-                                (isRsv2InUse()?'1':'.'),
-                                (isRsv3InUse()?'1':'.'));
+                                (((b & 0x40) != 0)?'1':'.'),
+                                (((b & 0x20) != 0)?'1':'.'),
+                                (((b & 0x10) != 0)?'1':'.'));
 
                     // base framing flags
                     switch(opcode)
@@ -653,7 +651,7 @@
         builder.append(",c=").append(cursor);
         builder.append(",len=").append(payloadLength);
         builder.append(",f=").append(frame);
-        builder.append(",p=").append(policy);
+        // builder.append(",p=").append(policy);
         builder.append("]");
         return builder.toString();
     }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketFrame.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketFrame.java
index d01cfe8..328fe22 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketFrame.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketFrame.java
@@ -96,7 +96,6 @@
 
     /**
      * Combined FIN + RSV1 + RSV2 + RSV3 + OpCode byte.
-     * <p>
      * 
      * <pre>
      *   1000_0000 (0x80) = fin
@@ -119,6 +118,7 @@
 
     /**
      * Construct form opcode
+     * @param opcode the opcode the frame is based on
      */
     protected WebSocketFrame(byte opcode)
     {
@@ -341,6 +341,7 @@
      * 
      * @param buf
      *            the bytebuffer to set
+     * @return the frame itself
      */
     public WebSocketFrame setPayload(ByteBuffer buf)
     {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
index a811807..33356b2 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
@@ -24,16 +24,20 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.ThreadClassLoaderScope;
 import org.eclipse.jetty.websocket.api.BatchMode;
+import org.eclipse.jetty.websocket.api.CloseException;
 import org.eclipse.jetty.websocket.api.CloseStatus;
 import org.eclipse.jetty.websocket.api.RemoteEndpoint;
 import org.eclipse.jetty.websocket.api.Session;
@@ -51,14 +55,18 @@
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 import org.eclipse.jetty.websocket.common.io.IOState;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketSessionScope;
 
 @ManagedObject("A Jetty WebSocket Session")
-public class WebSocketSession extends ContainerLifeCycle implements Session, IncomingFrames, ConnectionStateListener
+public class WebSocketSession extends ContainerLifeCycle implements Session, WebSocketSessionScope, IncomingFrames, Connection.Listener, ConnectionStateListener
 {
     private static final Logger LOG = Log.getLogger(WebSocketSession.class);
+    private static final Logger LOG_OPEN = Log.getLogger(WebSocketSession.class.getName() + "_OPEN");
+    private final WebSocketContainerScope containerScope;
     private final URI requestURI;
-    private final EventDriver websocket;
     private final LogicalConnection connection;
+    private final EventDriver websocket;
     private final SessionListener[] sessionListeners;
     private final Executor executor;
     private ClassLoader classLoader;
@@ -71,16 +79,14 @@
     private WebSocketPolicy policy;
     private UpgradeRequest upgradeRequest;
     private UpgradeResponse upgradeResponse;
-    private BatchMode batchMode = BatchMode.AUTO;
 
-    public WebSocketSession(URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
+    public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, EventDriver websocket, LogicalConnection connection, SessionListener... sessionListeners)
     {
-        if (requestURI == null)
-        {
-            throw new RuntimeException("Request URI cannot be null");
-        }
+        Objects.requireNonNull(containerScope,"Container Scope cannot be null");
+        Objects.requireNonNull(requestURI,"Request URI cannot be null");
 
         this.classLoader = Thread.currentThread().getContextClassLoader();
+        this.containerScope = containerScope;
         this.requestURI = requestURI;
         this.websocket = websocket;
         this.connection = connection;
@@ -89,6 +95,9 @@
         this.outgoingHandler = connection;
         this.incomingHandler = websocket;
         this.connection.getIOState().addListener(this);
+        
+        addBean(this.connection);
+        addBean(this.websocket);
     }
 
     @Override
@@ -126,7 +135,36 @@
     {
         executor.execute(runnable);
     }
+    
+    @Override
+    protected void doStart() throws Exception
+    {
+        if(LOG.isDebugEnabled())
+            LOG.debug("starting - {}",this);
 
+        super.doStart();
+    }
+    
+    @Override
+    protected void doStop() throws Exception
+    {
+        if(LOG.isDebugEnabled())
+            LOG.debug("stopping - {}",this);
+        
+        if (getConnection() != null)
+        {
+            try
+            {
+                getConnection().close(StatusCode.SHUTDOWN,"Shutdown");
+            }
+            catch (Throwable t)
+            {
+                LOG.debug("During Connection Shutdown",t);
+            }
+        }
+        super.doStop();
+    }
+    
     @Override
     public void dump(Appendable out, String indent) throws IOException
     {
@@ -197,6 +235,12 @@
         return connection;
     }
 
+    @Override
+    public WebSocketContainerScope getContainerScope()
+    {
+        return this.containerScope;
+    }
+
     public ExtensionFactory getExtensionFactory()
     {
         return extensionFactory;
@@ -244,12 +288,16 @@
     @Override
     public RemoteEndpoint getRemote()
     {
-        if (connection.getIOState().isOutputAvailable())
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.getRemote()",policy.getBehavior(),this.getClass().getSimpleName());
+        ConnectionState state = connection.getIOState().getConnectionState();
+
+        if ((state == ConnectionState.OPEN) || (state == ConnectionState.CONNECTED))
         {
             return remote;
         }
 
-        throw new WebSocketException("RemoteEndpoint unavailable, outgoing connection not open");
+        throw new WebSocketException("RemoteEndpoint unavailable, current state [" + state + "], expecting [OPEN or CONNECTED]");
     }
 
     @Override
@@ -274,6 +322,13 @@
     {
         return this.upgradeResponse;
     }
+    
+
+    @Override
+    public WebSocketSession getWebSocketSession()
+    {
+        return this;
+    }
 
     @Override
     public int hashCode()
@@ -303,10 +358,19 @@
     @Override
     public void incomingFrame(Frame frame)
     {
-        if (connection.getIOState().isInputAvailable())
+        ClassLoader old = Thread.currentThread().getContextClassLoader();
+        try
         {
-            // Forward Frames Through Extension List
-            incomingHandler.incomingFrame(frame);
+            Thread.currentThread().setContextClassLoader(classLoader);
+            if (connection.getIOState().isInputAvailable())
+            {
+                // Forward Frames Through Extension List
+                incomingHandler.incomingFrame(frame);
+            }
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader(old);
         }
     }
 
@@ -346,6 +410,19 @@
     {
         incomingError(cause);
     }
+    
+    @Override
+    public void onClosed(Connection connection)
+    {
+    }
+    
+    @Override
+    public void onOpened(Connection connection)
+    {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.onOpened()",policy.getBehavior(),this.getClass().getSimpleName());
+        open();
+    }
 
     @SuppressWarnings("incomplete-switch")
     @Override
@@ -354,6 +431,11 @@
         switch (state)
         {
             case CLOSED:
+                IOState ioState = this.connection.getIOState();
+                CloseInfo close = ioState.getCloseInfo();
+                // confirmed close of local endpoint
+                notifyClose(close.getStatusCode(),close.getReason());
+                
                 // notify session listeners
                 for (SessionListener listener : sessionListeners)
                 {
@@ -368,17 +450,15 @@
                         LOG.ignore(t);
                     }
                 }
-                IOState ioState = this.connection.getIOState();
-                CloseInfo close = ioState.getCloseInfo();
-                // confirmed close of local endpoint
-                notifyClose(close.getStatusCode(),close.getReason());
                 break;
-            case OPEN:
+            case CONNECTED:
                 // notify session listeners
                 for (SessionListener listener : sessionListeners)
                 {
                     try
                     {
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("{}.onSessionOpen()", listener.getClass().getSimpleName());
                         listener.onSessionOpened(this);
                     }
                     catch (Throwable t)
@@ -389,34 +469,31 @@
                 break;
         }
     }
-
+    
     /**
      * Open/Activate the session
      */
     public void open()
     {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.open()",policy.getBehavior(),this.getClass().getSimpleName());
+
         if (remote != null)
         {
             // already opened
             return;
         }
         
-        ClassLoader old = Thread.currentThread().getContextClassLoader();
-        try 
+        try(ThreadClassLoaderScope scope = new ThreadClassLoaderScope(classLoader)) 
         {
-            Thread.currentThread().setContextClassLoader(classLoader);
-
             // Upgrade success
             connection.getIOState().onConnected();
-            
+    
             // Connect remote
-            BatchMode endpointBatchMode = websocket.getBatchMode();
-            if (endpointBatchMode == null)
-            {
-                endpointBatchMode = this.getBatchMode();
-            }
-            remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,endpointBatchMode);
-
+            remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,getBatchMode());
+            if(LOG_OPEN.isDebugEnabled())
+                LOG_OPEN.debug("[{}] {}.open() remote={}",policy.getBehavior(),this.getClass().getSimpleName(),remote);
+            
             // Open WebSocket
             websocket.openSession(this);
 
@@ -428,8 +505,14 @@
                 LOG.debug("open -> {}",dump());
             }
         }
+        catch (CloseException ce)
+        {
+            LOG.warn(ce);
+            close(ce.getStatusCode(),ce.getMessage());
+        }
         catch (Throwable t)
         {
+            LOG.warn(t);
             // Exception on end-user WS-Endpoint.
             // Fast-fail & close connection with reason.
             int statusCode = StatusCode.SERVER_ERROR;
@@ -437,15 +520,10 @@
             {
                 statusCode = StatusCode.POLICY_VIOLATION;
             }
-            
             close(statusCode,t.getMessage());
         }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader(old);
-        }
     }
-
+    
     public void setExtensionFactory(ExtensionFactory extensionFactory)
     {
         this.extensionFactory = extensionFactory;
@@ -504,20 +582,11 @@
     }
 
     /**
-     * @return the batching mode default for RemoteEndpoint behavior
+     * @return the default (initial) value for the batching mode.
      */
     public BatchMode getBatchMode()
     {
-        return batchMode;
-    }
-    
-    /**
-     * Set the batch mode default for the RemoteEndpoint behavior.
-     * @param mode the batching mode.
-     */
-    public void setBatchMode(BatchMode mode)
-    {
-        this.batchMode = mode;
+        return BatchMode.AUTO;
     }
 
     @Override
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
index fab53f9..8494a26 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSessionFactory.java
@@ -23,18 +23,35 @@
 import org.eclipse.jetty.websocket.common.events.EventDriver;
 import org.eclipse.jetty.websocket.common.events.JettyAnnotatedEventDriver;
 import org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 
 /**
  * Default Session factory, creating WebSocketSession objects.
  */
 public class WebSocketSessionFactory implements SessionFactory
 {
+    private final WebSocketContainerScope containerScope;
     private final SessionListener[] listeners;
 
-    public WebSocketSessionFactory(SessionListener... sessionListeners)
+    public WebSocketSessionFactory(WebSocketContainerScope containerScope, SessionListener... sessionListeners)
     {
-        listeners = sessionListeners;
-    }
+        this.containerScope = containerScope;
+        if ((sessionListeners != null) && (sessionListeners.length > 0))
+        {
+            this.listeners = sessionListeners;
+        }
+        else
+        {
+            if (this.containerScope instanceof SessionListener)
+            {
+                this.listeners = new SessionListener[] { (SessionListener)containerScope };
+            }
+            else
+            {
+                this.listeners = new SessionListener[0];
+            }
+        }
+   }
 
     @Override
     public boolean supports(EventDriver websocket)
@@ -45,6 +62,6 @@
     @Override
     public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
     {
-        return new WebSocketSession(requestURI,websocket,connection,listeners);
+        return new WebSocketSession(containerScope, requestURI,websocket,connection,listeners);
     }
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
index 1bedab4..8224f2c 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
@@ -23,6 +23,7 @@
 
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.BatchMode;
@@ -40,11 +41,11 @@
 /**
  * EventDriver is the main interface between the User's WebSocket POJO and the internal jetty implementation of WebSocket.
  */
-public abstract class AbstractEventDriver implements IncomingFrames, EventDriver
+public abstract class AbstractEventDriver extends AbstractLifeCycle implements IncomingFrames, EventDriver
 {
     private static final Logger LOG = Log.getLogger(AbstractEventDriver.class);
     protected final Logger TARGET_LOG;
-    protected final WebSocketPolicy policy;
+    protected WebSocketPolicy policy;
     protected final Object websocket;
     protected WebSocketSession session;
     protected MessageAppender activeMessage;
@@ -222,6 +223,7 @@
         if (LOG.isDebugEnabled())
             LOG.debug("openSession({})",session);
         this.session = session;
+        this.session.getContainerScope().getObjectFactory().decorate(this.websocket);
         try
         {
             this.onConnect();
@@ -232,6 +234,12 @@
             throw t;
         }
     }
+    
+    @Override
+    protected void doStop() throws Exception
+    {
+        session = null;
+    }
 
     protected void terminateConnection(int statusCode, String rawreason)
     {
@@ -244,6 +252,12 @@
     {
         TARGET_LOG.warn("Unhandled Error (closing connection)",t);
         onError(t);
+        
+        if (t instanceof CloseException)
+        {
+            terminateConnection(((CloseException)t).getStatusCode(),t.getClass().getSimpleName());
+            return;
+        }
 
         // Unhandled Error, close the connection.
         switch (policy.getBehavior())
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverFactory.java
index 26d6185..3f5620d 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriverFactory.java
@@ -24,7 +24,9 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
+import org.eclipse.jetty.websocket.api.WebSocketListener;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
 
 /**
  * Create EventDriver implementations.
@@ -99,7 +101,7 @@
      * Wrap the given WebSocket object instance in a suitable EventDriver
      * 
      * @param websocket
-     *            the websocket instance to wrap. Must either implement {@link WebSocketListener} or be annotated with {@link WebSocket &#064WebSocket}
+     *            the websocket instance to wrap. Must either implement {@link WebSocketListener} or be annotated with {@link WebSocket &#064;WebSocket}
      * @return appropriate EventDriver for this websocket instance.
      */
     public EventDriver wrap(Object websocket)
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerEventDriver.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerEventDriver.java
index 07d99fa..cad31b0 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerEventDriver.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerEventDriver.java
@@ -25,12 +25,19 @@
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.WebSocketConnectionListener;
+import org.eclipse.jetty.websocket.api.WebSocketFrameListener;
 import org.eclipse.jetty.websocket.api.WebSocketListener;
+import org.eclipse.jetty.websocket.api.WebSocketPartialListener;
+import org.eclipse.jetty.websocket.api.WebSocketPingPongListener;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.api.extensions.Frame.Type;
 import org.eclipse.jetty.websocket.common.CloseInfo;
+import org.eclipse.jetty.websocket.common.frames.ReadOnlyDelegatedFrame;
 import org.eclipse.jetty.websocket.common.message.SimpleBinaryMessage;
 import org.eclipse.jetty.websocket.common.message.SimpleTextMessage;
+import org.eclipse.jetty.websocket.common.util.Utf8PartialBuilder;
 
 /**
  * Handler for {@link WebSocketListener} based User WebSocket implementations.
@@ -38,10 +45,11 @@
 public class JettyListenerEventDriver extends AbstractEventDriver
 {
     private static final Logger LOG = Log.getLogger(JettyListenerEventDriver.class);
-    private final WebSocketListener listener;
+    private final WebSocketConnectionListener listener;
+    private Utf8PartialBuilder utf8Partial;
     private boolean hasCloseBeenCalled = false;
 
-    public JettyListenerEventDriver(WebSocketPolicy policy, WebSocketListener listener)
+    public JettyListenerEventDriver(WebSocketPolicy policy, WebSocketConnectionListener listener)
     {
         super(policy,listener);
         this.listener = listener;
@@ -50,18 +58,29 @@
     @Override
     public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException
     {
-        if (activeMessage == null)
+        if (listener instanceof WebSocketListener)
         {
-            activeMessage = new SimpleBinaryMessage(this);
+            if (activeMessage == null)
+            {
+                activeMessage = new SimpleBinaryMessage(this);
+            }
+
+            appendMessage(buffer,fin);
         }
 
-        appendMessage(buffer,fin);
+        if (listener instanceof WebSocketPartialListener)
+        {
+            ((WebSocketPartialListener)listener).onWebSocketPartialBinary(buffer.slice().asReadOnlyBuffer(),fin);
+        }
     }
 
     @Override
     public void onBinaryMessage(byte[] data)
     {
-        listener.onWebSocketBinary(data,0,data.length);
+        if (listener instanceof WebSocketListener)
+        {
+            ((WebSocketListener)listener).onWebSocketBinary(data,0,data.length);
+        }
     }
 
     @Override
@@ -96,7 +115,22 @@
     @Override
     public void onFrame(Frame frame)
     {
-        /* ignore, not supported by WebSocketListener */
+        if (listener instanceof WebSocketFrameListener)
+        {
+            ((WebSocketFrameListener)listener).onWebSocketFrame(new ReadOnlyDelegatedFrame(frame));
+        }
+
+        if (listener instanceof WebSocketPingPongListener)
+        {
+            if (frame.getType() == Type.PING)
+            {
+                ((WebSocketPingPongListener)listener).onWebSocketPing(frame.getPayload().asReadOnlyBuffer());
+            }
+            else if (frame.getType() == Type.PONG)
+            {
+                ((WebSocketPingPongListener)listener).onWebSocketPong(frame.getPayload().asReadOnlyBuffer());
+            }
+        }
     }
 
     @Override
@@ -114,18 +148,46 @@
     @Override
     public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException
     {
-        if (activeMessage == null)
+        if (listener instanceof WebSocketListener)
         {
-            activeMessage = new SimpleTextMessage(this);
+            if (activeMessage == null)
+            {
+                activeMessage = new SimpleTextMessage(this);
+            }
+
+            appendMessage(buffer,fin);
         }
 
-        appendMessage(buffer,fin);
+        if (listener instanceof WebSocketPartialListener)
+        {
+            if (utf8Partial == null)
+            {
+                utf8Partial = new Utf8PartialBuilder();
+            }
+            
+            String partial = utf8Partial.toPartialString(buffer);
+            
+            ((WebSocketPartialListener)listener).onWebSocketPartialText(partial,fin);
+            
+            if (fin)
+            {
+                partial = null;
+            }
+        }
     }
 
+    /**
+     * Whole Message event.
+     * 
+     * @param message the whole message
+     */
     @Override
     public void onTextMessage(String message)
     {
-        listener.onWebSocketText(message);
+        if (listener instanceof WebSocketListener)
+        {
+            ((WebSocketListener)listener).onWebSocketText(message);
+        }
     }
 
     @Override
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerImpl.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerImpl.java
index 4d0a9de..d841daf 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerImpl.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyListenerImpl.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.events;
 
+import org.eclipse.jetty.websocket.api.WebSocketConnectionListener;
 import org.eclipse.jetty.websocket.api.WebSocketListener;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 
@@ -26,7 +27,7 @@
     @Override
     public EventDriver create(Object websocket, WebSocketPolicy policy)
     {
-        WebSocketListener listener = (WebSocketListener)websocket;
+        WebSocketConnectionListener listener = (WebSocketConnectionListener)websocket;
         return new JettyListenerEventDriver(policy,listener);
     }
 
@@ -39,6 +40,6 @@
     @Override
     public boolean supports(Object websocket)
     {
-        return (websocket instanceof WebSocketListener);
+        return (websocket instanceof WebSocketConnectionListener);
     }
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/AbstractMethodAnnotationScanner.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/AbstractMethodAnnotationScanner.java
index 8dd48fc..bd0011a 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/AbstractMethodAnnotationScanner.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/AbstractMethodAnnotationScanner.java
@@ -27,6 +27,7 @@
 
 /**
  * Basic scanner for Annotated Methods
+ * @param <T> The type of metadata
  */
 public abstract class AbstractMethodAnnotationScanner<T>
 {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
index a30b08f..ede7a20 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/annotated/CallableMethod.java
@@ -55,7 +55,8 @@
 
         if (obj == null)
         {
-            LOG.warn("Cannot call {} on null object",this.method);
+            String err = String.format("Cannot call %s on null object", this.method);
+            LOG.warn(new RuntimeException(err));            
             return null;
         }
 
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
index 36c1a79..58e8c90 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
@@ -35,6 +35,7 @@
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
 import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 
 @ManagedObject("Abstract Extension")
 public abstract class AbstractExtension extends ContainerLifeCycle implements Extension
@@ -67,6 +68,12 @@
         out.append(heading).append(" : ");
         out.append(bean.toString());
     }
+    
+    public void init(WebSocketContainerScope container)
+    {
+        this.policy = container.getPolicy();
+        this.bufferPool = container.getBufferPool();
+    }
 
     public ByteBufferPool getBufferPool()
     {
@@ -183,7 +190,7 @@
     {
         this.connection = connection;
     }
-
+    
     @Override
     public void setNextIncomingFrames(IncomingFrames nextIncoming)
     {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameCaptureExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameCaptureExtension.java
new file mode 100644
index 0000000..ef6c58c
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameCaptureExtension.java
@@ -0,0 +1,187 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.extensions;
+
+import static java.nio.file.StandardOpenOption.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Calendar;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.BatchMode;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.WriteCallback;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.common.Generator;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+
+public class FrameCaptureExtension extends AbstractExtension
+{
+    private static final Logger LOG = Log.getLogger(FrameCaptureExtension.class);
+
+    private static final int BUFSIZE = 32768;
+    private Generator generator;
+    private Path outputDir;
+    private String prefix = "frame";
+    private Path incomingFramesPath;
+    private Path outgoingFramesPath;
+    
+    private AtomicInteger incomingCount = new AtomicInteger(0);
+    private AtomicInteger outgoingCount = new AtomicInteger(0);
+
+    private SeekableByteChannel incomingChannel;
+    private SeekableByteChannel outgoingChannel;
+
+    @Override
+    public String getName()
+    {
+        return "@frame-capture";
+    }
+
+    @Override
+    public void incomingFrame(Frame frame)
+    {
+        saveFrame(frame,false);
+        try
+        {
+            nextIncomingFrame(frame);
+        }
+        catch (Throwable t)
+        {
+            IO.close(incomingChannel);
+            incomingChannel = null;
+            throw t;
+        }
+    }
+
+    @Override
+    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
+    {
+        saveFrame(frame,true);
+        try
+        {
+            nextOutgoingFrame(frame,callback,batchMode);
+        }
+        catch (Throwable t)
+        {
+            IO.close(outgoingChannel);
+            outgoingChannel = null;
+            throw t;
+        }
+    }
+
+    private void saveFrame(Frame frame, boolean outgoing)
+    {
+        if (outputDir == null || generator == null)
+        {
+            return;
+        }
+
+        @SuppressWarnings("resource")
+        SeekableByteChannel channel = (outgoing) ? outgoingChannel : incomingChannel;
+        
+        if (channel == null)
+        {
+            return;
+        }
+
+        ByteBuffer buf = getBufferPool().acquire(BUFSIZE,false);
+
+        try
+        {
+            WebSocketFrame f = WebSocketFrame.copy(frame);
+            f.setMasked(false);
+            generator.generateHeaderBytes(f,buf);
+            channel.write(buf);
+            if (frame.hasPayload())
+            {
+                channel.write(frame.getPayload().slice());
+            }
+            if (LOG.isDebugEnabled())
+                LOG.debug("Saved {} frame #{}",(outgoing) ? "outgoing" : "incoming",
+                        (outgoing) ? outgoingCount.incrementAndGet() : incomingCount.incrementAndGet());
+        }
+        catch (IOException e)
+        {
+            LOG.warn("Unable to save frame: " + frame,e);
+        }
+        finally
+        {
+            getBufferPool().release(buf);
+        }
+    }
+
+    @Override
+    public void setConfig(ExtensionConfig config)
+    {
+        super.setConfig(config);
+
+        String cfgOutputDir = config.getParameter("output-dir",null);
+        if (StringUtil.isNotBlank(cfgOutputDir))
+        {
+            Path path = new File(cfgOutputDir).toPath();
+            if (Files.isDirectory(path) && Files.exists(path) && Files.isWritable(path))
+            {
+                this.outputDir = path;
+            }
+            else
+            {
+                LOG.warn("Unable to configure {}: not a valid output directory",path.toAbsolutePath().toString());
+            }
+        }
+
+        String cfgPrefix = config.getParameter("prefix","frame");
+        if (StringUtil.isNotBlank(cfgPrefix))
+        {
+            this.prefix = cfgPrefix;
+        }
+
+        if (this.outputDir != null)
+        {
+            try
+            {
+                Path dir = this.outputDir.toRealPath();
+
+                // create a non-validating, read-only generator
+                String tstamp = String.format("%1$tY%1$tm%1$td-%1$tH%1$tM%1$tS",Calendar.getInstance());
+                incomingFramesPath = dir.resolve(String.format("%s-%s-incoming.dat",this.prefix,tstamp));
+                outgoingFramesPath = dir.resolve(String.format("%s-%s-outgoing.dat",this.prefix,tstamp));
+
+                incomingChannel = Files.newByteChannel(incomingFramesPath,CREATE,WRITE);
+                outgoingChannel = Files.newByteChannel(outgoingFramesPath,CREATE,WRITE);
+
+                this.generator = new Generator(WebSocketPolicy.newServerPolicy(),getBufferPool(),false,true);
+            }
+            catch (IOException e)
+            {
+                LOG.warn("Unable to create capture file(s)",e);
+            }
+        }
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameDebugExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameDebugExtension.java
deleted file mode 100644
index b811213..0000000
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/FrameDebugExtension.java
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.common.extensions;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SeekableByteChannel;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.BatchMode;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
-import org.eclipse.jetty.websocket.api.extensions.Frame;
-import org.eclipse.jetty.websocket.common.Generator;
-
-public class FrameDebugExtension extends AbstractExtension
-{
-    private static final Logger LOG = Log.getLogger(FrameDebugExtension.class);
-
-    private static final int BUFSIZE = 32768;
-    private Generator generator;
-    private Path outputDir;
-    private String prefix = "frame";
-    private AtomicLong incomingId = new AtomicLong(0);
-    private AtomicLong outgoingId = new AtomicLong(0);
-
-    @Override
-    public String getName()
-    {
-        return "@frame-debug";
-    }
-
-    @Override
-    public void incomingFrame(Frame frame)
-    {
-        saveFrame(frame,false);
-        nextIncomingFrame(frame);
-    }
-
-    @Override
-    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
-    {
-        saveFrame(frame,true);
-        nextOutgoingFrame(frame,callback,batchMode);
-    }
-
-    private void saveFrame(Frame frame, boolean outgoing)
-    {
-        if (outputDir == null || generator == null)
-        {
-            return;
-        }
-
-        StringBuilder filename = new StringBuilder();
-        filename.append(prefix);
-        if (outgoing)
-        {
-            filename.append(String.format("-outgoing-%05d",outgoingId.getAndIncrement()));
-        }
-        else
-        {
-            filename.append(String.format("-incoming-%05d",incomingId.getAndIncrement()));
-        }
-        filename.append(".dat");
-
-        Path outputFile = outputDir.resolve(filename.toString());
-        ByteBuffer buf = getBufferPool().acquire(BUFSIZE,false);
-        try (SeekableByteChannel channel = Files.newByteChannel(outputFile,StandardOpenOption.CREATE,StandardOpenOption.WRITE))
-        {
-            generator.generateHeaderBytes(frame,buf);
-            channel.write(buf);
-            if (frame.hasPayload())
-            {
-                channel.write(frame.getPayload().slice());
-            }
-            LOG.debug("Saved raw frame: {}",outputFile.toString());
-        }
-        catch (IOException e)
-        {
-            LOG.warn("Unable to save frame: " + filename.toString(),e);
-        }
-        finally
-        {
-            getBufferPool().release(buf);
-        }
-    }
-
-    @Override
-    public void setConfig(ExtensionConfig config)
-    {
-        super.setConfig(config);
-
-        String cfgOutputDir = config.getParameter("output-dir",null);
-        if (StringUtil.isNotBlank(cfgOutputDir))
-        {
-            Path path = new File(cfgOutputDir).toPath();
-            if (Files.isDirectory(path) && Files.exists(path) && Files.isWritable(path))
-            {
-                this.outputDir = path;
-            }
-            else
-            {
-                LOG.warn("Unable to configure {}: not a valid output directory",path.toAbsolutePath().toString());
-            }
-        }
-
-        String cfgPrefix = config.getParameter("prefix","frame");
-        if (StringUtil.isNotBlank(cfgPrefix))
-        {
-            this.prefix = cfgPrefix;
-        }
-
-        if (this.outputDir != null)
-        {
-            // create a non-validating, read-only generator
-            this.generator = new Generator(getPolicy(),getBufferPool(),false,true);
-        }
-    }
-}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
index 98beb4a..c111a8d 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/WebSocketExtensionFactory.java
@@ -18,24 +18,21 @@
 
 package org.eclipse.jetty.websocket.common.extensions;
 
-import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.websocket.api.WebSocketException;
-import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.Extension;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 
 public class WebSocketExtensionFactory extends ExtensionFactory
 {
-    private WebSocketPolicy policy;
-    private ByteBufferPool bufferPool;
+    private WebSocketContainerScope container;
 
-    public WebSocketExtensionFactory(WebSocketPolicy policy, ByteBufferPool bufferPool)
+    public WebSocketExtensionFactory(WebSocketContainerScope container)
     {
         super();
-        this.policy = policy;
-        this.bufferPool = bufferPool;
+        this.container = container;
     }
 
     @Override
@@ -60,12 +57,11 @@
 
         try
         {
-            Extension ext = extClass.newInstance();
+            Extension ext = container.getObjectFactory().createInstance(extClass);
             if (ext instanceof AbstractExtension)
             {
                 AbstractExtension aext = (AbstractExtension)ext;
-                aext.setPolicy(policy);
-                aext.setBufferPool(bufferPool);
+                aext.init(container);
                 aext.setConfig(config);
             }
             return ext;
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
index cfbe18f..6fc9b53 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java
@@ -154,30 +154,33 @@
             return;
         }
         byte[] output = new byte[DECOMPRESS_BUF_SIZE];
-
-        if (inflater.needsInput() && !supplyInput(inflater,buf))
+        
+        while(buf.hasRemaining() && inflater.needsInput())
         {
-            LOG.debug("Needed input, but no buffer could supply input");
-            return;
-        }
-
-        int read = 0;
-        while ((read = inflater.inflate(output)) >= 0)
-        {
-            if (read == 0)
+            if (!supplyInput(inflater,buf))
             {
-                LOG.debug("Decompress: read 0 {}",toDetail(inflater));
-                break;
+                LOG.debug("Needed input, but no buffer could supply input");
+                return;
             }
-            else
+    
+            int read = 0;
+            while ((read = inflater.inflate(output)) >= 0)
             {
-                // do something with output
-                if (LOG.isDebugEnabled())
+                if (read == 0)
                 {
-                    LOG.debug("Decompressed {} bytes: {}",read,toDetail(inflater));
+                    LOG.debug("Decompress: read 0 {}",toDetail(inflater));
+                    break;
                 }
-
-                accumulator.copyChunk(output,0,read);
+                else
+                {
+                    // do something with output
+                    if (LOG.isDebugEnabled())
+                    {
+                        LOG.debug("Decompressed {} bytes: {}",read,toDetail(inflater));
+                    }
+    
+                    accumulator.copyChunk(output,0,read);
+                }
             }
         }
 
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtension.java
index c03c23f..c307e53 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtension.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtension.java
@@ -32,7 +32,7 @@
 
 /**
  * Per Message Deflate Compression extension for WebSocket.
- * <p/>
+ * <p>
  * Attempts to follow <a href="https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-12">draft-ietf-hybi-permessage-compression-12</a>
  */
 public class PerMessageDeflateExtension extends CompressExtension
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/DataFrame.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/DataFrame.java
index 5c5bd5c..3b2332c 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/DataFrame.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/DataFrame.java
@@ -36,6 +36,7 @@
      * Construct new DataFrame based on headers of provided frame.
      * <p>
      * Useful for when working in extensions and a new frame needs to be created.
+     * @param basedOn the frame this one is based on
      */
     public DataFrame(Frame basedOn)
     {
@@ -46,6 +47,8 @@
      * Construct new DataFrame based on headers of provided frame, overriding for continuations if needed.
      * <p>
      * Useful for when working in extensions and a new frame needs to be created.
+     * @param basedOn the frame this one is based on
+     * @param continuation true if this is a continuation frame
      */
     public DataFrame(Frame basedOn, boolean continuation)
     {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/ReadOnlyDelegatedFrame.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/ReadOnlyDelegatedFrame.java
new file mode 100644
index 0000000..c454583
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/frames/ReadOnlyDelegatedFrame.java
@@ -0,0 +1,112 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.frames;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+
+/**
+ * Immutable, Read-only, Frame implementation.
+ */
+public class ReadOnlyDelegatedFrame implements Frame
+{
+    private final Frame delegate;
+    
+    public ReadOnlyDelegatedFrame(Frame frame)
+    {
+        this.delegate = frame;
+    }
+
+    @Override
+    public byte[] getMask()
+    {
+        return delegate.getMask();
+    }
+
+    @Override
+    public byte getOpCode()
+    {
+        return delegate.getOpCode();
+    }
+
+    @Override
+    public ByteBuffer getPayload()
+    {
+        if(!delegate.hasPayload()) {
+            return null;
+        }
+        return delegate.getPayload().asReadOnlyBuffer();
+    }
+
+    @Override
+    public int getPayloadLength()
+    {
+        return delegate.getPayloadLength();
+    }
+
+    @Override
+    public Type getType()
+    {
+        return delegate.getType();
+    }
+
+    @Override
+    public boolean hasPayload()
+    {
+        return delegate.hasPayload();
+    }
+
+    @Override
+    public boolean isFin()
+    {
+        return delegate.isFin();
+    }
+
+    @Override
+    @Deprecated
+    public boolean isLast()
+    {
+        return delegate.isLast();
+    }
+
+    @Override
+    public boolean isMasked()
+    {
+        return delegate.isMasked();
+    }
+
+    @Override
+    public boolean isRsv1()
+    {
+        return delegate.isRsv1();
+    }
+
+    @Override
+    public boolean isRsv2()
+    {
+        return delegate.isRsv2();
+    }
+
+    @Override
+    public boolean isRsv3()
+    {
+        return delegate.isRsv3();
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
index dfc57f6..a3a0ed3 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
@@ -32,6 +32,7 @@
 
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
@@ -52,13 +53,12 @@
 import org.eclipse.jetty.websocket.common.Generator;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
 import org.eclipse.jetty.websocket.common.Parser;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
 
 /**
- * Provides the implementation of {@link LogicalConnection} within the framework of the new {@link Connection} framework of {@code jetty-io}.
+ * Provides the implementation of {@link LogicalConnection} within the framework of the new {@link org.eclipse.jetty.io.Connection} framework of {@code jetty-io}.
  */
-public abstract class AbstractWebSocketConnection extends AbstractConnection implements LogicalConnection, ConnectionStateListener, Dumpable
+public abstract class AbstractWebSocketConnection extends AbstractConnection implements LogicalConnection, Connection.UpgradeTo, ConnectionStateListener, Dumpable 
 {
     private class Flusher extends FrameFlusher
     {
@@ -70,7 +70,7 @@
         @Override
         protected void onFailure(Throwable x)
         {
-            session.notifyError(x);
+            notifyError(x);
 
             if (ioState.wasAbnormalClose())
             {
@@ -156,8 +156,8 @@
 
         private void onLocalClose()
         {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Local Close Confirmed {}",close);
+            if (LOG_CLOSE.isDebugEnabled())
+                LOG_CLOSE.debug("Local Close Confirmed {}",close);
             if (close.isAbnormal())
             {
                 ioState.onAbnormalClose(close);
@@ -199,6 +199,8 @@
     }
 
     private static final Logger LOG = Log.getLogger(AbstractWebSocketConnection.class);
+    private static final Logger LOG_OPEN = Log.getLogger(AbstractWebSocketConnection.class.getName() + "_OPEN");
+    private static final Logger LOG_CLOSE = Log.getLogger(AbstractWebSocketConnection.class.getName() + "_CLOSE");
 
     /**
      * Minimum size of a buffer is the determined to be what would be the maximum framing header size (not including payload)
@@ -212,17 +214,16 @@
     private final WebSocketPolicy policy;
     private final AtomicBoolean suspendToken;
     private final FrameFlusher flusher;
-    private WebSocketSession session;
     private List<ExtensionConfig> extensions;
     private boolean isFilling;
-    private ByteBuffer buffer;
+    private ByteBuffer prefillBuffer;
     private ReadMode readMode = ReadMode.PARSE;
     private IOState ioState;
     private Stats stats = new Stats();
 
     public AbstractWebSocketConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
     {
-        super(endp,executor,EXECUTE_ONFILLABLE); // TODO review if this is best. Specifically with MUX
+        super(endp,executor);
         this.policy = policy;
         this.bufferPool = bufferPool;
         this.generator = new Generator(policy,bufferPool);
@@ -249,6 +250,8 @@
     @Override
     public void close()
     {
+        if(LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug(".close()");
         CloseInfo close = new CloseInfo();
         this.outgoingFrame(close.asFrame(),new OnCloseLocalCallback(close),BatchMode.OFF);
     }
@@ -268,8 +271,8 @@
     @Override
     public void close(int statusCode, String reason)
     {
-        if (LOG.isDebugEnabled())
-            LOG.debug("close({},{})",statusCode,reason);
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("close({},{})",statusCode,reason);
         CloseInfo close = new CloseInfo(statusCode,reason);
         this.outgoingFrame(close.asFrame(),new OnCloseLocalCallback(close),BatchMode.OFF);
     }
@@ -277,24 +280,27 @@
     @Override
     public void disconnect()
     {
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("{} disconnect()",policy.getBehavior());
         disconnect(false);
     }
 
     private void disconnect(boolean onlyOutput)
     {
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} disconnect({})",policy.getBehavior(),onlyOutput?"outputOnly":"both");
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("{} disconnect({})",policy.getBehavior(),onlyOutput?"outputOnly":"both");
         // close FrameFlusher, we cannot write anymore at this point.
         flusher.close();
         EndPoint endPoint = getEndPoint();
         // We need to gently close first, to allow
         // SSL close alerts to be sent by Jetty
-        if (LOG.isDebugEnabled())
-            LOG.debug("Shutting down output {}",endPoint);
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("Shutting down output {}",endPoint);
         endPoint.shutdownOutput();
         if (!onlyOutput)
         {
-            LOG.debug("Closing {}",endPoint);
+            if (LOG_CLOSE.isDebugEnabled())
+                LOG_CLOSE.debug("Closing {}",endPoint);
             endPoint.close();
         }
     }
@@ -382,12 +388,6 @@
         return scheduler;
     }
 
-    @Override
-    public WebSocketSession getSession()
-    {
-        return session;
-    }
-
     public Stats getStats()
     {
         return stats;
@@ -423,21 +423,31 @@
     @Override
     public void onConnectionStateChange(ConnectionState state)
     {
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} Connection State Change: {}",policy.getBehavior(),state);
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("{} Connection State Change: {}",policy.getBehavior(),state);
+        
         switch (state)
         {
             case OPEN:
-                if (BufferUtil.isEmpty(buffer))
+                if (BufferUtil.hasContent(prefillBuffer))
                 {
                     if (LOG.isDebugEnabled())
-                        LOG.debug("fillInterested");
-                    fillInterested();
+                    {
+                        LOG.debug("Parsing Upgrade prefill buffer ({} remaining)",prefillBuffer.remaining());
+                    }
+                    parser.parse(prefillBuffer);
                 }
-                else
-                    onFillable();
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("OPEN: normal fillInterested");
+                }
+                // TODO: investigate what happens if a failure occurs during prefill, and an attempt to write close fails,
+                // should a fill interested occur? or just a quick disconnect?
+                fillInterested();
                 break;
             case CLOSED:
+                if (LOG_CLOSE.isDebugEnabled())
+                    LOG_CLOSE.debug("CLOSED - wasAbnormalClose: {}", ioState.wasAbnormalClose());
                 if (ioState.wasAbnormalClose())
                 {
                     // Fire out a close frame, indicating abnormal shutdown, then disconnect
@@ -451,6 +461,8 @@
                 }
                 break;
             case CLOSING:
+                if (LOG_CLOSE.isDebugEnabled())
+                    LOG_CLOSE.debug("CLOSING - wasRemoteCloseInitiated: {}", ioState.wasRemoteCloseInitiated());
                 // First occurrence of .onCloseLocal or .onCloseRemote use
                 if (ioState.wasRemoteCloseInitiated())
                 {
@@ -469,8 +481,9 @@
         if (LOG.isDebugEnabled())
             LOG.debug("{} onFillable()",policy.getBehavior());
         stats.countOnFillableEvents.incrementAndGet();
-        if (buffer==null)
-            buffer = bufferPool.acquire(getInputBufferSize(),true);
+        
+        ByteBuffer buffer = bufferPool.acquire(getInputBufferSize(),true);
+        
         try
         {
             isFilling = true;
@@ -487,7 +500,6 @@
         finally
         {
             bufferPool.release(buffer);
-            buffer=null;
         }
 
         if ((readMode != ReadMode.EOF) && (suspendToken.get() == false))
@@ -510,14 +522,31 @@
         super.onFillInterestedFailed(cause);
     }
 
-    protected void prefill(ByteBuffer prefilled)
+    /**
+     * Extra bytes from the initial HTTP upgrade that need to
+     * be processed by the websocket parser before starting
+     * to read bytes from the connection
+     * @param prefilled the bytes of prefilled content encountered during upgrade
+     */
+    protected void setInitialBuffer(ByteBuffer prefilled)
     {
-        buffer=prefilled;
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("set Initial Buffer - {}",BufferUtil.toDetailString(prefilled));
+        }
+        prefillBuffer = prefilled;
+    }
+    
+    private void notifyError(Throwable t)
+    {
+        getParser().getIncomingFramesHandler().incomingError(t);
     }
     
     @Override
     public void onOpen()
     {
+        if(LOG_OPEN.isDebugEnabled())
+            LOG_OPEN.debug("[{}] {}.onOpened()",policy.getBehavior(),this.getClass().getSimpleName());
         super.onOpen();
         this.ioState.onOpened();
     }
@@ -530,11 +559,13 @@
     {
         IOState state = getIOState();
         ConnectionState cstate = state.getConnectionState();
-        if (LOG.isDebugEnabled())
-            LOG.debug("{} Read Timeout - {}",policy.getBehavior(),cstate);
+        if (LOG_CLOSE.isDebugEnabled())
+            LOG_CLOSE.debug("{} Read Timeout - {}",policy.getBehavior(),cstate);
 
         if (cstate == ConnectionState.CLOSED)
         {
+            if (LOG_CLOSE.isDebugEnabled())
+                LOG_CLOSE.debug("onReadTimeout - Connection Already CLOSED");
             // close already completed, extra timeouts not relevant
             // allow underlying connection and endpoint to disconnect on its own
             return true;
@@ -542,7 +573,7 @@
 
         try
         {
-            session.notifyError(new SocketTimeoutException("Timeout on Read"));
+            notifyError(new SocketTimeoutException("Timeout on Read"));
         }
         finally
         {
@@ -581,15 +612,14 @@
                 }
                 else if (filled < 0)
                 {
-                    LOG.debug("read - EOF Reached (remote: {})",getRemoteAddress());
+                    if (LOG_CLOSE.isDebugEnabled())
+                        LOG_CLOSE.debug("read - EOF Reached (remote: {})",getRemoteAddress());
                     return ReadMode.EOF;
                 }
                 else
                 {
-                    if (LOG.isDebugEnabled())
-                    {
-                        LOG.debug("Discarded {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
-                    }
+                    if (LOG_CLOSE.isDebugEnabled())
+                        LOG_CLOSE.debug("Discarded {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
                 }
             }
         }
@@ -610,27 +640,27 @@
         EndPoint endPoint = getEndPoint();
         try
         {
-            while (true) // TODO: should this honor the LogicalConnection.suspend() ?
+            // Process the content from the Endpoint next
+            while(true)  // TODO: should this honor the LogicalConnection.suspend() ?
             {
                 int filled = endPoint.fill(buffer);
-                if (filled == 0)
-                {
-                    return ReadMode.PARSE;
-                }
-                else if (filled < 0)
+                if (filled < 0)
                 {
                     LOG.debug("read - EOF Reached (remote: {})",getRemoteAddress());
                     ioState.onReadFailure(new EOFException("Remote Read EOF"));
                     return ReadMode.EOF;
                 }
-                else
+                else if (filled == 0)
                 {
-                    if (LOG.isDebugEnabled())
-                    {
-                        LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
-                    }
-                    parser.parse(buffer);
+                    // Done reading, wait for next onFillable
+                    return ReadMode.PARSE;
                 }
+                
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("Filled {} bytes - {}",filled,BufferUtil.toDetailString(buffer));
+                }
+                parser.parse(buffer);
             }
         }
         catch (IOException e)
@@ -653,7 +683,7 @@
             return ReadMode.DISCARD;
         }
     }
-
+    
     @Override
     public void resume()
     {
@@ -693,12 +723,6 @@
     }
 
     @Override
-    public void setSession(WebSocketSession session)
-    {
-        this.session = session;
-    }
-
-    @Override
     public SuspendToken suspend()
     {
         suspendToken.set(true);
@@ -720,7 +744,17 @@
     @Override
     public String toString()
     {
-        return String.format("%s{f=%s,g=%s,p=%s}",super.toString(),flusher,generator,parser);
+        return String.format("%s@%X{endp=%s,ios=%s,f=%s,g=%s,p=%s}",getClass().getSimpleName(),hashCode(),getEndPoint(),ioState,flusher,generator,parser);
     }
 
+    /**
+     * Extra bytes from the initial HTTP upgrade that need to
+     * be processed by the websocket parser before starting
+     * to read bytes from the connection
+     */
+    @Override
+    public void onUpgradeTo(ByteBuffer prefilled)
+    {
+        setInitialBuffer(prefilled);
+    }
 }
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java
index 26c0335..65edf0b 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java
@@ -40,7 +40,7 @@
 import org.eclipse.jetty.websocket.common.frames.BinaryFrame;
 
 /**
- * Interface for working with bytes destined for {@link EndPoint#write(Callback, ByteBuffer...)}
+ * Interface for working with bytes destined for {@link EndPoint#write(org.eclipse.jetty.util.Callback, ByteBuffer...)}
  */
 public class FrameFlusher
 {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FutureWriteCallback.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FutureWriteCallback.java
index 0de9e57..71f3d64 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FutureWriteCallback.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FutureWriteCallback.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.io;
 
+import java.util.concurrent.Future;
+
 import org.eclipse.jetty.util.FutureCallback;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
index 0284eae..e344db9 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/IOState.java
@@ -189,6 +189,7 @@
      * A websocket connection has been disconnected for abnormal close reasons.
      * <p>
      * This is the low level disconnect of the socket. It could be the result of a normal close operation, from an IO error, or even from a timeout.
+     * @param close the close information
      */
     public void onAbnormalClose(CloseInfo close)
     {
@@ -220,6 +221,7 @@
 
     /**
      * A close handshake has been issued from the local endpoint
+     * @param close the close information
      */
     public void onCloseLocal(CloseInfo close)
     {
@@ -248,6 +250,9 @@
         synchronized (this)
         {
             closeInfo = close;
+            
+            // Turn off further output
+            outputAvailable = false;
 
             boolean in = inputAvailable;
             boolean out = outputAvailable;
@@ -255,9 +260,7 @@
             {
                 closeHandshakeSource = CloseHandshakeSource.LOCAL;
             }
-            out = false;
-            outputAvailable = false;
-
+            
             LOG.debug("onCloseLocal(), input={}, output={}",in,out);
 
             if (!in && !out)
@@ -301,6 +304,7 @@
 
     /**
      * A close handshake has been received from the remote endpoint
+     * @param close the close information
      */
     public void onCloseRemote(CloseInfo close)
     {
@@ -316,6 +320,9 @@
             }
 
             closeInfo = close;
+            
+            // turn off further input
+            inputAvailable = false;
 
             boolean in = inputAvailable;
             boolean out = outputAvailable;
@@ -323,8 +330,6 @@
             {
                 closeHandshakeSource = CloseHandshakeSource.REMOTE;
             }
-            in = false;
-            inputAvailable = false;
 
             if (LOG.isDebugEnabled())
                 LOG.debug("onCloseRemote(), input={}, output={}",in,out);
@@ -399,6 +404,9 @@
      */
     public void onOpened()
     {
+        if(LOG.isDebugEnabled())
+            LOG.debug(" onOpened()");
+        
         ConnectionState event = null;
         synchronized (this)
         {
@@ -426,6 +434,7 @@
      * The local endpoint has reached a read failure.
      * <p>
      * This could be a normal result after a proper close handshake, or even a premature close due to a connection disconnect.
+     * @param t the read failure
      */
     public void onReadFailure(Throwable t)
     {
@@ -476,6 +485,7 @@
      * The local endpoint has reached a write failure.
      * <p>
      * A low level I/O failure, or even a jetty side EndPoint close (from idle timeout) are a few scenarios
+     * @param t the throwable that caused the write failure
      */
     public void onWriteFailure(Throwable t)
     {
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParser.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParser.java
index 4b49152..b306ef5 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParser.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/http/HttpResponseHeaderParser.java
@@ -80,7 +80,9 @@
             {
                 if (parseHeader(line))
                 {
-                    // Finished parsing entire header
+                    // Now finished with parsing the entire response header
+                    // Save the remaining bytes for WebSocket to process.
+                    
                     ByteBuffer copy = ByteBuffer.allocate(buf.remaining());
                     BufferUtil.put(buf,copy);
                     BufferUtil.flipToFlush(copy,0);
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/PayloadProcessor.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/PayloadProcessor.java
index f53ac34..eda94f3 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/PayloadProcessor.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/payload/PayloadProcessor.java
@@ -20,6 +20,7 @@
 
 import java.nio.ByteBuffer;
 
+import org.eclipse.jetty.websocket.api.BadPayloadException;
 import org.eclipse.jetty.websocket.api.extensions.Frame;
 
 /**
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java
index b4c1d9a..c1f0438 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageInputStream.java
@@ -32,7 +32,7 @@
 
 /**
  * Support class for reading a (single) WebSocket BINARY message via a InputStream.
- * <p/>
+ * <p>
  * An InputStream that can access a queue of ByteBuffer payloads, along with expected InputStream blocking behavior.
  */
 public class MessageInputStream extends InputStream implements MessageAppender
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageReader.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageReader.java
index a1144c3..a46b1d7 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageReader.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageReader.java
@@ -21,11 +21,12 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
 /**
  * Support class for reading a (single) WebSocket TEXT message via a Reader.
- * <p/>
+ * <p>
  * In compliance to the WebSocket spec, this reader always uses the UTF8 {@link Charset}.
  */
 public class MessageReader extends InputStreamReader implements MessageAppender
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageWriter.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageWriter.java
index c0cc59e..4ea653d 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageWriter.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/message/MessageWriter.java
@@ -36,7 +36,7 @@
 
 /**
  * Support for writing a single WebSocket TEXT message via a {@link Writer}
- * <p/>
+ * <p>
  * Note: Per WebSocket spec, all WebSocket TEXT messages must be encoded in UTF-8
  */
 public class MessageWriter extends Writer
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/package-info.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/package-info.java
index 8474905..21f6f89 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/package-info.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/package-info.java
@@ -21,7 +21,7 @@
  * <p>
  * A core set of internal implementation classes for the Jetty WebSocket API.
  * <p>
- * Note: do not reference or use classes present in this package space in your code. <br />
+ * Note: do not reference or use classes present in this package space in your code. <br>
  * Restrict your usage to the Jetty WebSocket API classes, the Jetty WebSocket Client API,
  * or the Jetty WebSocket Servlet API.
  */
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
new file mode 100644
index 0000000..a68574c
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
@@ -0,0 +1,108 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.scopes;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+
+public class SimpleContainerScope extends ContainerLifeCycle implements WebSocketContainerScope
+{
+    private final ByteBufferPool bufferPool;
+    private final DecoratedObjectFactory objectFactory;
+    private final WebSocketPolicy policy;
+    private Executor executor;
+    private SslContextFactory sslContextFactory;
+
+    public SimpleContainerScope(WebSocketPolicy policy)
+    {
+        this(policy,new MappedByteBufferPool(),new DecoratedObjectFactory());
+    }
+
+    public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool)
+    {
+        this(policy,bufferPool,new DecoratedObjectFactory());
+    }
+
+    public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory)
+    {
+        this.policy = policy;
+        this.bufferPool = bufferPool;
+        this.objectFactory = objectFactory;
+
+        QueuedThreadPool threadPool = new QueuedThreadPool();
+        String name = "WebSocketSimpleContainer@" + hashCode();
+        threadPool.setName(name);
+        threadPool.setDaemon(true);
+        this.executor = threadPool;
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+    }
+
+    @Override
+    protected void doStop() throws Exception
+    {
+        super.doStop();
+    }
+
+    @Override
+    public ByteBufferPool getBufferPool()
+    {
+        return this.bufferPool;
+    }
+
+    @Override
+    public Executor getExecutor()
+    {
+        return this.executor;
+    }
+
+    @Override
+    public DecoratedObjectFactory getObjectFactory()
+    {
+        return this.objectFactory;
+    }
+
+    @Override
+    public WebSocketPolicy getPolicy()
+    {
+        return this.policy;
+    }
+
+    @Override
+    public SslContextFactory getSslContextFactory()
+    {
+        return this.sslContextFactory;
+    }
+
+    public void setSslContextFactory(SslContextFactory sslContextFactory)
+    {
+        this.sslContextFactory = sslContextFactory;
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
new file mode 100644
index 0000000..0717cfc
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.scopes;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+
+/**
+ * Defined Scope for a WebSocketContainer.
+ */
+public interface WebSocketContainerScope
+{
+    /**
+     * The configured Container Buffer Pool.
+     * 
+     * @return the buffer pool (never null)
+     */
+    public ByteBufferPool getBufferPool();
+
+    /**
+     * Executor in use by the container.
+     * 
+     * @return the Executor in use by the container.
+     */
+    public Executor getExecutor();
+
+    /**
+     * Object Factory used to create objects.
+     * 
+     * @return Object Factory used to create instances of objects.
+     */
+    public DecoratedObjectFactory getObjectFactory();
+
+    /**
+     * The policy the container is running on.
+     * 
+     * @return the websocket policy
+     */
+    public WebSocketPolicy getPolicy();
+
+    /**
+     * The SslContextFactory in use by the container.
+     * 
+     * @return the SslContextFactory in use by the container (can be null if no SSL context is defined)
+     */
+    public SslContextFactory getSslContextFactory();
+}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketSessionScope.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketSessionScope.java
new file mode 100644
index 0000000..cc54747
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketSessionScope.java
@@ -0,0 +1,39 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.scopes;
+
+import org.eclipse.jetty.websocket.common.WebSocketSession;
+
+/**
+ * Defined Scope for a WebSocketSession (active connection)
+ */
+public interface WebSocketSessionScope
+{
+    /**
+     * Active {@link WebSocketSession} associated with this scope.
+     * @return the websocket session
+     */
+    WebSocketSession getWebSocketSession();
+
+    /**
+     * The parent {@link WebSocketContainerScope} for this session scope.
+     * @return the websocket container scope
+     */
+    WebSocketContainerScope getContainerScope();
+}
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/TextUtil.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/TextUtil.java
index f951921..7dfed50 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/TextUtil.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/TextUtil.java
@@ -43,7 +43,6 @@
 
     /**
      * Smash a long string to fit within the max string length, by taking the middle section of the string and replacing them with an ellipsis "..."
-     * <p>
      * 
      * <pre>
      * Examples:
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilder.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilder.java
new file mode 100644
index 0000000..9b0e0e0
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilder.java
@@ -0,0 +1,63 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.util;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.Utf8Appendable;
+import org.eclipse.jetty.util.Utf8StringBuilder;
+
+/**
+ * Similar in scope to the {@link Utf8StringBuilder}, but allowing partially constructed Strings without throwing
+ * Exceptions for incomplete UTF8 sequences.
+ * <p>
+ * A call to {@link #toPartialString(ByteBuffer)} will return the section of the String from the start to the last
+ * completed UTF8 sequence. Leaving incomplete sequences for a subsequent call to complete.
+ */
+public class Utf8PartialBuilder
+{
+    private final StringBuilder str;
+    private final Utf8Appendable utf8;
+
+    public Utf8PartialBuilder()
+    {
+        this.str = new StringBuilder();
+        this.utf8 = new Utf8Appendable(str)
+        {
+            @Override
+            public int length()
+            {
+                return str.length();
+            }
+        };
+    }
+
+    public String toPartialString(ByteBuffer buf)
+    {
+        if (buf == null)
+        {
+            // no change, return empty
+            return "";
+        }
+        utf8.append(buf);
+        String ret = str.toString();
+        str.setLength(0);
+        return ret;
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/examples/ListenerFrameSocket.java b/jetty-websocket/websocket-common/src/test/java/examples/ListenerFrameSocket.java
new file mode 100644
index 0000000..1c0c71f
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/examples/ListenerFrameSocket.java
@@ -0,0 +1,53 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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 examples;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketFrameListener;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.common.events.EventCapture;
+
+public class ListenerFrameSocket implements WebSocketFrameListener
+{
+    public EventCapture capture = new EventCapture();
+
+    @Override
+    public void onWebSocketClose(int statusCode, String reason)
+    {
+        capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
+    }
+
+    @Override
+    public void onWebSocketConnect(Session session)
+    {
+        capture.add("onWebSocketConnect(%s)",session);
+    }
+
+    @Override
+    public void onWebSocketError(Throwable cause)
+    {
+        capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
+    }
+    
+    @Override
+    public void onWebSocketFrame(Frame frame)
+    {
+        capture.add("onWebSocketFrame(%s, %d, %b)", frame.getType(), frame.getPayload().remaining(), frame.isFin());
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java
new file mode 100644
index 0000000..c343f5e
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPartialSocket.java
@@ -0,0 +1,60 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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 examples;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketPartialListener;
+import org.eclipse.jetty.websocket.common.events.EventCapture;
+
+public class ListenerPartialSocket implements WebSocketPartialListener
+{
+    public EventCapture capture = new EventCapture();
+
+    @Override
+    public void onWebSocketClose(int statusCode, String reason)
+    {
+        capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
+    }
+
+    @Override
+    public void onWebSocketConnect(Session session)
+    {
+        capture.add("onWebSocketConnect(%s)",session);
+    }
+
+    @Override
+    public void onWebSocketError(Throwable cause)
+    {
+        capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
+    }
+    
+    @Override
+    public void onWebSocketPartialText(String payload, boolean fin)
+    {
+        capture.add("onWebSocketPartialText('%s', %b)",payload,fin);
+    }
+    
+    @Override
+    public void onWebSocketPartialBinary(ByteBuffer payload, boolean fin)
+    {
+        capture.add("onWebSocketPartialBinary(%s [%d], %b)",payload,payload.remaining(),fin);
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/examples/ListenerPingPongSocket.java b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPingPongSocket.java
new file mode 100644
index 0000000..b0cd5ff
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/examples/ListenerPingPongSocket.java
@@ -0,0 +1,60 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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 examples;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketPingPongListener;
+import org.eclipse.jetty.websocket.common.events.EventCapture;
+
+public class ListenerPingPongSocket implements WebSocketPingPongListener
+{
+    public EventCapture capture = new EventCapture();
+
+    @Override
+    public void onWebSocketClose(int statusCode, String reason)
+    {
+        capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
+    }
+
+    @Override
+    public void onWebSocketConnect(Session session)
+    {
+        capture.add("onWebSocketConnect(%s)",session);
+    }
+
+    @Override
+    public void onWebSocketError(Throwable cause)
+    {
+        capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
+    }
+
+    @Override
+    public void onWebSocketPing(ByteBuffer payload)
+    {
+        capture.add("onWebSocketPing(%d)",payload.remaining());
+    }
+
+    @Override
+    public void onWebSocketPong(ByteBuffer payload)
+    {
+        capture.add("onWebSocketPong(%d)",payload.remaining());
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/CloseInfoTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/CloseInfoTest.java
index 89ed9e7..da59aeb 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/CloseInfoTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/CloseInfoTest.java
@@ -18,9 +18,15 @@
 
 package org.eclipse.jetty.websocket.common;
 
-import static org.eclipse.jetty.websocket.api.StatusCode.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.eclipse.jetty.websocket.api.StatusCode.FAILED_TLS_HANDSHAKE;
+import static org.eclipse.jetty.websocket.api.StatusCode.NORMAL;
+import static org.eclipse.jetty.websocket.api.StatusCode.NO_CLOSE;
+import static org.eclipse.jetty.websocket.api.StatusCode.NO_CODE;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
 
 import java.nio.ByteBuffer;
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorParserRoundtripTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorParserRoundtripTest.java
index 8ff660d..be2ce7b 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorParserRoundtripTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorParserRoundtripTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java
index 7274220..01c6147 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common;
 
+import static org.hamcrest.Matchers.is;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 
@@ -39,8 +41,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class GeneratorTest
 {
     private static final Logger LOG = Log.getLogger(GeneratorTest.WindowHelper.class);
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java
index cfa265c..33cd763 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketFrameTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java
index d3ae887..5eae421 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java
index 1386a3b..b91bdf7 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.ab;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -27,6 +27,7 @@
 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.common.Generator;
 import org.eclipse.jetty.websocket.common.OpCode;
 import org.eclipse.jetty.websocket.common.Parser;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java
index 7d0c2ba..c0c268e 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.ab;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 
@@ -26,6 +26,7 @@
 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.common.Generator;
 import org.eclipse.jetty.websocket.common.OpCode;
 import org.eclipse.jetty.websocket.common.Parser;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java
index c0b51cb..07d4a1f 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.ab;
 
+import static org.hamcrest.Matchers.is;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 
@@ -39,8 +41,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class TestABCase2
 {
     WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadBinarySignatureSocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadBinarySignatureSocket.java
index c961cce..3fb10e0 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadBinarySignatureSocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadBinarySignatureSocket.java
@@ -30,6 +30,11 @@
 {
     /**
      * Declaring a non-void return type
+     * @param session  the session
+     * @param buf the buffer
+     * @param offset the offset
+     * @param len the length
+     * @return the response boolean
      */
     @OnWebSocketMessage
     public boolean onBinary(Session session, byte buf[], int offset, int len)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateBinarySocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateBinarySocket.java
index ede0645..8595971 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateBinarySocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateBinarySocket.java
@@ -31,6 +31,9 @@
 {
     /**
      * First method
+     * @param payload the payload
+     * @param offset the offset
+     * @param len the len
      */
     @OnWebSocketMessage
     public void binMe(byte[] payload, int offset, int len)
@@ -40,6 +43,7 @@
 
     /**
      * Second method
+     * @param stream the input stream
      */
     @OnWebSocketMessage
     public void streamMe(InputStream stream)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateFrameSocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateFrameSocket.java
index 8b672b3..8493aaf 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateFrameSocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadDuplicateFrameSocket.java
@@ -27,6 +27,7 @@
 {
     /**
      * The get a frame
+     * @param frame the frame
      */
     @OnWebSocketFrame
     public void frameMe(Frame frame)
@@ -36,6 +37,7 @@
 
     /**
      * This is a duplicate frame type (should throw an exception attempting to use)
+     * @param frame the frame
      */
     @OnWebSocketFrame
     public void watchMe(Frame frame)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadTextSignatureSocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadTextSignatureSocket.java
index 3248acc..b634e63 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadTextSignatureSocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/BadTextSignatureSocket.java
@@ -30,6 +30,8 @@
 {
     /**
      * Declaring a static method
+     * @param session the session
+     * @param text the text message
      */
     @OnWebSocketMessage
     public static void onText(Session session, String text)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/FrameSocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/FrameSocket.java
index 0509e42..0c90c41 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/FrameSocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/annotations/FrameSocket.java
@@ -27,6 +27,7 @@
 {
     /**
      * A frame
+     * @param frame the frame
      */
     @OnWebSocketFrame
     public void frameMe(Frame frame)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventCapture.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventCapture.java
index 7e3ad4a..9a5cad2 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventCapture.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventCapture.java
@@ -18,6 +18,10 @@
 
 package org.eclipse.jetty.websocket.common.events;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.startsWith;
+
 import java.util.regex.Pattern;
 
 import org.eclipse.jetty.toolchain.test.EventQueue;
@@ -25,10 +29,6 @@
 import org.eclipse.jetty.util.log.Logger;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.startsWith;
-
 @SuppressWarnings("serial")
 public class EventCapture extends EventQueue<String>
 {
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java
index 9123e83..333e323 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java
@@ -30,7 +30,10 @@
 import org.eclipse.jetty.websocket.common.frames.PingFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.io.LocalWebSocketSession;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestName;
@@ -49,6 +52,14 @@
 
     @Rule
     public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
+    
+    private WebSocketContainerScope container;
+    
+    @Before
+    public void initContainer()
+    {
+        this.container = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
+    }
 
     private Frame makeBinaryFrame(String content, boolean fin)
     {
@@ -61,7 +72,7 @@
         AdapterConnectCloseSocket socket = new AdapterConnectCloseSocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.open();
             driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
@@ -78,7 +89,7 @@
         AnnotatedBinaryArraySocket socket = new AnnotatedBinaryArraySocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.open();
             driver.incomingFrame(makeBinaryFrame("Hello World",true));
@@ -97,7 +108,7 @@
         AnnotatedTextSocket socket = new AnnotatedTextSocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.open();
             driver.incomingError(new WebSocketException("oof"));
@@ -116,7 +127,7 @@
         AnnotatedFramesSocket socket = new AnnotatedFramesSocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.open();
             driver.incomingFrame(new PingFrame().setPayload("PING"));
@@ -140,7 +151,7 @@
         AnnotatedBinaryStreamSocket socket = new AnnotatedBinaryStreamSocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.open();
             driver.incomingFrame(makeBinaryFrame("Hello World",true));
@@ -154,12 +165,12 @@
     }
 
     @Test
-    public void testListener_Text() throws Exception
+    public void testListenerBasic_Text() throws Exception
     {
         ListenerBasicSocket socket = new ListenerBasicSocket();
         EventDriver driver = wrap(socket);
 
-        try (LocalWebSocketSession conn = new LocalWebSocketSession(testname,driver,bufferPool))
+        try (LocalWebSocketSession conn = new LocalWebSocketSession(container,testname,driver))
         {
             conn.start();
             conn.open();
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
index e61846f..6d84048 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.extensions;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -28,8 +28,9 @@
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.Extension;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
-import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
 import org.eclipse.jetty.websocket.common.extensions.identity.IdentityExtension;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
 import org.junit.Assert;
 import org.junit.Rule;
@@ -56,7 +57,9 @@
     private ExtensionStack createExtensionStack()
     {
         WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
-        ExtensionFactory factory = new WebSocketExtensionFactory(policy,bufferPool);
+        WebSocketContainerScope container = new SimpleContainerScope(policy,bufferPool);
+        
+        WebSocketExtensionFactory factory = new WebSocketExtensionFactory(container);
         return new ExtensionStack(factory);
     }
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java
index 28db1c7..7f30fc7 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.extensions;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.nio.ByteBuffer;
 import java.util.Collections;
@@ -33,6 +34,8 @@
 import org.eclipse.jetty.websocket.common.Parser;
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.ByteBufferAssert;
 import org.eclipse.jetty.websocket.common.test.IncomingFramesCapture;
 import org.eclipse.jetty.websocket.common.test.UnitParser;
@@ -126,7 +129,9 @@
     public ExtensionTool(WebSocketPolicy policy, ByteBufferPool bufferPool)
     {
         this.policy = policy;
-        this.factory = new WebSocketExtensionFactory(policy,bufferPool);
+        WebSocketContainerScope container = new SimpleContainerScope(policy, bufferPool);
+        WebSocketExtensionFactory extFactory = new WebSocketExtensionFactory(container);
+        this.factory = extFactory;
     }
 
     public Tester newTester(String parameterizedExtension)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java
index cee57cb..ed17295 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.extensions;
 
+import static org.hamcrest.Matchers.is;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -44,8 +46,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class FragmentExtensionTest
 {
     @Rule
@@ -140,6 +140,7 @@
 
     /**
      * Verify that outgoing text frames are fragmented by the maxLength configuration.
+     * @throws IOException on test failure
      */
     @Test
     public void testOutgoingFramesByMaxLength() throws IOException
@@ -212,6 +213,7 @@
 
     /**
      * Verify that outgoing text frames are fragmented by default configuration
+     * @throws IOException on test failure
      */
     @Test
     public void testOutgoingFramesDefaultConfig() throws IOException
@@ -276,6 +278,7 @@
 
     /**
      * Outgoing PING (Control Frame) should pass through extension unmodified
+     * @throws IOException on test failure
      */
     @Test
     public void testOutgoingPing() throws IOException
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java
index 02395d4..6585132 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.extensions;
 
+import static org.hamcrest.Matchers.is;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -36,8 +38,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class IdentityExtensionTest
 {
     /**
@@ -71,6 +71,7 @@
 
     /**
      * Verify that outgoing frames are unmodified
+     * @throws IOException on test failure
      */
     @Test
     public void testOutgoingFrames() throws IOException
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java
index 85a6fb0..d143bd9 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.websocket.common.extensions.compress;
 
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
@@ -25,6 +28,7 @@
 import java.util.List;
 
 import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.websocket.api.BatchMode;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
@@ -44,83 +48,61 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 /**
  * Client side behavioral tests for permessage-deflate extension.
- * <p/>
+ * <p>
  * See: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-15
  */
 public class PerMessageDeflateExtensionTest extends AbstractExtensionTest
 {
     @Rule
     public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
-
-    /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
-     * Section 8.2.3.4: Using a DEFLATE Block with BFINAL Set to 1
-     */
-    @Test
-    public void testDraft15_DeflateBlockWithBFinal1()
+    
+    private void assertEndsWithTail(String hexStr, boolean expectedResult)
     {
-        Tester tester = clientExtensions.newTester("permessage-deflate");
-
-        tester.assertNegotiated("permessage-deflate");
-
-        tester.parseIncomingHex(// 1 message
-                "0xc1 0x08", // header
-                "0xf3 0x48 0xcd 0xc9 0xc9 0x07 0x00 0x00" // example payload 
-        );
-
-        tester.assertHasFrames("Hello");
+        ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(hexStr));
+        assertThat("endsWithTail([" + hexStr + "])",CompressExtension.endsWithTail(buf),is(expectedResult));
+    }
+    
+    @Test
+    public void testEndsWithTailBytes()
+    {
+        assertEndsWithTail("11223344",false);
+        assertEndsWithTail("00",false);
+        assertEndsWithTail("0000",false);
+        assertEndsWithTail("FFFF0000",false);
+        assertEndsWithTail("880000FFFF",true);
+        assertEndsWithTail("0000FFFF",true);
     }
 
     /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
-     * Section 8.2.3.3: Using a DEFLATE Block with No Compression
-     */
-    @Test
-    public void testDraft15_DeflateBlockWithNoCompression()
-    {
-        Tester tester = clientExtensions.newTester("permessage-deflate");
-
-        tester.assertNegotiated("permessage-deflate");
-
-        tester.parseIncomingHex(// 1 message / no compression
-                "0xc1 0x0b 0x00 0x05 0x00 0xfa 0xff 0x48 0x65 0x6c 0x6c 0x6f 0x00" // example frame
-        );
-
-        tester.assertHasFrames("Hello");
-    }
-
-    /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
      * Section 8.2.3.1: A message compressed using 1 compressed DEFLATE block
      */
     @Test
-    public void testDraft15_Hello_UnCompressedBlock()
+    public void testDraft21_Hello_UnCompressedBlock()
     {
         Tester tester = clientExtensions.newTester("permessage-deflate");
 
         tester.assertNegotiated("permessage-deflate");
 
-        tester.parseIncomingHex(//basic, 1 block, compressed with 0 compression level (aka, uncompressed).
-                "0xc1 0x07 0xf2 0x48 0xcd 0xc9 0xc9 0x07 0x00" // example frame
+        tester.parseIncomingHex(
+                // basic, 1 block, compressed with 0 compression level (aka, uncompressed).
+                "0xc1 0x07",  // (HEADER added for this test)
+                "0xf2 0x48 0xcd 0xc9 0xc9 0x07 0x00" // example frame from RFC
         );
 
         tester.assertHasFrames("Hello");
     }
 
     /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
      * Section 8.2.3.1: A message compressed using 1 compressed DEFLATE block (with fragmentation)
      */
     @Test
-    public void testDraft15_Hello_UnCompressedBlock_Fragmented()
+    public void testDraft21_Hello_UnCompressedBlock_Fragmented()
     {
         Tester tester = clientExtensions.newTester("permessage-deflate");
 
@@ -138,12 +120,12 @@
     }
 
     /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
      * Section 8.2.3.2: Sharing LZ77 Sliding Window
      */
     @Test
-    public void testDraft15_SharingL77SlidingWindow_ContextTakeover()
+    public void testDraft21_SharingL77SlidingWindow_ContextTakeover()
     {
         Tester tester = clientExtensions.newTester("permessage-deflate");
 
@@ -161,12 +143,12 @@
     }
 
     /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
      * Section 8.2.3.2: Sharing LZ77 Sliding Window
      */
     @Test
-    public void testDraft15_SharingL77SlidingWindow_NoContextTakeover()
+    public void testDraft21_SharingL77SlidingWindow_NoContextTakeover()
     {
         Tester tester = clientExtensions.newTester("permessage-deflate");
 
@@ -185,12 +167,51 @@
     }
 
     /**
-     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-15.
-     * <p/>
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
+     * Section 8.2.3.3: Using a DEFLATE Block with No Compression
+     */
+    @Test
+    public void testDraft21_DeflateBlockWithNoCompression()
+    {
+        Tester tester = clientExtensions.newTester("permessage-deflate");
+
+        tester.assertNegotiated("permessage-deflate");
+
+        tester.parseIncomingHex(// 1 message / no compression
+                "0xc1 0x0b 0x00 0x05 0x00 0xfa 0xff 0x48 0x65 0x6c 0x6c 0x6f 0x00" // example frame
+        );
+
+        tester.assertHasFrames("Hello");
+    }
+
+    /**
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
+     * Section 8.2.3.4: Using a DEFLATE Block with BFINAL Set to 1
+     */
+    @Test
+    public void testDraft21_DeflateBlockWithBFinal1()
+    {
+        Tester tester = clientExtensions.newTester("permessage-deflate");
+
+        tester.assertNegotiated("permessage-deflate");
+
+        tester.parseIncomingHex(// 1 message
+                "0xc1 0x08", // header
+                "0xf3 0x48 0xcd 0xc9 0xc9 0x07 0x00 0x00" // example payload 
+        );
+
+        tester.assertHasFrames("Hello");
+    }
+
+    /**
+     * Decode payload example as seen in draft-ietf-hybi-permessage-compression-21.
+     * <p>
      * Section 8.2.3.5: Two DEFLATE Blocks in 1 Message
      */
     @Test
-    public void testDraft15_TwoDeflateBlocksOneMessage()
+    public void testDraft21_TwoDeflateBlocksOneMessage()
     {
         Tester tester = clientExtensions.newTester("permessage-deflate");
 
@@ -298,6 +319,7 @@
 
     /**
      * Outgoing PING (Control Frame) should pass through extension unmodified
+     * @throws IOException on test failure
      */
     @Test
     public void testOutgoingPing() throws IOException
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
index c936e85..71b8e3d 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
@@ -35,7 +35,6 @@
 import org.eclipse.jetty.websocket.common.CloseInfo;
 import org.eclipse.jetty.websocket.common.ConnectionState;
 import org.eclipse.jetty.websocket.common.LogicalConnection;
-import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
 import org.junit.rules.TestName;
 
@@ -150,12 +149,6 @@
     }
 
     @Override
-    public WebSocketSession getSession()
-    {
-        return null;
-    }
-
-    @Override
     public void incomingError(Throwable e)
     {
         incoming.incomingError(e);
@@ -236,11 +229,6 @@
     }
 
     @Override
-    public void setSession(WebSocketSession session)
-    {
-    }
-
-    @Override
     public SuspendToken suspend()
     {
         return null;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketSession.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketSession.java
index aacb0bc..9f84f19 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketSession.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketSession.java
@@ -20,9 +20,9 @@
 
 import java.net.URI;
 
-import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.websocket.common.WebSocketSession;
 import org.eclipse.jetty.websocket.common.events.EventDriver;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.OutgoingFramesCapture;
 import org.junit.rules.TestName;
 
@@ -31,9 +31,10 @@
     private String id;
     private OutgoingFramesCapture outgoingCapture;
 
-    public LocalWebSocketSession(TestName testname, EventDriver driver, ByteBufferPool bufferPool)
+    public LocalWebSocketSession(WebSocketContainerScope containerScope, TestName testname, EventDriver driver)
     {
-        super(URI.create("ws://localhost/LocalWebSocketSesssion/" + testname.getMethodName()),driver,new LocalWebSocketConnection(testname,bufferPool));
+        super(containerScope,URI.create("ws://localhost/LocalWebSocketSesssion/" + testname.getMethodName()),driver,
+                new LocalWebSocketConnection(testname,containerScope.getBufferPool()));
         this.id = testname.getMethodName();
         outgoingCapture = new OutgoingFramesCapture();
         setOutgoingHandler(outgoingCapture);
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
index 54736e7..8975c5a 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageInputStreamTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.message;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -49,7 +49,6 @@
         {
             // Append a single message (simple, short)
             ByteBuffer payload = BufferUtil.toBuffer("Hello World",StandardCharsets.UTF_8);
-            System.out.printf("payload = %s%n",BufferUtil.toDetailString(payload));
             boolean fin = true;
             stream.appendFrame(payload,fin);
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageOutputStreamTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageOutputStreamTest.java
index d040c01..25b73a6 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageOutputStreamTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageOutputStreamTest.java
@@ -33,6 +33,8 @@
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
 import org.eclipse.jetty.websocket.common.io.FramePipes;
 import org.eclipse.jetty.websocket.common.io.LocalWebSocketSession;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
 import org.junit.After;
 import org.junit.Assert;
@@ -73,6 +75,9 @@
 
         // Event Driver factory
         EventDriverFactory factory = new EventDriverFactory(policy);
+        
+        // Container
+        WebSocketContainerScope containerScope = new SimpleContainerScope(policy,bufferPool);
 
         // local socket
         EventDriver driver = factory.wrap(new TrackingSocket("local"));
@@ -81,7 +86,7 @@
         socket = new TrackingSocket("remote");
         OutgoingFrames socketPipe = FramePipes.to(factory.wrap(socket));
 
-        session = new LocalWebSocketSession(testname,driver,bufferPool);
+        session = new LocalWebSocketSession(containerScope,testname,driver);
 
         session.setPolicy(policy);
         // talk to our remote socket
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageWriterTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageWriterTest.java
index ad04670..b94357a 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageWriterTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/MessageWriterTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.message;
 
+import static org.hamcrest.Matchers.is;
+
 import java.util.Arrays;
 
 import org.eclipse.jetty.toolchain.test.TestTracker;
@@ -29,6 +31,8 @@
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
 import org.eclipse.jetty.websocket.common.io.FramePipes;
 import org.eclipse.jetty.websocket.common.io.LocalWebSocketSession;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
 import org.junit.After;
 import org.junit.Assert;
@@ -37,8 +41,6 @@
 import org.junit.Test;
 import org.junit.rules.TestName;
 
-import static org.hamcrest.Matchers.is;
-
 public class MessageWriterTest
 {
     private static final Logger LOG = Log.getLogger(MessageWriterTest.class);
@@ -72,6 +74,9 @@
         // Event Driver factory
         EventDriverFactory factory = new EventDriverFactory(policy);
 
+        // Container
+        WebSocketContainerScope containerScope = new SimpleContainerScope(policy,bufferPool);
+
         // local socket
         EventDriver driver = factory.wrap(new TrackingSocket("local"));
 
@@ -79,7 +84,7 @@
         socket = new TrackingSocket("remote");
         OutgoingFrames socketPipe = FramePipes.to(factory.wrap(socket));
 
-        session = new LocalWebSocketSession(testname,driver,bufferPool);
+        session = new LocalWebSocketSession(containerScope,testname,driver);
 
         session.setPolicy(policy);
         // talk to our remote socket
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingInputStreamSocket.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingInputStreamSocket.java
index 276119b..b85d561 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingInputStreamSocket.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/TrackingInputStreamSocket.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.message;
 
+import static org.hamcrest.Matchers.is;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.concurrent.CountDownLatch;
@@ -33,8 +35,6 @@
 import org.eclipse.jetty.websocket.api.annotations.WebSocket;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.is;
-
 @WebSocket
 public class TrackingInputStreamSocket
 {
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/Utf8CharBufferTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/Utf8CharBufferTest.java
index b7d5051..c677659 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/Utf8CharBufferTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/message/Utf8CharBufferTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.message;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java
index 76f55c1..2ebff22 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java
@@ -18,12 +18,15 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
@@ -40,6 +43,8 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import javax.net.ssl.HttpsURLConnection;
+
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.toolchain.test.EventQueue;
@@ -68,6 +73,7 @@
 import org.eclipse.jetty.websocket.common.io.IOState;
 import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
 import org.eclipse.jetty.websocket.common.io.http.HttpResponseHeaderParser;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
 import org.junit.Assert;
 
 /**
@@ -82,7 +88,7 @@
  * with regards to basic IO behavior, a write should work as expected, a read should work as expected, but <u>what</u> byte it sends or reads is not within its
  * scope.
  */
-public class BlockheadClient implements OutgoingFrames, ConnectionStateListener, AutoCloseable
+public class BlockheadClient implements OutgoingFrames, ConnectionStateListener, AutoCloseable, IBlockheadClient
 {
     private class FrameReadingThread extends Thread implements Runnable, IncomingFrames
     {
@@ -227,21 +233,33 @@
         this.generator = new Generator(policy,bufferPool);
         this.parser = new Parser(policy,bufferPool);
 
-        this.extensionFactory = new WebSocketExtensionFactory(policy,bufferPool);
+        this.extensionFactory = new WebSocketExtensionFactory(new SimpleContainerScope(policy,bufferPool));
         this.ioState = new IOState();
         this.ioState.addListener(this);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#addExtensions(java.lang.String)
+     */
+    @Override
     public void addExtensions(String xtension)
     {
         this.extensions.add(xtension);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#addHeader(java.lang.String)
+     */
+    @Override
     public void addHeader(String header)
     {
         this.headers.add(header);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#awaitDisconnect(long, java.util.concurrent.TimeUnit)
+     */
+    @Override
     public boolean awaitDisconnect(long timeout, TimeUnit unit) throws InterruptedException
     {
         return disconnectedLatch.await(timeout,unit);
@@ -257,6 +275,9 @@
         extensions.clear();
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#close()
+     */
     @Override
     public void close()
     {
@@ -264,6 +285,10 @@
         close(-1,null);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#close(int, java.lang.String)
+     */
+    @Override
     public void close(int statusCode, String message)
     {
         LOG.debug("close({},{})",statusCode,message);
@@ -279,6 +304,10 @@
         }
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#connect()
+     */
+    @Override
     public void connect() throws IOException
     {
         InetAddress destAddr = InetAddress.getByName(destHttpURI.getHost());
@@ -317,6 +346,10 @@
         }
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#expectServerDisconnect()
+     */
+    @Override
     public void expectServerDisconnect()
     {
         if (eof)
@@ -347,6 +380,10 @@
         }
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#expectUpgradeResponse()
+     */
+    @Override
     public HttpResponse expectUpgradeResponse() throws IOException
     {
         HttpResponse response = readResponseHeader();
@@ -460,6 +497,10 @@
         return ioState;
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#getProtocols()
+     */
+    @Override
     public String getProtocols()
     {
         return protocols;
@@ -591,6 +632,10 @@
         return frameReader.frames;
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#readResponseHeader()
+     */
+    @Override
     public HttpResponse readResponseHeader() throws IOException
     {
         HttpResponse response = new HttpResponse();
@@ -626,6 +671,10 @@
         return response;
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#sendStandardRequest()
+     */
+    @Override
     public void sendStandardRequest() throws IOException
     {
         StringBuilder req = generateUpgradeRequest();
@@ -670,11 +719,19 @@
         this.executor = executor;
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#setProtocols(java.lang.String)
+     */
+    @Override
     public void setProtocols(String protocols)
     {
         this.protocols = protocols;
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#setTimeout(int, java.util.concurrent.TimeUnit)
+     */
+    @Override
     public void setTimeout(int duration, TimeUnit unit)
     {
         this.timeout = (int)TimeUnit.MILLISECONDS.convert(duration,unit);
@@ -719,6 +776,10 @@
         LOG.info("Waking up from sleep");
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#write(org.eclipse.jetty.websocket.common.WebSocketFrame)
+     */
+    @Override
     public void write(WebSocketFrame frame) throws IOException
     {
         if (!ioState.isOpen())
@@ -738,12 +799,20 @@
         extensionStack.outgoingFrame(frame,null,BatchMode.OFF);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.nio.ByteBuffer)
+     */
+    @Override
     public void writeRaw(ByteBuffer buf) throws IOException
     {
         LOG.debug("write(ByteBuffer) {}",BufferUtil.toDetailString(buf));
         BufferUtil.writeTo(buf,out);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.nio.ByteBuffer, int)
+     */
+    @Override
     public void writeRaw(ByteBuffer buf, int numBytes) throws IOException
     {
         int len = Math.min(numBytes,buf.remaining());
@@ -752,12 +821,20 @@
         out.write(arr);
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.lang.String)
+     */
+    @Override
     public void writeRaw(String str) throws IOException
     {
         LOG.debug("write((String)[{}]){}{})",str.length(),'\n',str);
         out.write(str.getBytes(StandardCharsets.ISO_8859_1));
     }
 
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRawSlowly(java.nio.ByteBuffer, int)
+     */
+    @Override
     public void writeRawSlowly(ByteBuffer buf, int segmentSize) throws IOException
     {
         while (buf.remaining() > 0)
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java
index 89b401a..1995999 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java
@@ -20,52 +20,15 @@
 
 import static org.hamcrest.Matchers.*;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.net.SocketException;
 import java.net.URI;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.MappedByteBufferPool;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.api.BatchMode;
-import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
-import org.eclipse.jetty.websocket.api.extensions.Frame;
-import org.eclipse.jetty.websocket.api.extensions.Frame.Type;
-import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
-import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
-import org.eclipse.jetty.websocket.common.AcceptHash;
-import org.eclipse.jetty.websocket.common.CloseInfo;
-import org.eclipse.jetty.websocket.common.Generator;
-import org.eclipse.jetty.websocket.common.OpCode;
-import org.eclipse.jetty.websocket.common.Parser;
-import org.eclipse.jetty.websocket.common.WebSocketFrame;
-import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
-import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
-import org.eclipse.jetty.websocket.common.frames.CloseFrame;
 import org.junit.Assert;
 
 /**
@@ -75,548 +38,16 @@
  */
 public class BlockheadServer
 {
-    public static class ServerConnection implements IncomingFrames, OutgoingFrames, Runnable
-    {
-        private final int BUFFER_SIZE = 8192;
-        private final Socket socket;
-        private final ByteBufferPool bufferPool;
-        private final WebSocketPolicy policy;
-        private final IncomingFramesCapture incomingFrames;
-        private final Parser parser;
-        private final Generator generator;
-        private final AtomicInteger parseCount;
-        private final WebSocketExtensionFactory extensionRegistry;
-        private final AtomicBoolean echoing = new AtomicBoolean(false);
-        private Thread echoThread;
-
-        /** Set to true to disable timeouts (for debugging reasons) */
-        private boolean debug = false;
-        private OutputStream out;
-        private InputStream in;
-
-        private Map<String, String> extraResponseHeaders = new HashMap<>();
-        private OutgoingFrames outgoing = this;
-
-        public ServerConnection(Socket socket)
-        {
-            this.socket = socket;
-            this.incomingFrames = new IncomingFramesCapture();
-            this.policy = WebSocketPolicy.newServerPolicy();
-            this.policy.setMaxBinaryMessageSize(100000);
-            this.policy.setMaxTextMessageSize(100000);
-            // This is a blockhead server connection, no point tracking leaks on this object.
-            this.bufferPool = new MappedByteBufferPool(BUFFER_SIZE);
-            this.parser = new Parser(policy,bufferPool);
-            this.parseCount = new AtomicInteger(0);
-            this.generator = new Generator(policy,bufferPool,false);
-            this.extensionRegistry = new WebSocketExtensionFactory(policy,bufferPool);
-        }
-
-        /**
-         * Add an extra header for the upgrade response (from the server). No extra work is done to ensure the key and value are sane for http.
-         */
-        public void addResponseHeader(String rawkey, String rawvalue)
-        {
-            extraResponseHeaders.put(rawkey,rawvalue);
-        }
-
-        public void close() throws IOException
-        {
-            write(new CloseFrame());
-            flush();
-        }
-
-        public void close(int statusCode) throws IOException
-        {
-            CloseInfo close = new CloseInfo(statusCode);
-            write(close.asFrame());
-            flush();
-        }
-
-        public void disconnect()
-        {
-            LOG.debug("disconnect");
-            IO.close(in);
-            IO.close(out);
-            if (socket != null)
-            {
-                try
-                {
-                    socket.close();
-                }
-                catch (IOException ignore)
-                {
-                    /* ignore */
-                }
-            }
-        }
-
-        public void echoMessage(int expectedFrames, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
-        {
-            LOG.debug("Echo Frames [expecting {}]",expectedFrames);
-            IncomingFramesCapture cap = readFrames(expectedFrames,timeoutDuration,timeoutUnit);
-            // now echo them back.
-            for (Frame frame : cap.getFrames())
-            {
-                write(WebSocketFrame.copy(frame).setMasked(false));
-            }
-        }
-
-        public void flush() throws IOException
-        {
-            getOutputStream().flush();
-        }
-
-        public ByteBufferPool getBufferPool()
-        {
-            return bufferPool;
-        }
-
-        public IncomingFramesCapture getIncomingFrames()
-        {
-            return incomingFrames;
-        }
-
-        public InputStream getInputStream() throws IOException
-        {
-            if (in == null)
-            {
-                in = socket.getInputStream();
-            }
-            return in;
-        }
-
-        private OutputStream getOutputStream() throws IOException
-        {
-            if (out == null)
-            {
-                out = socket.getOutputStream();
-            }
-            return out;
-        }
-
-        public Parser getParser()
-        {
-            return parser;
-        }
-
-        public WebSocketPolicy getPolicy()
-        {
-            return policy;
-        }
-
-        @Override
-        public void incomingError(Throwable e)
-        {
-            incomingFrames.incomingError(e);
-        }
-
-        @Override
-        public void incomingFrame(Frame frame)
-        {
-            LOG.debug("incoming({})",frame);
-            int count = parseCount.incrementAndGet();
-            if ((count % 10) == 0)
-            {
-                LOG.info("Server parsed {} frames",count);
-            }
-            incomingFrames.incomingFrame(WebSocketFrame.copy(frame));
-
-            if (frame.getOpCode() == OpCode.CLOSE)
-            {
-                CloseInfo close = new CloseInfo(frame);
-                LOG.debug("Close frame: {}",close);
-            }
-
-            Type type = frame.getType();
-            if (echoing.get() && (type.isData() || type.isContinuation()))
-            {
-                try
-                {
-                    write(WebSocketFrame.copy(frame).setMasked(false));
-                }
-                catch (IOException e)
-                {
-                    LOG.warn(e);
-                }
-            }
-        }
-
-        @Override
-        public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
-        {
-            ByteBuffer headerBuf = generator.generateHeaderBytes(frame);
-            if (LOG.isDebugEnabled())
-            {
-                LOG.debug("writing out: {}",BufferUtil.toDetailString(headerBuf));
-            }
-
-            try
-            {
-                BufferUtil.writeTo(headerBuf,out);
-                if (frame.hasPayload())
-                    BufferUtil.writeTo(frame.getPayload(),out);
-                out.flush();
-                if (callback != null)
-                {
-                    callback.writeSuccess();
-                }
-
-                if (frame.getOpCode() == OpCode.CLOSE)
-                {
-                    disconnect();
-                }
-            }
-            catch (Throwable t)
-            {
-                if (callback != null)
-                {
-                    callback.writeFailed(t);
-                }
-            }
-        }
-
-        public List<ExtensionConfig> parseExtensions(List<String> requestLines)
-        {
-            List<ExtensionConfig> extensionConfigs = new ArrayList<>();
-            
-            List<String> hits = regexFind(requestLines, "^Sec-WebSocket-Extensions: (.*)$");
-
-            for (String econf : hits)
-            {
-                // found extensions
-                ExtensionConfig config = ExtensionConfig.parse(econf);
-                extensionConfigs.add(config);
-            }
-
-            return extensionConfigs;
-        }
-
-        public String parseWebSocketKey(List<String> requestLines)
-        {
-            List<String> hits = regexFind(requestLines,"^Sec-WebSocket-Key: (.*)$");
-            if (hits.size() <= 0)
-            {
-                return null;
-            }
-            
-            Assert.assertThat("Number of Sec-WebSocket-Key headers", hits.size(), is(1));
-            
-            String key = hits.get(0);
-            return key;
-        }
-
-        public int read(ByteBuffer buf) throws IOException
-        {
-            int len = 0;
-            while ((in.available() > 0) && (buf.remaining() > 0))
-            {
-                buf.put((byte)in.read());
-                len++;
-            }
-            return len;
-        }
-
-        public IncomingFramesCapture readFrames(int expectedCount, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
-        {
-            LOG.debug("Read: waiting for {} frame(s) from client",expectedCount);
-            int startCount = incomingFrames.size();
-
-            ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
-            BufferUtil.clearToFill(buf);
-            try
-            {
-                long msDur = TimeUnit.MILLISECONDS.convert(timeoutDuration,timeoutUnit);
-                long now = System.currentTimeMillis();
-                long expireOn = now + msDur;
-                LOG.debug("Now: {} - expireOn: {} ({} ms)",now,expireOn,msDur);
-
-                int len = 0;
-                while (incomingFrames.size() < (startCount + expectedCount))
-                {
-                    BufferUtil.clearToFill(buf);
-                    len = read(buf);
-                    if (len > 0)
-                    {
-                        LOG.debug("Read {} bytes",len);
-                        BufferUtil.flipToFlush(buf,0);
-                        parser.parse(buf);
-                    }
-                    try
-                    {
-                        TimeUnit.MILLISECONDS.sleep(20);
-                    }
-                    catch (InterruptedException gnore)
-                    {
-                        /* ignore */
-                    }
-                    if (!debug && (System.currentTimeMillis() > expireOn))
-                    {
-                        incomingFrames.dump();
-                        throw new TimeoutException(String.format("Timeout reading all %d expected frames. (managed to only read %d frame(s))",expectedCount,
-                                incomingFrames.size()));
-                    }
-                }
-            }
-            finally
-            {
-                bufferPool.release(buf);
-            }
-
-            return incomingFrames;
-        }
-
-        public String readRequest() throws IOException
-        {
-            LOG.debug("Reading client request");
-            StringBuilder request = new StringBuilder();
-            BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
-            for (String line = in.readLine(); line != null; line = in.readLine())
-            {
-                if (line.length() == 0)
-                {
-                    break;
-                }
-                request.append(line).append("\r\n");
-                LOG.debug("read line: {}",line);
-            }
-
-            LOG.debug("Client Request:{}{}","\n",request);
-            return request.toString();
-        }
-
-        public List<String> readRequestLines() throws IOException
-        {
-            LOG.debug("Reading client request header");
-            List<String> lines = new ArrayList<>();
-
-            BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
-            for (String line = in.readLine(); line != null; line = in.readLine())
-            {
-                if (line.length() == 0)
-                {
-                    break;
-                }
-                lines.add(line);
-            }
-
-            return lines;
-        }
-
-        public List<String> regexFind(List<String> lines, String pattern)
-        {
-            List<String> hits = new ArrayList<>();
-
-            Pattern patKey = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
-
-            Matcher mat;
-            for (String line : lines)
-            {
-                mat = patKey.matcher(line);
-                if (mat.matches())
-                {
-                    if (mat.groupCount() >= 1)
-                    {
-                        hits.add(mat.group(1));
-                    }
-                    else
-                    {
-                        hits.add(mat.group(0));
-                    }
-                }
-            }
-
-            return hits;
-        }
-
-        public void respond(String rawstr) throws IOException
-        {
-            LOG.debug("respond(){}{}","\n",rawstr);
-            getOutputStream().write(rawstr.getBytes());
-            flush();
-        }
-
-        @Override
-        public void run()
-        {
-            LOG.debug("Entering echo thread");
-
-            ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
-            BufferUtil.clearToFill(buf);
-            long readBytes = 0;
-            try
-            {
-                while (echoing.get())
-                {
-                    BufferUtil.clearToFill(buf);
-                    long len = read(buf);
-                    if (len > 0)
-                    {
-                        readBytes += len;
-                        LOG.debug("Read {} bytes",len);
-                        BufferUtil.flipToFlush(buf,0);
-                        parser.parse(buf);
-                    }
-
-                    try
-                    {
-                        TimeUnit.MILLISECONDS.sleep(20);
-                    }
-                    catch (InterruptedException gnore)
-                    {
-                        /* ignore */
-                    }
-                }
-            }
-            catch (IOException e)
-            {
-                LOG.debug("Exception during echo loop",e);
-            }
-            finally
-            {
-                LOG.debug("Read {} bytes",readBytes);
-                bufferPool.release(buf);
-            }
-        }
-
-        public void setSoTimeout(int ms) throws SocketException
-        {
-            socket.setSoTimeout(ms);
-        }
-
-        public void startEcho()
-        {
-            if (echoThread != null)
-            {
-                throw new IllegalStateException("Echo thread already declared!");
-            }
-            echoThread = new Thread(this,"BlockheadServer/Echo");
-            echoing.set(true);
-            echoThread.start();
-        }
-
-        public void stopEcho()
-        {
-            echoing.set(false);
-        }
-
-        public List<String> upgrade() throws IOException
-        {
-            List<String> requestLines = readRequestLines();
-            List<ExtensionConfig> extensionConfigs = parseExtensions(requestLines);
-            String key = parseWebSocketKey(requestLines);
-
-            LOG.debug("Client Request Extensions: {}",extensionConfigs);
-            LOG.debug("Client Request Key: {}",key);
-
-            Assert.assertThat("Request: Sec-WebSocket-Key",key,notNullValue());
-
-            // collect extensions configured in response header
-            ExtensionStack extensionStack = new ExtensionStack(extensionRegistry);
-            extensionStack.negotiate(extensionConfigs);
-
-            // Start with default routing
-            extensionStack.setNextIncoming(this);
-            extensionStack.setNextOutgoing(this);
-
-            // Configure Parser / Generator
-            extensionStack.configure(parser);
-            extensionStack.configure(generator);
-
-            // Start Stack
-            try
-            {
-                extensionStack.start();
-            }
-            catch (Exception e)
-            {
-                throw new IOException("Unable to start Extension Stack");
-            }
-
-            // Configure Parser
-            parser.setIncomingFramesHandler(extensionStack);
-
-            // Setup Response
-            StringBuilder resp = new StringBuilder();
-            resp.append("HTTP/1.1 101 Upgrade\r\n");
-            resp.append("Connection: upgrade\r\n");
-            resp.append("Sec-WebSocket-Accept: ");
-            resp.append(AcceptHash.hashKey(key)).append("\r\n");
-            if (extensionStack.hasNegotiatedExtensions())
-            {
-                // Respond to used extensions
-                resp.append("Sec-WebSocket-Extensions: ");
-                boolean delim = false;
-                for (ExtensionConfig ext : extensionStack.getNegotiatedExtensions())
-                {
-                    if (delim)
-                    {
-                        resp.append(", ");
-                    }
-                    resp.append(ext.getParameterizedName());
-                    delim = true;
-                }
-                resp.append("\r\n");
-            }
-            if (extraResponseHeaders.size() > 0)
-            {
-                for (Map.Entry<String, String> xheader : extraResponseHeaders.entrySet())
-                {
-                    resp.append(xheader.getKey());
-                    resp.append(": ");
-                    resp.append(xheader.getValue());
-                    resp.append("\r\n");
-                }
-            }
-            resp.append("\r\n");
-
-            // Write Response
-            LOG.debug("Response: {}",resp.toString());
-            write(resp.toString().getBytes());
-            return requestLines;
-        }
-
-        private void write(byte[] bytes) throws IOException
-        {
-            getOutputStream().write(bytes);
-        }
-
-        public void write(byte[] buf, int offset, int length) throws IOException
-        {
-            getOutputStream().write(buf,offset,length);
-        }
-
-        public void write(Frame frame) throws IOException
-        {
-            LOG.debug("write(Frame->{}) to {}",frame,outgoing);
-            outgoing.outgoingFrame(frame,null,BatchMode.OFF);
-        }
-
-        public void write(int b) throws IOException
-        {
-            getOutputStream().write(b);
-        }
-
-        public void write(ByteBuffer buf) throws IOException
-        {
-            byte arr[] = BufferUtil.toArray(buf);
-            if ((arr != null) && (arr.length > 0))
-            {
-                getOutputStream().write(arr);
-            }
-        }
-    }
-
     private static final Logger LOG = Log.getLogger(BlockheadServer.class);
     private ServerSocket serverSocket;
     private URI wsUri;
 
-    public ServerConnection accept() throws IOException
+    public IBlockheadServerConnection accept() throws IOException
     {
         LOG.debug(".accept()");
         assertIsStarted();
         Socket socket = serverSocket.accept();
-        return new ServerConnection(socket);
+        return new BlockheadServerConnection(socket);
     }
 
     private void assertIsStarted()
@@ -633,42 +64,6 @@
         return wsUri;
     }
 
-    public void respondToClient(Socket connection, String serverResponse) throws IOException
-    {
-        InputStream in = null;
-        InputStreamReader isr = null;
-        BufferedReader buf = null;
-        OutputStream out = null;
-        try
-        {
-            in = connection.getInputStream();
-            isr = new InputStreamReader(in);
-            buf = new BufferedReader(isr);
-            String line;
-            while ((line = buf.readLine()) != null)
-            {
-                // System.err.println(line);
-                if (line.length() == 0)
-                {
-                    // Got the "\r\n" line.
-                    break;
-                }
-            }
-
-            // System.out.println("[Server-Out] " + serverResponse);
-            out = connection.getOutputStream();
-            out.write(serverResponse.getBytes());
-            out.flush();
-        }
-        finally
-        {
-            IO.close(buf);
-            IO.close(isr);
-            IO.close(in);
-            IO.close(out);
-        }
-    }
-
     public void start() throws IOException
     {
         InetAddress addr = InetAddress.getByName("localhost");
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java
new file mode 100644
index 0000000..e7ccb6f
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java
@@ -0,0 +1,614 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.test;
+
+import static org.hamcrest.Matchers.*;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.BatchMode;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.WriteCallback;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
+import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
+import org.eclipse.jetty.websocket.api.extensions.Frame.Type;
+import org.eclipse.jetty.websocket.common.AcceptHash;
+import org.eclipse.jetty.websocket.common.CloseInfo;
+import org.eclipse.jetty.websocket.common.Generator;
+import org.eclipse.jetty.websocket.common.OpCode;
+import org.eclipse.jetty.websocket.common.Parser;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
+import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
+import org.eclipse.jetty.websocket.common.frames.CloseFrame;
+import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
+import org.junit.Assert;
+
+public class BlockheadServerConnection implements IncomingFrames, OutgoingFrames, Runnable, IBlockheadServerConnection
+{
+    private static final Logger LOG = Log.getLogger(BlockheadServerConnection.class);
+    
+    private final int BUFFER_SIZE = 8192;
+    private final Socket socket;
+    private final ByteBufferPool bufferPool;
+    private final WebSocketPolicy policy;
+    private final IncomingFramesCapture incomingFrames;
+    private final Parser parser;
+    private final Generator generator;
+    private final AtomicInteger parseCount;
+    private final WebSocketExtensionFactory extensionRegistry;
+    private final AtomicBoolean echoing = new AtomicBoolean(false);
+    private Thread echoThread;
+
+    /** Set to true to disable timeouts (for debugging reasons) */
+    private boolean debug = false;
+    private OutputStream out;
+    private InputStream in;
+
+    private Map<String, String> extraResponseHeaders = new HashMap<>();
+    private OutgoingFrames outgoing = this;
+
+    public BlockheadServerConnection(Socket socket)
+    {
+        this.socket = socket;
+        this.incomingFrames = new IncomingFramesCapture();
+        this.policy = WebSocketPolicy.newServerPolicy();
+        this.policy.setMaxBinaryMessageSize(100000);
+        this.policy.setMaxTextMessageSize(100000);
+        // This is a blockhead server connection, no point tracking leaks on this object.
+        this.bufferPool = new MappedByteBufferPool(BUFFER_SIZE);
+        this.parser = new Parser(policy,bufferPool);
+        this.parseCount = new AtomicInteger(0);
+        this.generator = new Generator(policy,bufferPool,false);
+        this.extensionRegistry = new WebSocketExtensionFactory(new SimpleContainerScope(policy,bufferPool));
+    }
+
+    /**
+     * Add an extra header for the upgrade response (from the server). No extra work is done to ensure the key and value are sane for http.
+     * @param rawkey the raw key
+     * @param rawvalue the raw value
+     */
+    public void addResponseHeader(String rawkey, String rawvalue)
+    {
+        extraResponseHeaders.put(rawkey,rawvalue);
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#close()
+     */
+    @Override
+    public void close() throws IOException
+    {
+        write(new CloseFrame());
+        flush();
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#close(int)
+     */
+    @Override
+    public void close(int statusCode) throws IOException
+    {
+        CloseInfo close = new CloseInfo(statusCode);
+        write(close.asFrame());
+        flush();
+    }
+
+    public void disconnect()
+    {
+        LOG.debug("disconnect");
+        IO.close(in);
+        IO.close(out);
+        if (socket != null)
+        {
+            try
+            {
+                socket.close();
+            }
+            catch (IOException ignore)
+            {
+                /* ignore */
+            }
+        }
+    }
+
+    public void echoMessage(int expectedFrames, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
+    {
+        LOG.debug("Echo Frames [expecting {}]",expectedFrames);
+        IncomingFramesCapture cap = readFrames(expectedFrames,timeoutDuration,timeoutUnit);
+        // now echo them back.
+        for (Frame frame : cap.getFrames())
+        {
+            write(WebSocketFrame.copy(frame).setMasked(false));
+        }
+    }
+
+    public void flush() throws IOException
+    {
+        getOutputStream().flush();
+    }
+
+    public ByteBufferPool getBufferPool()
+    {
+        return bufferPool;
+    }
+
+    public IncomingFramesCapture getIncomingFrames()
+    {
+        return incomingFrames;
+    }
+
+    public InputStream getInputStream() throws IOException
+    {
+        if (in == null)
+        {
+            in = socket.getInputStream();
+        }
+        return in;
+    }
+
+    private OutputStream getOutputStream() throws IOException
+    {
+        if (out == null)
+        {
+            out = socket.getOutputStream();
+        }
+        return out;
+    }
+
+    public Parser getParser()
+    {
+        return parser;
+    }
+
+    public WebSocketPolicy getPolicy()
+    {
+        return policy;
+    }
+
+    @Override
+    public void incomingError(Throwable e)
+    {
+        incomingFrames.incomingError(e);
+    }
+
+    @Override
+    public void incomingFrame(Frame frame)
+    {
+        LOG.debug("incoming({})",frame);
+        int count = parseCount.incrementAndGet();
+        if ((count % 10) == 0)
+        {
+            LOG.info("Server parsed {} frames",count);
+        }
+        incomingFrames.incomingFrame(WebSocketFrame.copy(frame));
+
+        if (frame.getOpCode() == OpCode.CLOSE)
+        {
+            CloseInfo close = new CloseInfo(frame);
+            LOG.debug("Close frame: {}",close);
+        }
+
+        Type type = frame.getType();
+        if (echoing.get() && (type.isData() || type.isContinuation()))
+        {
+            try
+            {
+                write(WebSocketFrame.copy(frame).setMasked(false));
+            }
+            catch (IOException e)
+            {
+                LOG.warn(e);
+            }
+        }
+    }
+
+    @Override
+    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
+    {
+        ByteBuffer headerBuf = generator.generateHeaderBytes(frame);
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("writing out: {}",BufferUtil.toDetailString(headerBuf));
+        }
+
+        try
+        {
+            BufferUtil.writeTo(headerBuf,out);
+            if (frame.hasPayload())
+                BufferUtil.writeTo(frame.getPayload(),out);
+            out.flush();
+            if (callback != null)
+            {
+                callback.writeSuccess();
+            }
+
+            if (frame.getOpCode() == OpCode.CLOSE)
+            {
+                disconnect();
+            }
+        }
+        catch (Throwable t)
+        {
+            if (callback != null)
+            {
+                callback.writeFailed(t);
+            }
+        }
+    }
+
+    public List<ExtensionConfig> parseExtensions(List<String> requestLines)
+    {
+        List<ExtensionConfig> extensionConfigs = new ArrayList<>();
+        
+        List<String> hits = regexFind(requestLines, "^Sec-WebSocket-Extensions: (.*)$");
+
+        for (String econf : hits)
+        {
+            // found extensions
+            ExtensionConfig config = ExtensionConfig.parse(econf);
+            extensionConfigs.add(config);
+        }
+
+        return extensionConfigs;
+    }
+
+    public String parseWebSocketKey(List<String> requestLines)
+    {
+        List<String> hits = regexFind(requestLines,"^Sec-WebSocket-Key: (.*)$");
+        if (hits.size() <= 0)
+        {
+            return null;
+        }
+        
+        Assert.assertThat("Number of Sec-WebSocket-Key headers", hits.size(), is(1));
+        
+        String key = hits.get(0);
+        return key;
+    }
+
+    public int read(ByteBuffer buf) throws IOException
+    {
+        int len = 0;
+        while ((in.available() > 0) && (buf.remaining() > 0))
+        {
+            buf.put((byte)in.read());
+            len++;
+        }
+        return len;
+    }
+
+    public IncomingFramesCapture readFrames(int expectedCount, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
+    {
+        LOG.debug("Read: waiting for {} frame(s) from client",expectedCount);
+        int startCount = incomingFrames.size();
+
+        ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
+        BufferUtil.clearToFill(buf);
+        try
+        {
+            long msDur = TimeUnit.MILLISECONDS.convert(timeoutDuration,timeoutUnit);
+            long now = System.currentTimeMillis();
+            long expireOn = now + msDur;
+            LOG.debug("Now: {} - expireOn: {} ({} ms)",now,expireOn,msDur);
+
+            int len = 0;
+            while (incomingFrames.size() < (startCount + expectedCount))
+            {
+                BufferUtil.clearToFill(buf);
+                len = read(buf);
+                if (len > 0)
+                {
+                    LOG.debug("Read {} bytes",len);
+                    BufferUtil.flipToFlush(buf,0);
+                    parser.parse(buf);
+                }
+                try
+                {
+                    TimeUnit.MILLISECONDS.sleep(20);
+                }
+                catch (InterruptedException gnore)
+                {
+                    /* ignore */
+                }
+                if (!debug && (System.currentTimeMillis() > expireOn))
+                {
+                    incomingFrames.dump();
+                    throw new TimeoutException(String.format("Timeout reading all %d expected frames. (managed to only read %d frame(s))",expectedCount,
+                            incomingFrames.size()));
+                }
+            }
+        }
+        finally
+        {
+            bufferPool.release(buf);
+        }
+
+        return incomingFrames;
+    }
+
+    public String readRequest() throws IOException
+    {
+        LOG.debug("Reading client request");
+        StringBuilder request = new StringBuilder();
+        BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
+        for (String line = in.readLine(); line != null; line = in.readLine())
+        {
+            if (line.length() == 0)
+            {
+                break;
+            }
+            request.append(line).append("\r\n");
+            LOG.debug("read line: {}",line);
+        }
+
+        LOG.debug("Client Request:{}{}","\n",request);
+        return request.toString();
+    }
+
+    public List<String> readRequestLines() throws IOException
+    {
+        LOG.debug("Reading client request header");
+        List<String> lines = new ArrayList<>();
+
+        BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
+        for (String line = in.readLine(); line != null; line = in.readLine())
+        {
+            if (line.length() == 0)
+            {
+                break;
+            }
+            lines.add(line);
+        }
+
+        return lines;
+    }
+
+    public List<String> regexFind(List<String> lines, String pattern)
+    {
+        List<String> hits = new ArrayList<>();
+
+        Pattern patKey = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
+
+        Matcher mat;
+        for (String line : lines)
+        {
+            mat = patKey.matcher(line);
+            if (mat.matches())
+            {
+                if (mat.groupCount() >= 1)
+                {
+                    hits.add(mat.group(1));
+                }
+                else
+                {
+                    hits.add(mat.group(0));
+                }
+            }
+        }
+
+        return hits;
+    }
+
+    public void respond(String rawstr) throws IOException
+    {
+        LOG.debug("respond(){}{}","\n",rawstr);
+        getOutputStream().write(rawstr.getBytes());
+        flush();
+    }
+
+    @Override
+    public void run()
+    {
+        LOG.debug("Entering echo thread");
+
+        ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
+        BufferUtil.clearToFill(buf);
+        long readBytes = 0;
+        try
+        {
+            while (echoing.get())
+            {
+                BufferUtil.clearToFill(buf);
+                long len = read(buf);
+                if (len > 0)
+                {
+                    readBytes += len;
+                    LOG.debug("Read {} bytes",len);
+                    BufferUtil.flipToFlush(buf,0);
+                    parser.parse(buf);
+                }
+
+                try
+                {
+                    TimeUnit.MILLISECONDS.sleep(20);
+                }
+                catch (InterruptedException gnore)
+                {
+                    /* ignore */
+                }
+            }
+        }
+        catch (IOException e)
+        {
+            LOG.debug("Exception during echo loop",e);
+        }
+        finally
+        {
+            LOG.debug("Read {} bytes",readBytes);
+            bufferPool.release(buf);
+        }
+    }
+
+    public void setSoTimeout(int ms) throws SocketException
+    {
+        socket.setSoTimeout(ms);
+    }
+
+    public void startEcho()
+    {
+        if (echoThread != null)
+        {
+            throw new IllegalStateException("Echo thread already declared!");
+        }
+        echoThread = new Thread(this,"BlockheadServer/Echo");
+        echoing.set(true);
+        echoThread.start();
+    }
+
+    public void stopEcho()
+    {
+        echoing.set(false);
+    }
+
+    public List<String> upgrade() throws IOException
+    {
+        List<String> requestLines = readRequestLines();
+        List<ExtensionConfig> extensionConfigs = parseExtensions(requestLines);
+        String key = parseWebSocketKey(requestLines);
+
+        LOG.debug("Client Request Extensions: {}",extensionConfigs);
+        LOG.debug("Client Request Key: {}",key);
+
+        Assert.assertThat("Request: Sec-WebSocket-Key",key,notNullValue());
+
+        // collect extensions configured in response header
+        ExtensionStack extensionStack = new ExtensionStack(extensionRegistry);
+        extensionStack.negotiate(extensionConfigs);
+
+        // Start with default routing
+        extensionStack.setNextIncoming(this);
+        extensionStack.setNextOutgoing(this);
+
+        // Configure Parser / Generator
+        extensionStack.configure(parser);
+        extensionStack.configure(generator);
+
+        // Start Stack
+        try
+        {
+            extensionStack.start();
+        }
+        catch (Exception e)
+        {
+            throw new IOException("Unable to start Extension Stack");
+        }
+
+        // Configure Parser
+        parser.setIncomingFramesHandler(extensionStack);
+
+        // Setup Response
+        StringBuilder resp = new StringBuilder();
+        resp.append("HTTP/1.1 101 Upgrade\r\n");
+        resp.append("Connection: upgrade\r\n");
+        resp.append("Sec-WebSocket-Accept: ");
+        resp.append(AcceptHash.hashKey(key)).append("\r\n");
+        if (extensionStack.hasNegotiatedExtensions())
+        {
+            // Respond to used extensions
+            resp.append("Sec-WebSocket-Extensions: ");
+            boolean delim = false;
+            for (ExtensionConfig ext : extensionStack.getNegotiatedExtensions())
+            {
+                if (delim)
+                {
+                    resp.append(", ");
+                }
+                resp.append(ext.getParameterizedName());
+                delim = true;
+            }
+            resp.append("\r\n");
+        }
+        if (extraResponseHeaders.size() > 0)
+        {
+            for (Map.Entry<String, String> xheader : extraResponseHeaders.entrySet())
+            {
+                resp.append(xheader.getKey());
+                resp.append(": ");
+                resp.append(xheader.getValue());
+                resp.append("\r\n");
+            }
+        }
+        resp.append("\r\n");
+
+        // Write Response
+        LOG.debug("Response: {}",resp.toString());
+        write(resp.toString().getBytes());
+        return requestLines;
+    }
+
+    private void write(byte[] bytes) throws IOException
+    {
+        getOutputStream().write(bytes);
+    }
+
+    public void write(byte[] buf, int offset, int length) throws IOException
+    {
+        getOutputStream().write(buf,offset,length);
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#write(org.eclipse.jetty.websocket.api.extensions.Frame)
+     */
+    @Override
+    public void write(Frame frame) throws IOException
+    {
+        LOG.debug("write(Frame->{}) to {}",frame,outgoing);
+        outgoing.outgoingFrame(frame,null,BatchMode.OFF);
+    }
+
+    public void write(int b) throws IOException
+    {
+        getOutputStream().write(b);
+    }
+
+    public void write(ByteBuffer buf) throws IOException
+    {
+        byte arr[] = BufferUtil.toArray(buf);
+        if ((arr != null) && (arr.length > 0))
+        {
+            getOutputStream().write(arr);
+        }
+    }
+}
\ No newline at end of file
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/ByteBufferAssert.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/ByteBufferAssert.java
index 7fd2022..3834a25 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/ByteBufferAssert.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/ByteBufferAssert.java
@@ -18,8 +18,9 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
 
 import java.nio.ByteBuffer;
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
new file mode 100644
index 0000000..a5a1ba6
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
@@ -0,0 +1,149 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.test;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Executor;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.websocket.api.BatchMode;
+import org.eclipse.jetty.websocket.api.SuspendToken;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.WriteCallback;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
+import org.eclipse.jetty.websocket.common.LogicalConnection;
+import org.eclipse.jetty.websocket.common.io.IOState;
+
+public class DummyConnection implements LogicalConnection
+{
+    private static final Logger LOG = Log.getLogger(DummyConnection.class);
+    private IOState iostate;
+
+    public DummyConnection()
+    {
+        this.iostate = new IOState();
+    }
+
+    @Override
+    public void close()
+    {
+    }
+
+    @Override
+    public void close(int statusCode, String reason)
+    {
+    }
+
+    @Override
+    public void disconnect()
+    {
+    }
+
+    @Override
+    public ByteBufferPool getBufferPool()
+    {
+        return null;
+    }
+
+    @Override
+    public Executor getExecutor()
+    {
+        return null;
+    }
+
+    @Override
+    public long getIdleTimeout()
+    {
+        return 0;
+    }
+
+    @Override
+    public IOState getIOState()
+    {
+        return this.iostate;
+    }
+
+    @Override
+    public InetSocketAddress getLocalAddress()
+    {
+        return null;
+    }
+
+    @Override
+    public long getMaxIdleTimeout()
+    {
+        return 0;
+    }
+
+    @Override
+    public WebSocketPolicy getPolicy()
+    {
+        return null;
+    }
+
+    @Override
+    public InetSocketAddress getRemoteAddress()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isReading()
+    {
+        return false;
+    }
+
+    @Override
+    public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
+    {
+        callback.writeSuccess();
+    }
+
+    @Override
+    public void resume()
+    {
+    }
+
+    @Override
+    public void setMaxIdleTimeout(long ms)
+    {
+    }
+
+    @Override
+    public void setNextIncomingFrames(IncomingFrames incoming)
+    {
+        if (LOG.isDebugEnabled())
+            LOG.debug("setNextIncomingFrames({})",incoming);
+    }
+
+    @Override
+    public SuspendToken suspend()
+    {
+        return null;
+    }
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Fuzzer.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Fuzzer.java
index ae5c98f..097f4c4 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Fuzzer.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/Fuzzer.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import java.io.IOException;
 import java.net.SocketException;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadClient.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadClient.java
new file mode 100644
index 0000000..3d42e39
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadClient.java
@@ -0,0 +1,79 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.test;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+
+/**
+ * Interface for BlockheadClient.
+ */
+public interface IBlockheadClient extends AutoCloseable
+{
+    public void addExtensions(String xtension);
+
+    public void addHeader(String header);
+
+    public boolean awaitDisconnect(long timeout, TimeUnit unit) throws InterruptedException;
+
+    public void close();
+
+    public void close(int statusCode, String message);
+
+    public void connect() throws IOException;
+
+    public void disconnect();
+
+    public void expectServerDisconnect();
+
+    public HttpResponse expectUpgradeResponse() throws IOException;
+
+    public InetSocketAddress getLocalSocketAddress();
+
+    public String getProtocols();
+
+    public InetSocketAddress getRemoteSocketAddress();
+
+    public EventQueue<WebSocketFrame> readFrames(int expectedFrameCount, int timeoutDuration, TimeUnit timeoutUnit) throws Exception;
+
+    public HttpResponse readResponseHeader() throws IOException;
+
+    public void sendStandardRequest() throws IOException;
+
+    public void setConnectionValue(String connectionValue);
+
+    public void setProtocols(String protocols);
+
+    public void setTimeout(int duration, TimeUnit unit);
+
+    public void write(WebSocketFrame frame) throws IOException;
+
+    public void writeRaw(ByteBuffer buf) throws IOException;
+
+    public void writeRaw(ByteBuffer buf, int numBytes) throws IOException;
+
+    public void writeRaw(String str) throws IOException;
+
+    public void writeRawSlowly(ByteBuffer buf, int segmentSize) throws IOException;
+}
\ No newline at end of file
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadServerConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadServerConnection.java
new file mode 100644
index 0000000..7858479
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IBlockheadServerConnection.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.test;
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.io.ByteBufferPool;
+import org.eclipse.jetty.websocket.api.extensions.Frame;
+import org.eclipse.jetty.websocket.common.Parser;
+
+public interface IBlockheadServerConnection
+{
+    public void close() throws IOException;
+
+    public void close(int statusCode) throws IOException;
+
+    public void write(Frame frame) throws IOException;
+
+    public List<String> upgrade() throws IOException;
+
+    public void disconnect();
+
+    public IncomingFramesCapture readFrames(int expectedCount, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException;
+    public void write(ByteBuffer buf) throws IOException;
+    public List<String> readRequestLines() throws IOException;
+    public String parseWebSocketKey(List<String> requestLines);
+    public void respond(String rawstr) throws IOException;
+    public String readRequest() throws IOException;
+    public List<String> regexFind(List<String> lines, String pattern);
+    public void echoMessage(int expectedFrames, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException;
+    public void setSoTimeout(int ms) throws SocketException;
+    public ByteBufferPool getBufferPool();
+    public int read(ByteBuffer buf) throws IOException;
+    public Parser getParser();
+    public IncomingFramesCapture getIncomingFrames();
+    public void flush() throws IOException;
+    public void write(int b) throws IOException;
+    public void startEcho();
+    public void stopEcho();
+    
+    /**
+     * Add an extra header for the upgrade response (from the server). No extra work is done to ensure the key and value are sane for http.
+     * @param rawkey the raw key
+     * @param rawvalue the raw value
+     */
+    public void addResponseHeader(String rawkey, String rawvalue);
+}
\ No newline at end of file
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java
index f5ac1c0..39bbf96 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
 
 import java.util.Queue;
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/LeakTrackingBufferPoolRule.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/LeakTrackingBufferPoolRule.java
index ab6eeba..132d5e6 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/LeakTrackingBufferPoolRule.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/LeakTrackingBufferPoolRule.java
@@ -18,15 +18,15 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
 import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
 public class LeakTrackingBufferPoolRule extends LeakTrackingByteBufferPool implements TestRule
 {
     private final String id;
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java
index f307193..bdf4b9f 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingFramesCapture.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+
 import java.util.LinkedList;
 
 import org.eclipse.jetty.util.BufferUtil;
@@ -29,9 +32,6 @@
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-
 public class OutgoingFramesCapture implements OutgoingFrames
 {
     private LinkedList<WebSocketFrame> frames = new LinkedList<>();
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingNetworkBytesCapture.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingNetworkBytesCapture.java
index cbbea46..d995753 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingNetworkBytesCapture.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/OutgoingNetworkBytesCapture.java
@@ -18,6 +18,9 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
+
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
@@ -32,9 +35,6 @@
 import org.eclipse.jetty.websocket.common.Generator;
 import org.junit.Assert;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.lessThan;
-
 /**
  * Capture outgoing network bytes.
  */
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/RawFrameBuilder.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/RawFrameBuilder.java
index 5fa30c3..b1b76c9 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/RawFrameBuilder.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/RawFrameBuilder.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.common.test;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitGenerator.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitGenerator.java
index 57bdb1c..c2fcae8 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitGenerator.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitGenerator.java
@@ -83,6 +83,8 @@
 
     /**
      * Generate a single giant buffer of all provided frames Not appropriate for production code, but useful for testing.
+     * @param frames the list of frames to generate from
+     * @return the bytebuffer representing all of the generated frames
      */
     public static ByteBuffer generate(List<WebSocketFrame> frames)
     {
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitParser.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitParser.java
index 818b5a8..53751a5 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitParser.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/UnitParser.java
@@ -50,6 +50,7 @@
      * Parse a buffer, but do so in a quiet fashion, squelching stacktraces if encountered.
      * <p>
      * Use if you know the parse will cause an exception and just don't wnat to make the test console all noisy.
+     * @param buf the buffer to parse
      */
     public void parseQuietly(ByteBuffer buf)
     {
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java
new file mode 100644
index 0000000..06e0347
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Sha1Sum.java
@@ -0,0 +1,110 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.common.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.toolchain.test.IO;
+import org.junit.Assert;
+
+/**
+ * Calculate the sha1sum for various content 
+ */
+public class Sha1Sum
+{
+    private static class NoOpOutputStream extends OutputStream
+    {
+        @Override
+        public void write(byte[] b) throws IOException
+        {
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException
+        {
+        }
+
+        @Override
+        public void flush() throws IOException
+        {
+        }
+
+        @Override
+        public void close() throws IOException
+        {
+        }
+
+        @Override
+        public void write(int b) throws IOException
+        {
+        }
+    }
+
+    public static String calculate(File file) throws NoSuchAlgorithmException, IOException
+    {
+        return calculate(file.toPath());
+    }
+
+    public static String calculate(Path path) throws NoSuchAlgorithmException, IOException
+    {
+        MessageDigest digest = MessageDigest.getInstance("SHA1");
+        try (InputStream in = Files.newInputStream(path,StandardOpenOption.READ);
+                NoOpOutputStream noop = new NoOpOutputStream();
+                DigestOutputStream digester = new DigestOutputStream(noop,digest))
+        {
+            IO.copy(in,digester);
+            return Hex.asHex(digest.digest());
+        }
+    }
+
+    public static String calculate(byte[] buf) throws NoSuchAlgorithmException
+    {
+        MessageDigest digest = MessageDigest.getInstance("SHA1");
+        digest.update(buf);
+        return Hex.asHex(digest.digest());
+    }
+    
+    public static String calculate(byte[] buf, int offset, int len) throws NoSuchAlgorithmException
+    {
+        MessageDigest digest = MessageDigest.getInstance("SHA1");
+        digest.update(buf,offset,len);
+        return Hex.asHex(digest.digest());
+    }
+    
+    public static String loadSha1(File sha1File) throws IOException
+    {
+        String contents = IO.readToString(sha1File);
+        Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
+        Matcher mat = pat.matcher(contents);
+        Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
+        return mat.group();
+    }
+
+}
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java
new file mode 100644
index 0000000..f7e59ec
--- /dev/null
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/util/Utf8PartialBuilderTest.java
@@ -0,0 +1,86 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.websocket.common.util;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.junit.Test;
+
+/**
+ * Test partial UTF8 String sequence building.
+ */
+public class Utf8PartialBuilderTest
+{
+    private ByteBuffer toByteBuffer(String hexStr)
+    {
+        return ByteBuffer.wrap(Hex.asByteArray(hexStr));
+    }
+    
+    @Test
+    public void testPartial_UnsplitCodepoint()
+    {
+        Utf8PartialBuilder utf8 = new Utf8PartialBuilder();
+
+        String seq1 = "Hello-\uC2B5@\uC39F\uC3A4";
+        String seq2 = "\uC3BC\uC3A0\uC3A1-UTF-8!!";
+
+        String ret1 = utf8.toPartialString(BufferUtil.toBuffer(seq1,StandardCharsets.UTF_8));
+        String ret2 = utf8.toPartialString(BufferUtil.toBuffer(seq2,StandardCharsets.UTF_8));
+
+        assertThat("Seq1",ret1,is(seq1));
+        assertThat("Seq2",ret2,is(seq2));
+    }
+    
+    @Test
+    public void testPartial_SplitCodepoint()
+    {
+        Utf8PartialBuilder utf8 = new Utf8PartialBuilder();
+
+        String seq1 = "48656C6C6F2DEC8AB540EC8E9FEC8E";
+        String seq2 = "A4EC8EBCEC8EA0EC8EA12D5554462D382121";
+        
+        String ret1 = utf8.toPartialString(toByteBuffer(seq1));
+        String ret2 = utf8.toPartialString(toByteBuffer(seq2));
+
+        assertThat("Seq1",ret1,is("Hello-\uC2B5@\uC39F"));
+        assertThat("Seq2",ret2,is("\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!"));
+    }
+    
+    @Test
+    public void testPartial_SplitCodepoint_WithNoBuf()
+    {
+        Utf8PartialBuilder utf8 = new Utf8PartialBuilder();
+
+        String seq1 = "48656C6C6F2DEC8AB540EC8E9FEC8E";
+        String seq2 = "A4EC8EBCEC8EA0EC8EA12D5554462D382121";
+        
+        String ret1 = utf8.toPartialString(toByteBuffer(seq1));
+        String ret2 = utf8.toPartialString(BufferUtil.EMPTY_BUFFER);
+        String ret3 = utf8.toPartialString(toByteBuffer(seq2));
+
+        assertThat("Seq1",ret1,is("Hello-\uC2B5@\uC39F"));
+        assertThat("Seq2",ret2,is(""));
+        assertThat("Seq3",ret3,is("\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!"));
+    }
+}
diff --git a/jetty-websocket/websocket-server/pom.xml b/jetty-websocket/websocket-server/pom.xml
index 9335a07..3d6be16 100644
--- a/jetty-websocket/websocket-server/pom.xml
+++ b/jetty-websocket/websocket-server/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.websocket</groupId>
         <artifactId>websocket-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -20,30 +20,20 @@
           <groupId>org.apache.felix</groupId>
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
-          <executions>
-            <execution>
-              <id>generate-manifest</id>
-              <goals>
-                <goal>manifest</goal>
-              </goals>
-              <configuration>
-                <instructions>
-                  <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
-                  <Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.websocket.servlet.WebSocketServletFactory</Provide-Capability>
-                  <_nouses>true</_nouses>
-                </instructions>
-              </configuration>
-            </execution>
-          </executions>
+          <configuration>
+            <instructions>
+              <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
+              <Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.websocket.servlet.WebSocketServletFactory</Provide-Capability>
+            </instructions>
+          </configuration>
         </plugin>
             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-jar-plugin</artifactId>
               <executions>
                 <execution>
-                  <id>artifact-jars</id>
+                  <id>test-jar</id>
                   <goals>
-                    <goal>jar</goal>
                     <goal>test-jar</goal>
                   </goals>
                 </execution>
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
index 06eb241..3a1798b 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.websocket.server;
 
 import java.io.IOException;
+
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/MappedWebSocketCreator.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/MappedWebSocketCreator.java
index 4e23d24..bbc8100 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/MappedWebSocketCreator.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/MappedWebSocketCreator.java
@@ -18,8 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
+import org.eclipse.jetty.http.pathmap.PathMappings;
+import org.eclipse.jetty.http.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
 
 /**
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java
index 148d63f..290f9b0 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketHandshake.java
@@ -28,8 +28,9 @@
     /**
      * Formulate a WebSocket upgrade handshake response.
      * 
-     * @param request
-     * @param response
+     * @param request the request
+     * @param response the response
+     * @throws IOException if unable to handshake
      */
     public void doHandshakeResponse(ServletUpgradeRequest request, ServletUpgradeResponse response) throws IOException;
 }
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
index a98ac53..c8f9ef4 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerConnection.java
@@ -19,14 +19,11 @@
 package org.eclipse.jetty.websocket.server;
 
 import java.net.InetSocketAddress;
-import java.nio.ByteBuffer;
 import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.thread.Scheduler;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
@@ -34,8 +31,6 @@
 
 public class WebSocketServerConnection extends AbstractWebSocketConnection implements Connection.UpgradeTo
 {
-    private final AtomicBoolean opened = new AtomicBoolean(false);
-
     public WebSocketServerConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
     {
         super(endp,executor,scheduler,policy,bufferPool);
@@ -56,23 +51,6 @@
     {
         return getEndPoint().getRemoteAddress();
     }
-
-    @Override
-    public void onUpgradeTo(ByteBuffer prefilled)
-    {
-        prefill(prefilled);
-    }
-
-    @Override
-    public void onOpen()
-    {
-        boolean beenOpened = opened.getAndSet(true);
-        if (!beenOpened)
-        {
-            getSession().open();
-        }
-        super.onOpen();
-    }
     
     @Override
     public void setNextIncomingFrames(IncomingFrames incoming)
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
index 6eb97ff..ec2dd3a 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
@@ -22,15 +22,16 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.Executor;
 
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -38,15 +39,19 @@
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.MappedByteBufferPool;
+import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
 import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
 import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
-import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.api.WebSocketException;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
@@ -60,6 +65,8 @@
 import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
 import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
 import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
+import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
+import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
@@ -68,7 +75,7 @@
 /**
  * Factory to create WebSocket connections
  */
-public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketServletFactory, SessionListener
+public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketContainerScope, WebSocketServletFactory, SessionListener
 {
     private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
 
@@ -83,10 +90,11 @@
     private final EventDriverFactory eventDriverFactory;
     private final ByteBufferPool bufferPool;
     private final WebSocketExtensionFactory extensionFactory;
+    private Executor executor;
     private List<SessionFactory> sessionFactories;
-    private Set<WebSocketSession> openSessions = new CopyOnWriteArraySet<>();
     private WebSocketCreator creator;
     private List<Class<?>> registeredSocketClasses;
+    private DecoratedObjectFactory objectFactory;
 
     public WebSocketServerFactory()
     {
@@ -117,12 +125,7 @@
         this.defaultPolicy = policy;
         this.eventDriverFactory = new EventDriverFactory(defaultPolicy);
         this.bufferPool = bufferPool;
-        this.extensionFactory = new WebSocketExtensionFactory(defaultPolicy, this.bufferPool);
-        
-        // Bug #431459 - unregistering compression extensions till they are more stable
-        this.extensionFactory.unregister("deflate-frame");
-        this.extensionFactory.unregister("permessage-deflate");
-        this.extensionFactory.unregister("x-webkit-deflate-frame");
+        this.extensionFactory = new WebSocketExtensionFactory(this);
         
         this.sessionFactories = new ArrayList<>();
         this.sessionFactories.add(new WebSocketSessionFactory(this));
@@ -160,6 +163,8 @@
         try
         {
             Thread.currentThread().setContextClassLoader(contextClassloader);
+            
+            // Create Servlet Specific Upgrade Request/Response objects
             ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request);
             ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response);
 
@@ -178,6 +183,9 @@
                 return false;
             }
 
+            // Allow Decorators to do their thing
+            websocketPojo = getObjectFactory().decorate(websocketPojo);
+            
             // Get the original HTTPConnection
             HttpConnection connection = (HttpConnection)request.getAttribute("org.eclipse.jetty.server.HttpConnection");
             
@@ -194,7 +202,7 @@
             Thread.currentThread().setContextClassLoader(old);
         }
     }
-
+    
     public void addSessionFactory(SessionFactory sessionFactory)
     {
         if (sessionFactories.contains(sessionFactory))
@@ -217,27 +225,6 @@
         }
     }
 
-    protected void shutdownAllConnections()
-    {
-        for (WebSocketSession session : openSessions)
-        {
-            if (session.getConnection() != null)
-            {
-                try
-                {
-                    session.getConnection().close(
-                            StatusCode.SHUTDOWN,
-                            "Shutdown");
-                }
-                catch (Throwable t)
-                {
-                    LOG.debug("During Shutdown All Connections",t);
-                }
-            }
-        }
-        openSessions.clear();
-    }
-
     @Override
     public WebSocketServletFactory createFactory(WebSocketPolicy policy)
     {
@@ -288,19 +275,29 @@
         Class<?> firstClass = registeredSocketClasses.get(0);
         try
         {
-            return firstClass.newInstance();
+            return objectFactory.createInstance(firstClass);
         }
         catch (InstantiationException | IllegalAccessException e)
         {
             throw new WebSocketException("Unable to create instance of " + firstClass, e);
         }
     }
+    
+    @Override
+    protected void doStart() throws Exception
+    {
+        if(this.objectFactory == null)
+        {
+            this.objectFactory = new DecoratedObjectFactory();
+        }
+        
+        super.doStart();
+    }
 
     @Override
-    protected void doStop() throws Exception
+    public ByteBufferPool getBufferPool()
     {
-        shutdownAllConnections();
-        super.doStop();
+        return this.bufferPool;
     }
 
     @Override
@@ -308,6 +305,17 @@
     {
         return this.creator;
     }
+    
+    @Override
+    public Executor getExecutor()
+    {
+        return this.executor;
+    }
+
+    public DecoratedObjectFactory getObjectFactory()
+    {
+        return objectFactory;
+    }
 
     public EventDriverFactory getEventDriverFactory()
     {
@@ -319,10 +327,10 @@
     {
         return extensionFactory;
     }
-
-    public Set<WebSocketSession> getOpenSessions()
+    
+    public Collection<WebSocketSession> getOpenSessions()
     {
-        return Collections.unmodifiableSet(this.openSessions);
+        return getBeans(WebSocketSession.class);
     }
 
     @Override
@@ -330,11 +338,60 @@
     {
         return defaultPolicy;
     }
-
+    
     @Override
-    public void init() throws Exception
+    public SslContextFactory getSslContextFactory()
     {
-        start(); // start lifecycle
+        /* Not relevant for a Server, as this is defined in the
+         * Connector configuration 
+         */
+        return null;
+    }
+
+    public void init(ServletContextHandler context) throws ServletException
+    {
+        this.objectFactory = (DecoratedObjectFactory)context.getServletContext().getAttribute(DecoratedObjectFactory.ATTR);
+        if (this.objectFactory == null)
+        {
+            this.objectFactory = new DecoratedObjectFactory();
+        }
+        
+        this.executor = context.getServer().getThreadPool();
+    }
+    
+    @Override
+    public void init(ServletContext context) throws ServletException
+    {
+        // Setup ObjectFactory
+        this.objectFactory = (DecoratedObjectFactory)context.getAttribute(DecoratedObjectFactory.ATTR);
+        if (this.objectFactory == null)
+        {
+            this.objectFactory = new DecoratedObjectFactory();
+        }
+        
+        // Validate Environment
+        ContextHandler handler = ContextHandler.getContextHandler(context);
+
+        if (handler == null)
+        {
+            throw new ServletException("Not running on Jetty, WebSocket support unavailable");
+        }
+
+        this.executor = handler.getServer().getThreadPool();
+        
+        try
+        {
+            // start lifecycle
+            start();
+        }
+        catch (ServletException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new ServletException(e);
+        }
     }
 
     @Override
@@ -396,13 +453,13 @@
     @Override
     public void onSessionClosed(WebSocketSession session)
     {
-        this.openSessions.remove(session);
+        removeBean(session);
     }
 
     @Override
     public void onSessionOpened(WebSocketSession session)
     {
-        this.openSessions.add(session);
+        addManaged(session);
     }
 
     protected String[] parseProtocols(String protocol)
@@ -513,11 +570,12 @@
 
         // Get original HTTP connection
         EndPoint endp = http.getEndPoint();
-        Executor executor = http.getConnector().getExecutor();
-        ByteBufferPool bufferPool = http.getConnector().getByteBufferPool();
-        
+        Connector connector = http.getConnector();
+        Executor executor = connector.getExecutor();
+        ByteBufferPool bufferPool = connector.getByteBufferPool();
+
         // Setup websocket connection
-        WebSocketServerConnection wsConnection = new WebSocketServerConnection(endp, executor, scheduler, driver.getPolicy(), bufferPool);
+        AbstractWebSocketConnection wsConnection = new WebSocketServerConnection(endp, executor, scheduler, driver.getPolicy(), bufferPool);
 
         extensionStack.setPolicy(driver.getPolicy());
         extensionStack.configure(wsConnection.getParser());
@@ -536,7 +594,7 @@
         // set true negotiated extension list back to response 
         response.setExtensions(extensionStack.getNegotiatedExtensions());
         session.setUpgradeResponse(response);
-        wsConnection.setSession(session);
+        wsConnection.addListener(session);
 
         // Setup Incoming Routing
         wsConnection.setNextIncomingFrames(extensionStack);
@@ -547,21 +605,12 @@
         extensionStack.setNextOutgoing(wsConnection);
 
         // Start Components
-        try
+        session.addManaged(extensionStack);
+        this.addManaged(session);
+        
+        if (session.isFailed())
         {
-            session.start();
-        }
-        catch (Exception e)
-        {
-            throw new IOException("Unable to start Session", e);
-        }
-        try
-        {
-            extensionStack.start();
-        }
-        catch (Exception e)
-        {
-            throw new IOException("Unable to start Extension Stack", e);
+            throw new IOException("Session failed to start");
         }
 
         // Tell jetty about the new upgraded connection
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
index 453062c..a189155 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeFilter.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 import java.util.EnumSet;
+
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -32,6 +33,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.pathmap.MappedResource;
+import org.eclipse.jetty.http.pathmap.PathMappings;
+import org.eclipse.jetty.http.pathmap.PathSpec;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.servlet.FilterHolder;
@@ -43,9 +47,6 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
 
 /**
@@ -256,6 +257,8 @@
 
         try
         {
+            ServletContext ctx = config.getServletContext();
+            factory.init(ctx);
             WebSocketPolicy policy = factory.getPolicy();
 
             String max = config.getInitParameter("maxIdleTime");
@@ -289,8 +292,8 @@
                 key = WebSocketUpgradeFilter.class.getName();
             }
             
-            setToAttribute(config.getServletContext(), key);
-
+            setToAttribute(ctx, key);
+            
             factory.start();
         }
         catch (Exception x)
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeHandlerWrapper.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeHandlerWrapper.java
index 88e9b0e..ce6fff9 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeHandlerWrapper.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketUpgradeHandlerWrapper.java
@@ -24,13 +24,13 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.eclipse.jetty.http.pathmap.MappedResource;
+import org.eclipse.jetty.http.pathmap.PathMappings;
+import org.eclipse.jetty.http.pathmap.PathSpec;
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
-import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
 
 public class WebSocketUpgradeHandlerWrapper extends HandlerWrapper implements MappedWebSocketCreator
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathMappings.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathMappings.java
deleted file mode 100644
index 2f53073..0000000
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathMappings.java
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.jetty.util.annotation.ManagedAttribute;
-import org.eclipse.jetty.util.annotation.ManagedObject;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.component.Dumpable;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
-
-/**
- * Path Mappings of PathSpec to Resource.
- * <p>
- * Sorted into search order upon entry into the Set
- * 
- * @param <E>
- */
-@ManagedObject("Path Mappings")
-public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
-{
-    @ManagedObject("Mapped Resource")
-    public static class MappedResource<E> implements Comparable<MappedResource<E>>
-    {
-        private final PathSpec pathSpec;
-        private final E resource;
-
-        public MappedResource(PathSpec pathSpec, E resource)
-        {
-            this.pathSpec = pathSpec;
-            this.resource = resource;
-        }
-
-        /**
-         * Comparison is based solely on the pathSpec
-         */
-        @Override
-        public int compareTo(MappedResource<E> other)
-        {
-            return this.pathSpec.compareTo(other.pathSpec);
-        }
-
-        @Override
-        public boolean equals(Object obj)
-        {
-            if (this == obj)
-            {
-                return true;
-            }
-            if (obj == null)
-            {
-                return false;
-            }
-            if (getClass() != obj.getClass())
-            {
-                return false;
-            }
-            MappedResource<?> other = (MappedResource<?>)obj;
-            if (pathSpec == null)
-            {
-                if (other.pathSpec != null)
-                {
-                    return false;
-                }
-            }
-            else if (!pathSpec.equals(other.pathSpec))
-            {
-                return false;
-            }
-            return true;
-        }
-
-        @ManagedAttribute(value = "path spec", readonly = true)
-        public PathSpec getPathSpec()
-        {
-            return pathSpec;
-        }
-
-        @ManagedAttribute(value = "resource", readonly = true)
-        public E getResource()
-        {
-            return resource;
-        }
-
-        @Override
-        public int hashCode()
-        {
-            final int prime = 31;
-            int result = 1;
-            result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
-            return result;
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource);
-        }
-    }
-
-    private static final Logger LOG = Log.getLogger(PathMappings.class);
-    private List<MappedResource<E>> mappings = new ArrayList<MappedResource<E>>();
-    private MappedResource<E> defaultResource = null;
-
-    @Override
-    public String dump()
-    {
-        return ContainerLifeCycle.dump(this);
-    }
-
-    @Override
-    public void dump(Appendable out, String indent) throws IOException
-    {
-        ContainerLifeCycle.dump(out,indent,mappings);
-    }
-
-    @ManagedAttribute(value = "mappings", readonly = true)
-    public List<MappedResource<E>> getMappings()
-    {
-        return mappings;
-    }
-    
-    public void reset()
-    {
-        mappings.clear();
-    }
-
-    public MappedResource<E> getMatch(String path)
-    {
-        int len = mappings.size();
-        for (int i = 0; i < len; i++)
-        {
-            MappedResource<E> mr = mappings.get(i);
-            if (mr.getPathSpec().matches(path))
-            {
-                return mr;
-            }
-        }
-        return defaultResource;
-    }
-
-    @Override
-    public Iterator<MappedResource<E>> iterator()
-    {
-        return mappings.iterator();
-    }
-
-    public void put(PathSpec pathSpec, E resource)
-    {
-        MappedResource<E> entry = new MappedResource<>(pathSpec,resource);
-        if (pathSpec.group == PathSpecGroup.DEFAULT)
-        {
-            defaultResource = entry;
-        }
-        // TODO: warning on replacement of existing mapping?
-        mappings.add(entry);
-        if (LOG.isDebugEnabled())
-            LOG.debug("Added {} to {}",entry,this);
-        Collections.sort(mappings);
-    }
-
-    @Override
-    public String toString()
-    {
-        return String.format("%s[size=%d]",this.getClass().getSimpleName(),mappings.size());
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpec.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpec.java
deleted file mode 100644
index fb4b148..0000000
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpec.java
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-/**
- * The base PathSpec, what all other path specs are based on
- */
-public abstract class PathSpec implements Comparable<PathSpec>
-{
-    protected String pathSpec;
-    protected PathSpecGroup group;
-    protected int pathDepth;
-    protected int specLength;
-
-    @Override
-    public int compareTo(PathSpec other)
-    {
-        // Grouping (increasing)
-        int diff = this.group.ordinal() - other.group.ordinal();
-        if (diff != 0)
-        {
-            return diff;
-        }
-
-        // Spec Length (decreasing)
-        diff = other.specLength - this.specLength;
-        if (diff != 0)
-        {
-            return diff;
-        }
-
-        // Path Spec Name (alphabetical)
-        return this.pathSpec.compareTo(other.pathSpec);
-    }
-
-    @Override
-    public boolean equals(Object obj)
-    {
-        if (this == obj)
-        {
-            return true;
-        }
-        if (obj == null)
-        {
-            return false;
-        }
-        if (getClass() != obj.getClass())
-        {
-            return false;
-        }
-        PathSpec other = (PathSpec)obj;
-        if (pathSpec == null)
-        {
-            if (other.pathSpec != null)
-            {
-                return false;
-            }
-        }
-        else if (!pathSpec.equals(other.pathSpec))
-        {
-            return false;
-        }
-        return true;
-    }
-
-    public PathSpecGroup getGroup()
-    {
-        return group;
-    }
-
-    /**
-     * Get the number of path elements that this path spec declares.
-     * <p>
-     * This is used to determine longest match logic.
-     * 
-     * @return the depth of the path segments that this spec declares
-     */
-    public int getPathDepth()
-    {
-        return pathDepth;
-    }
-
-    /**
-     * Return the portion of the path that is after the path spec.
-     * 
-     * @param path
-     *            the path to match against
-     * @return the path info portion of the string
-     */
-    public abstract String getPathInfo(String path);
-
-    /**
-     * Return the portion of the path that matches a path spec.
-     * 
-     * @param path
-     *            the path to match against
-     * @return the match, or null if no match at all
-     */
-    public abstract String getPathMatch(String path);
-
-    /**
-     * The as-provided path spec.
-     * 
-     * @return the as-provided path spec
-     */
-    public String getPathSpec()
-    {
-        return pathSpec;
-    }
-
-    /**
-     * Get the relative path.
-     * 
-     * @param base
-     *            the base the path is relative to
-     * @param path
-     *            the additional path
-     * @return the base plus path with pathSpec portion removed
-     */
-    public abstract String getRelativePath(String base, String path);
-
-    @Override
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
-        return result;
-    }
-
-    /**
-     * Test to see if the provided path matches this path spec
-     * 
-     * @param path
-     *            the path to test
-     * @return true if the path matches this path spec, false otherwise
-     */
-    public abstract boolean matches(String path);
-
-    @Override
-    public String toString()
-    {
-        StringBuilder str = new StringBuilder();
-        str.append(this.getClass().getSimpleName()).append("[\"");
-        str.append(pathSpec);
-        str.append("\",pathDepth=").append(pathDepth);
-        str.append(",group=").append(group);
-        str.append("]");
-        return str.toString();
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpecGroup.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpecGroup.java
deleted file mode 100644
index ff181d2..0000000
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/PathSpecGroup.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-/**
- * Types of path spec groups.
- * <p>
- * This is used to facilitate proper pathspec search order.
- * <p>
- * Search Order: {@link PathSpecGroup#ordinal()} [increasin], {@link PathSpec#specLength} [decreasing], {@link PathSpec#pathSpec} [natural sort order]
- */
-public enum PathSpecGroup
-{
-    // NOTE: Order of enums determines order of Groups.
-
-    /**
-     * For exactly defined path specs, no glob.
-     */
-    EXACT,
-    /**
-     * For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle.
-     * 
-     * <pre>
-     *   "^/downloads/[^/]*.zip$"  - regex spec
-     *   "/a/{var}/c"              - websocket spec
-     * </pre>
-     * 
-     * Note: there is no known servlet spec variant of this kind of path spec
-     */
-    MIDDLE_GLOB,
-    /**
-     * For path specs that have a hardcoded prefix and a trailing wildcard glob.
-     * <p>
-     * 
-     * <pre>
-     *   "/downloads/*"          - servlet spec
-     *   "/api/*"                - servlet spec
-     *   "^/rest/.*$"            - regex spec
-     *   "/bookings/{guest-id}"  - websocket spec
-     *   "/rewards/{vip-level}"  - websocket spec
-     * </pre>
-     */
-    PREFIX_GLOB,
-    /**
-     * For path specs that have a wildcard glob with a hardcoded suffix
-     * 
-     * <pre>
-     *   "*.do"        - servlet spec
-     *   "*.css"       - servlet spec
-     *   "^.*\.zip$"   - regex spec
-     * </pre>
-     * 
-     * Note: there is no known websocket spec variant of this kind of path spec
-     */
-    SUFFIX_GLOB,
-    /**
-     * The default spec for accessing the Root and/or Default behavior.
-     * 
-     * <pre>
-     *   "/"           - servlet spec   (Default Servlet)
-     *   "/"           - websocket spec (Root Context)
-     *   "^/$"         - regex spec     (Root Context)
-     * </pre>
-     */
-    DEFAULT;
-}
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpec.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpec.java
index ac2b516..3111a6c 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpec.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpec.java
@@ -18,159 +18,14 @@
 
 package org.eclipse.jetty.websocket.server.pathmap;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class RegexPathSpec extends PathSpec
+/**
+ * @deprecated moved to jetty-http {@link org.eclipse.jetty.http.pathmap.RegexPathSpec} (this facade will be removed in Jetty 9.4) 
+ */
+@Deprecated
+public class RegexPathSpec extends org.eclipse.jetty.http.pathmap.RegexPathSpec
 {
-    protected Pattern pattern;
-
-    protected RegexPathSpec()
-    {
-        super();
-    }
-
     public RegexPathSpec(String regex)
     {
-        super.pathSpec = regex;
-        boolean inGrouping = false;
-        this.pathDepth = 0;
-        this.specLength = pathSpec.length();
-        // build up a simple signature we can use to identify the grouping
-        StringBuilder signature = new StringBuilder();
-        for (char c : pathSpec.toCharArray())
-        {
-            switch (c)
-            {
-                case '[':
-                    inGrouping = true;
-                    break;
-                case ']':
-                    inGrouping = false;
-                    signature.append('g'); // glob
-                    break;
-                case '*':
-                    signature.append('g'); // glob
-                    break;
-                case '/':
-                    if (!inGrouping)
-                    {
-                        this.pathDepth++;
-                    }
-                    break;
-                default:
-                    if (!inGrouping)
-                    {
-                        if (Character.isLetterOrDigit(c))
-                        {
-                            signature.append('l'); // literal (exact)
-                        }
-                    }
-                    break;
-            }
-        }
-        this.pattern = Pattern.compile(pathSpec);
-
-        // Figure out the grouping based on the signature
-        String sig = signature.toString();
-
-        if (Pattern.matches("^l*$",sig))
-        {
-            this.group = PathSpecGroup.EXACT;
-        }
-        else if (Pattern.matches("^l*g+",sig))
-        {
-            this.group = PathSpecGroup.PREFIX_GLOB;
-        }
-        else if (Pattern.matches("^g+l+$",sig))
-        {
-            this.group = PathSpecGroup.SUFFIX_GLOB;
-        }
-        else
-        {
-            this.group = PathSpecGroup.MIDDLE_GLOB;
-        }
-    }
-
-    public Matcher getMatcher(String path)
-    {
-        return this.pattern.matcher(path);
-    }
-
-    @Override
-    public String getPathInfo(String path)
-    {
-        // Path Info only valid for PREFIX_GLOB types
-        if (group == PathSpecGroup.PREFIX_GLOB)
-        {
-            Matcher matcher = getMatcher(path);
-            if (matcher.matches())
-            {
-                if (matcher.groupCount() >= 1)
-                {
-                    String pathInfo = matcher.group(1);
-                    if ("".equals(pathInfo))
-                    {
-                        return "/";
-                    }
-                    else
-                    {
-                        return pathInfo;
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public String getPathMatch(String path)
-    {
-        Matcher matcher = getMatcher(path);
-        if (matcher.matches())
-        {
-            if (matcher.groupCount() >= 1)
-            {
-                int idx = matcher.start(1);
-                if (idx > 0)
-                {
-                    if (path.charAt(idx - 1) == '/')
-                    {
-                        idx--;
-                    }
-                    return path.substring(0,idx);
-                }
-            }
-            return path;
-        }
-        return null;
-    }
-
-    public Pattern getPattern()
-    {
-        return this.pattern;
-    }
-
-    @Override
-    public String getRelativePath(String base, String path)
-    {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean matches(final String path)
-    {
-        int idx = path.indexOf('?');
-        if (idx >= 0)
-        {
-            // match only non-query part
-            return getMatcher(path.substring(0,idx)).matches();
-        }
-        else
-        {
-            // match entire path
-            return getMatcher(path).matches();
-        }
+        super(regex);
     }
 }
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpec.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpec.java
index 4a13bca..da52817 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpec.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpec.java
@@ -18,274 +18,14 @@
 
 package org.eclipse.jetty.websocket.server.pathmap;
 
-import org.eclipse.jetty.util.URIUtil;
-
-public class ServletPathSpec extends PathSpec
+/**
+ * @deprecated moved to jetty-http {@link org.eclipse.jetty.http.pathmap.ServletPathSpec} (this facade will be removed in Jetty 9.4) 
+ */
+@Deprecated
+public class ServletPathSpec extends org.eclipse.jetty.http.pathmap.ServletPathSpec
 {
-    public static final String PATH_SPEC_SEPARATORS = ":,";
-
-    /**
-     * Get multi-path spec splits.
-     * 
-     * @param servletPathSpec
-     *            the path spec that might contain multiple declared path specs
-     * @return the individual path specs found.
-     */
-    public static ServletPathSpec[] getMultiPathSpecs(String servletPathSpec)
-    {
-        String pathSpecs[] = servletPathSpec.split(PATH_SPEC_SEPARATORS);
-        int len = pathSpecs.length;
-        ServletPathSpec sps[] = new ServletPathSpec[len];
-        for (int i = 0; i < len; i++)
-        {
-            sps[i] = new ServletPathSpec(pathSpecs[i]);
-        }
-        return sps;
-    }
-
     public ServletPathSpec(String servletPathSpec)
     {
-        super();
-        assertValidServletPathSpec(servletPathSpec);
-
-        // The Path Spec for Default Servlet
-        if ((servletPathSpec == null) || (servletPathSpec.length() == 0) || "/".equals(servletPathSpec))
-        {
-            super.pathSpec = "/";
-            super.pathDepth = -1; // force this to be last in sort order
-            this.specLength = 1;
-            this.group = PathSpecGroup.DEFAULT;
-            return;
-        }
-
-        this.specLength = servletPathSpec.length();
-        super.pathDepth = 0;
-        char lastChar = servletPathSpec.charAt(specLength - 1);
-        // prefix based
-        if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
-        {
-            this.group = PathSpecGroup.PREFIX_GLOB;
-        }
-        // suffix based
-        else if (servletPathSpec.charAt(0) == '*')
-        {
-            this.group = PathSpecGroup.SUFFIX_GLOB;
-        }
-        else
-        {
-            this.group = PathSpecGroup.EXACT;
-        }
-
-        for (int i = 0; i < specLength; i++)
-        {
-            int cp = servletPathSpec.codePointAt(i);
-            if (cp < 128)
-            {
-                char c = (char)cp;
-                switch (c)
-                {
-                    case '/':
-                        super.pathDepth++;
-                        break;
-                }
-            }
-        }
-
-        super.pathSpec = servletPathSpec;
-    }
-
-    private void assertValidServletPathSpec(String servletPathSpec)
-    {
-        if ((servletPathSpec == null) || servletPathSpec.equals(""))
-        {
-            return; // empty path spec
-        }
-
-        // Ensure we don't have path spec separators here in our single path spec.
-        for (char c : PATH_SPEC_SEPARATORS.toCharArray())
-        {
-            if (servletPathSpec.indexOf(c) >= 0)
-            {
-                throw new IllegalArgumentException("Servlet Spec 12.2 violation: encountered Path Spec Separator [" + PATH_SPEC_SEPARATORS
-                        + "] within specified path spec. did you forget to split this path spec up?");
-            }
-        }
-
-        int len = servletPathSpec.length();
-        // path spec must either start with '/' or '*.'
-        if (servletPathSpec.charAt(0) == '/')
-        {
-            // Prefix Based
-            if (len == 1)
-            {
-                return; // simple '/' path spec
-            }
-            int idx = servletPathSpec.indexOf('*');
-            if (idx < 0)
-            {
-                return; // no hit on glob '*'
-            }
-            // only allowed to have '*' at the end of the path spec
-            if (idx != (len - 1))
-            {
-                throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches");
-            }
-        }
-        else if (servletPathSpec.startsWith("*."))
-        {
-            // Suffix Based
-            int idx = servletPathSpec.indexOf('/');
-            // cannot have path separator
-            if (idx >= 0)
-            {
-                throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators");
-            }
-
-            idx = servletPathSpec.indexOf('*',2);
-            // only allowed to have 1 glob '*', at the start of the path spec
-            if (idx >= 1)
-            {
-                throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*'");
-            }
-        }
-        else
-        {
-            throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\"");
-        }
-    }
-
-    @Override
-    public String getPathInfo(String path)
-    {
-        // Path Info only valid for PREFIX_GLOB types
-        if (group == PathSpecGroup.PREFIX_GLOB)
-        {
-            if (path.length() == (specLength - 2))
-            {
-                return null;
-            }
-            return path.substring(specLength - 2);
-        }
-
-        return null;
-    }
-
-    @Override
-    public String getPathMatch(String path)
-    {
-        switch (group)
-        {
-            case EXACT:
-                if (pathSpec.equals(path))
-                {
-                    return path;
-                }
-                else
-                {
-                    return null;
-                }
-            case PREFIX_GLOB:
-                if (isWildcardMatch(path))
-                {
-                    return path.substring(0,specLength - 2);
-                }
-                else
-                {
-                    return null;
-                }
-            case SUFFIX_GLOB:
-                if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1))
-                {
-                    return path;
-                }
-                else
-                {
-                    return null;
-                }
-            case DEFAULT:
-                return path;
-            default:
-                return null;
-        }
-    }
-
-    @Override
-    public String getRelativePath(String base, String path)
-    {
-        String info = getPathInfo(path);
-        if (info == null)
-        {
-            info = path;
-        }
-
-        if (info.startsWith("./"))
-        {
-            info = info.substring(2);
-        }
-        if (base.endsWith(URIUtil.SLASH))
-        {
-            if (info.startsWith(URIUtil.SLASH))
-            {
-                path = base + info.substring(1);
-            }
-            else
-            {
-                path = base + info;
-            }
-        }
-        else if (info.startsWith(URIUtil.SLASH))
-        {
-            path = base + info;
-        }
-        else
-        {
-            path = base + URIUtil.SLASH + info;
-        }
-        return path;
-    }
-
-    private boolean isExactMatch(String path)
-    {
-        if (group == PathSpecGroup.EXACT)
-        {
-            if (pathSpec.equals(path))
-            {
-                return true;
-            }
-            return (path.charAt(path.length() - 1) == '/') && (path.equals(pathSpec + '/'));
-        }
-        return false;
-    }
-
-    private boolean isWildcardMatch(String path)
-    {
-        // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar"
-        int cpl = specLength - 2;
-        if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl)))
-        {
-            if ((path.length() == cpl) || ('/' == path.charAt(cpl)))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean matches(String path)
-    {
-        switch (group)
-        {
-            case EXACT:
-                return isExactMatch(path);
-            case PREFIX_GLOB:
-                return isWildcardMatch(path);
-            case SUFFIX_GLOB:
-                return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1);
-            case DEFAULT:
-                return true;
-            default:
-                return false;
-        }
+        super(servletPathSpec);
     }
 }
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/AnnotatedMaxMessageSizeTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/AnnotatedMaxMessageSizeTest.java
index 4411bbb..89f8ba4 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/AnnotatedMaxMessageSizeTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/AnnotatedMaxMessageSizeTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.io.IOException;
 import java.net.URI;
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ChromeTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ChromeTest.java
index b8b29f9..fda6b1d 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ChromeTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ChromeTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsLegacyTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsLegacyTest.java
new file mode 100644
index 0000000..fad933e
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsLegacyTest.java
@@ -0,0 +1,181 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.server;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.Decorator;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
+import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class DecoratorsLegacyTest
+{
+    private static class DecoratorsSocket extends WebSocketAdapter
+    {
+        private final DecoratedObjectFactory objFactory;
+        
+        public DecoratorsSocket(DecoratedObjectFactory objFactory)
+        {
+            this.objFactory = objFactory;
+        }
+        
+        @Override
+        public void onWebSocketText(String message)
+        {
+            StringWriter str = new StringWriter();
+            PrintWriter out = new PrintWriter(str);
+            
+            if (objFactory != null)
+            {
+                out.printf("Object is a DecoratedObjectFactory%n");
+                List<Decorator> decorators = objFactory.getDecorators();
+                out.printf("Decorators.size = [%d]%n",decorators.size());
+                for (Decorator decorator : decorators)
+                {
+                    out.printf(" decorator[] = %s%n",decorator.getClass().getName());
+                }
+            }
+            else
+            {
+                out.printf("DecoratedObjectFactory is NULL%n");
+            }
+
+            getRemote().sendStringByFuture(str.toString());
+        }
+    }
+
+    private static class DecoratorsCreator implements WebSocketCreator
+    {
+        @Override
+        public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
+        {
+            ServletContext servletContext = req.getHttpServletRequest().getServletContext();
+            DecoratedObjectFactory objFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
+            return new DecoratorsSocket(objFactory);
+        }
+    }
+
+    public static class DecoratorsRequestServlet extends WebSocketServlet
+    {
+        private static final long serialVersionUID = 1L;
+        private final WebSocketCreator creator;
+
+        public DecoratorsRequestServlet(WebSocketCreator creator)
+        {
+            this.creator = creator;
+        }
+
+        @Override
+        public void configure(WebSocketServletFactory factory)
+        {
+            factory.setCreator(this.creator);
+        }
+    }
+    
+    @SuppressWarnings("deprecation")
+    private static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
+    {
+        @Override
+        public <T> T decorate(T o)
+        {
+            return o;
+        }
+
+        @Override
+        public void destroy(Object o)
+        {
+        }
+    }
+
+    private static SimpleServletServer server;
+    private static DecoratorsCreator decoratorsCreator;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        decoratorsCreator = new DecoratorsCreator();
+        server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
+        {
+            @SuppressWarnings("deprecation")
+            @Override
+            protected void configureServletContextHandler(ServletContextHandler context)
+            {
+                context.getObjectFactory().clear();
+                // Add decorator in the legacy way
+                context.addDecorator(new DummyLegacyDecorator());
+            }
+        };
+        server.start();
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        server.stop();
+    }
+
+    @Test
+    public void testAccessRequestCookies() throws Exception
+    {
+        BlockheadClient client = new BlockheadClient(server.getServerUri());
+        client.setTimeout(1,TimeUnit.SECONDS);
+
+        try
+        {
+            client.connect();
+            client.sendStandardRequest();
+            client.expectUpgradeResponse();
+            
+            client.write(new TextFrame().setPayload("info"));
+
+            EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
+            WebSocketFrame resp = frames.poll();
+            String textMsg = resp.getPayloadAsUTF8();
+            
+            assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
+            assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
+            assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyLegacyDecorator.class.getName()));
+        }
+        finally
+        {
+            client.close();
+        }
+    }
+}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsTest.java
new file mode 100644
index 0000000..b17e7ee
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/DecoratorsTest.java
@@ -0,0 +1,179 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.server;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.junit.Assert.assertThat;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.DecoratedObjectFactory;
+import org.eclipse.jetty.util.Decorator;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
+import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class DecoratorsTest
+{
+    private static class DecoratorsSocket extends WebSocketAdapter
+    {
+        private final DecoratedObjectFactory objFactory;
+        
+        public DecoratorsSocket(DecoratedObjectFactory objFactory)
+        {
+            this.objFactory = objFactory;
+        }
+        
+        @Override
+        public void onWebSocketText(String message)
+        {
+            StringWriter str = new StringWriter();
+            PrintWriter out = new PrintWriter(str);
+            
+            if (objFactory != null)
+            {
+                out.printf("Object is a DecoratedObjectFactory%n");
+                List<Decorator> decorators = objFactory.getDecorators();
+                out.printf("Decorators.size = [%d]%n",decorators.size());
+                for (Decorator decorator : decorators)
+                {
+                    out.printf(" decorator[] = %s%n",decorator.getClass().getName());
+                }
+            }
+            else
+            {
+                out.printf("DecoratedObjectFactory is NULL%n");
+            }
+
+            getRemote().sendStringByFuture(str.toString());
+        }
+    }
+
+    private static class DecoratorsCreator implements WebSocketCreator
+    {
+        @Override
+        public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
+        {
+            ServletContext servletContext = req.getHttpServletRequest().getServletContext();
+            DecoratedObjectFactory objFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
+            return new DecoratorsSocket(objFactory);
+        }
+    }
+
+    public static class DecoratorsRequestServlet extends WebSocketServlet
+    {
+        private static final long serialVersionUID = 1L;
+        private final WebSocketCreator creator;
+
+        public DecoratorsRequestServlet(WebSocketCreator creator)
+        {
+            this.creator = creator;
+        }
+
+        @Override
+        public void configure(WebSocketServletFactory factory)
+        {
+            factory.setCreator(this.creator);
+        }
+    }
+    
+    private static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator
+    {
+        @Override
+        public <T> T decorate(T o)
+        {
+            return o;
+        }
+
+        @Override
+        public void destroy(Object o)
+        {
+        }
+    }
+
+    private static SimpleServletServer server;
+    private static DecoratorsCreator decoratorsCreator;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        decoratorsCreator = new DecoratorsCreator();
+        server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
+        {
+            @Override
+            protected void configureServletContextHandler(ServletContextHandler context)
+            {
+                // Add decorator in the new util way
+                context.getObjectFactory().clear();
+                context.getObjectFactory().addDecorator(new DummyUtilDecorator());
+            }
+        };
+        server.start();
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        server.stop();
+    }
+
+    @Test
+    public void testAccessRequestCookies() throws Exception
+    {
+        BlockheadClient client = new BlockheadClient(server.getServerUri());
+        client.setTimeout(1,TimeUnit.SECONDS);
+
+        try
+        {
+            client.connect();
+            client.sendStandardRequest();
+            client.expectUpgradeResponse();
+            
+            client.write(new TextFrame().setPayload("info"));
+
+            EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
+            WebSocketFrame resp = frames.poll();
+            String textMsg = resp.getPayloadAsUTF8();
+            
+            assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
+            assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
+            assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyUtilDecorator.class.getName()));
+        }
+        finally
+        {
+            client.close();
+        }
+    }
+}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FirefoxTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FirefoxTest.java
index 99b4ccd..ee36f5b 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FirefoxTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FirefoxTest.java
@@ -26,6 +26,7 @@
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
 import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -52,7 +53,7 @@
     @Test
     public void testConnectionKeepAlive() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             // Odd Connection Header value seen in Firefox
             client.setConnectionValue("keep-alive, Upgrade");
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java
index 9039e5f..4d8f962 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/FragmentExtensionTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java
index 66bc879..7c8741e 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java
index 44dcd07..8e401a7 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import java.util.concurrent.TimeUnit;
 
@@ -67,6 +68,7 @@
 
     /**
      * Test IdleTimeout on server.
+     * @throws Exception on test failure
      */
     @Test
     public void testIdleTimeout() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java
new file mode 100644
index 0000000..bf9f70f
--- /dev/null
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ManyConnectionsCleanupTest.java
@@ -0,0 +1,369 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.websocket.server;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jetty.toolchain.test.EventQueue;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.log.StacklessLogging;
+import org.eclipse.jetty.util.log.StdErrLog;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.common.CloseInfo;
+import org.eclipse.jetty.websocket.common.OpCode;
+import org.eclipse.jetty.websocket.common.WebSocketFrame;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
+import org.eclipse.jetty.websocket.common.frames.TextFrame;
+import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
+import org.eclipse.jetty.websocket.server.helper.RFCSocket;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
+import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Tests various close scenarios that should result in Open Session cleanup
+ */
+@Ignore
+public class ManyConnectionsCleanupTest
+{
+    static class AbstractCloseSocket extends WebSocketAdapter
+    {
+        public CountDownLatch closeLatch = new CountDownLatch(1);
+        public String closeReason = null;
+        public int closeStatusCode = -1;
+        public List<Throwable> errors = new ArrayList<>();
+
+        @Override
+        public void onWebSocketClose(int statusCode, String reason)
+        {
+            LOG.debug("onWebSocketClose({}, {})",statusCode,reason);
+            this.closeStatusCode = statusCode;
+            this.closeReason = reason;
+            closeLatch.countDown();
+        }
+
+        @Override
+        public void onWebSocketError(Throwable cause)
+        {
+            errors.add(cause);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class CloseServlet extends WebSocketServlet implements WebSocketCreator
+    {
+        private WebSocketServerFactory serverFactory;
+        private AtomicInteger calls = new AtomicInteger(0);
+
+        @Override
+        public void configure(WebSocketServletFactory factory)
+        {
+            factory.setCreator(this);
+            if (factory instanceof WebSocketServerFactory)
+            {
+                this.serverFactory = (WebSocketServerFactory)factory;
+            }
+        }
+
+        @Override
+        public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
+        {
+            if (req.hasSubProtocol("fastclose"))
+            {
+                closeSocket = new FastCloseSocket(calls);
+                return closeSocket;
+            }
+
+            if (req.hasSubProtocol("fastfail"))
+            {
+                closeSocket = new FastFailSocket(calls);
+                return closeSocket;
+            }
+
+            if (req.hasSubProtocol("container"))
+            {
+                closeSocket = new ContainerSocket(serverFactory,calls);
+                return closeSocket;
+            }
+            return new RFCSocket();
+        }
+    }
+
+    /**
+     * On Message, return container information
+     */
+    public static class ContainerSocket extends AbstractCloseSocket
+    {
+        private static final Logger LOG = Log.getLogger(ManyConnectionsCleanupTest.ContainerSocket.class);
+        private final WebSocketServerFactory container;
+        private final AtomicInteger calls;
+        private Session session;
+
+        public ContainerSocket(WebSocketServerFactory container, AtomicInteger calls)
+        {
+            this.container = container;
+            this.calls = calls;
+        }
+
+        @Override
+        public void onWebSocketText(String message)
+        {
+            LOG.debug("onWebSocketText({})",message);
+            calls.incrementAndGet();
+            if (message.equalsIgnoreCase("openSessions"))
+            {
+                Collection<WebSocketSession> sessions = container.getOpenSessions();
+
+                StringBuilder ret = new StringBuilder();
+                ret.append("openSessions.size=").append(sessions.size()).append('\n');
+                int idx = 0;
+                for (WebSocketSession sess : sessions)
+                {
+                    ret.append('[').append(idx++).append("] ").append(sess.toString()).append('\n');
+                }
+                session.getRemote().sendStringByFuture(ret.toString());
+                session.close(StatusCode.NORMAL,"ContainerSocket");
+            } else if(message.equalsIgnoreCase("calls"))
+            {
+                session.getRemote().sendStringByFuture(String.format("calls=%,d",calls.get()));
+            }
+        }
+
+        @Override
+        public void onWebSocketConnect(Session sess)
+        {
+            LOG.debug("onWebSocketConnect({})",sess);
+            this.session = sess;
+        }
+    }
+
+    /**
+     * On Connect, close socket
+     */
+    public static class FastCloseSocket extends AbstractCloseSocket
+    {
+        private static final Logger LOG = Log.getLogger(ManyConnectionsCleanupTest.FastCloseSocket.class);
+        private final AtomicInteger calls;
+
+        public FastCloseSocket(AtomicInteger calls)
+        {
+            this.calls = calls;
+        }
+
+        @Override
+        public void onWebSocketConnect(Session sess)
+        {
+            LOG.debug("onWebSocketConnect({})",sess);
+            calls.incrementAndGet();
+            sess.close(StatusCode.NORMAL,"FastCloseServer");
+        }
+    }
+
+    /**
+     * On Connect, throw unhandled exception
+     */
+    public static class FastFailSocket extends AbstractCloseSocket
+    {
+        private static final Logger LOG = Log.getLogger(ManyConnectionsCleanupTest.FastFailSocket.class);
+        private final AtomicInteger calls;
+
+        public FastFailSocket(AtomicInteger calls)
+        {
+            this.calls = calls;
+        }
+
+        @Override
+        public void onWebSocketConnect(Session sess)
+        {
+            LOG.debug("onWebSocketConnect({})",sess);
+            calls.incrementAndGet();
+            // Test failure due to unhandled exception
+            // this should trigger a fast-fail closure during open/connect
+            throw new RuntimeException("Intentional FastFail");
+        }
+    }
+
+    private static final Logger LOG = Log.getLogger(ManyConnectionsCleanupTest.class);
+
+    private static SimpleServletServer server;
+    private static AbstractCloseSocket closeSocket;
+
+    @BeforeClass
+    public static void startServer() throws Exception
+    {
+        server = new SimpleServletServer(new CloseServlet());
+        server.start();
+    }
+
+    @AfterClass
+    public static void stopServer()
+    {
+        server.stop();
+    }
+
+    /**
+     * Test session open session cleanup (bug #474936)
+     * 
+     * @throws Exception
+     *             on test failure
+     */
+    @Test
+    public void testOpenSessionCleanup() throws Exception
+    {
+        int iterationCount = 100;
+        
+        StdErrLog.getLogger(FastFailSocket.class).setLevel(StdErrLog.LEVEL_OFF);
+        
+        StdErrLog sessLog = StdErrLog.getLogger(WebSocketSession.class);
+        int oldLevel = sessLog.getLevel();
+        sessLog.setLevel(StdErrLog.LEVEL_OFF);
+        
+        for (int requests = 0; requests < iterationCount; requests++)
+        {
+            fastFail();
+            fastClose();
+            dropConnection();
+        }
+        
+        sessLog.setLevel(oldLevel);
+
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
+        {
+            client.setProtocols("container");
+            client.setTimeout(1,TimeUnit.SECONDS);
+            client.connect();
+            client.sendStandardRequest();
+            client.expectUpgradeResponse();
+            
+            client.write(new TextFrame().setPayload("calls"));
+            client.write(new TextFrame().setPayload("openSessions"));
+
+            EventQueue<WebSocketFrame> frames = client.readFrames(3,6,TimeUnit.SECONDS);
+            WebSocketFrame frame;
+            String resp;
+            
+            frame = frames.poll();
+            assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.TEXT));
+            resp = frame.getPayloadAsUTF8();
+            assertThat("Should only have 1 open session",resp,containsString("calls=" + ((iterationCount * 2) + 1)));
+
+            frame = frames.poll();
+            assertThat("frames[1].opcode",frame.getOpCode(),is(OpCode.TEXT));
+            resp = frame.getPayloadAsUTF8();
+            assertThat("Should only have 1 open session",resp,containsString("openSessions.size=1\n"));
+
+            frame = frames.poll();
+            assertThat("frames[2].opcode",frame.getOpCode(),is(OpCode.CLOSE));
+            CloseInfo close = new CloseInfo(frame);
+            assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
+            client.write(close.asFrame()); // respond with close
+
+            // ensure server socket got close event
+            assertThat("Open Sessions Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
+            assertThat("Open Sessions.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL));
+            assertThat("Open Sessions.errors",closeSocket.errors.size(),is(0));
+        }
+    }
+
+    private void fastClose() throws Exception
+    {
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
+        {
+            client.setProtocols("fastclose");
+            client.setTimeout(1,TimeUnit.SECONDS);
+            try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
+            {
+                client.connect();
+                client.sendStandardRequest();
+                client.expectUpgradeResponse();
+                
+                client.readFrames(1,1,TimeUnit.SECONDS);
+
+                CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
+                assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
+
+                // Notify server of close handshake
+                client.write(close.asFrame()); // respond with close
+
+                // ensure server socket got close event
+                assertThat("Fast Close Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
+                assertThat("Fast Close.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL));
+            }
+        }
+    }
+
+    private void fastFail() throws Exception
+    {
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
+        {
+            client.setProtocols("fastfail");
+            client.setTimeout(1,TimeUnit.SECONDS);
+            try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
+            {
+                client.connect();
+                client.sendStandardRequest();
+                client.expectUpgradeResponse();
+                
+                // client.readFrames(1,2,TimeUnit.SECONDS);
+
+                CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
+                client.write(close.asFrame()); // respond with close
+
+                // ensure server socket got close event
+                assertThat("Fast Fail Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
+                assertThat("Fast Fail.statusCode",closeSocket.closeStatusCode,is(StatusCode.SERVER_ERROR));
+                assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1));
+            }
+        }
+    }
+    
+    private void dropConnection() throws Exception
+    {
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
+        {
+            client.setProtocols("container");
+            client.setTimeout(1,TimeUnit.SECONDS);
+            try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
+            {
+                client.connect();
+                client.sendStandardRequest();
+                client.expectUpgradeResponse();
+                client.disconnect();
+            }
+        }
+    }
+}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/PerMessageDeflateExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/PerMessageDeflateExtensionTest.java
index edb0ea6..5ada833 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/PerMessageDeflateExtensionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/PerMessageDeflateExtensionTest.java
@@ -18,41 +18,99 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
-import org.eclipse.jetty.toolchain.test.EventQueue;
-import org.eclipse.jetty.websocket.common.WebSocketFrame;
-import org.eclipse.jetty.websocket.common.frames.TextFrame;
-import org.eclipse.jetty.websocket.common.test.BlockheadClient;
-import org.eclipse.jetty.websocket.common.test.HttpResponse;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
+import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.eclipse.jetty.websocket.common.test.LeakTrackingBufferPoolRule;
+import org.eclipse.jetty.websocket.common.util.Sha1Sum;
+import org.eclipse.jetty.websocket.server.helper.CaptureSocket;
 import org.eclipse.jetty.websocket.server.helper.EchoServlet;
-import org.junit.AfterClass;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Assume;
-import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class PerMessageDeflateExtensionTest
 {
-    private static SimpleServletServer server;
-
-    @BeforeClass
-    public static void startServer() throws Exception
+    private static enum TestCaseMessageSize
     {
-        server = new SimpleServletServer(new EchoServlet());
-        server.start();
+        TINY(10),
+        SMALL(1024),
+        MEDIUM(10*1024),
+        LARGE(100*1024),
+        HUGE(1024*1024);
+        
+        private int size;
+
+        private TestCaseMessageSize(int size)
+        {
+            this.size = size;
+        }
+    }
+    
+    @Parameters(name = "{0} ({3}) (Input Buffer Size: {4} bytes)")
+    public static List<Object[]> modes()
+    {
+        List<Object[]> modes = new ArrayList<>();
+        
+        for(TestCaseMessageSize size: TestCaseMessageSize.values())
+        {
+            modes.add(new Object[] { "Normal HTTP/WS", false, "ws", size, -1 });
+            modes.add(new Object[] { "Encrypted HTTPS/WSS", true, "wss", size, -1 });
+            int altInputBufSize = 15*1024;
+            modes.add(new Object[] { "Normal HTTP/WS", false, "ws", size, altInputBufSize });
+            modes.add(new Object[] { "Encrypted HTTPS/WSS", true, "wss", size, altInputBufSize });
+        }
+        
+        return modes;
     }
 
-    @AfterClass
-    public static void stopServer()
+    @Rule
+    public LeakTrackingBufferPoolRule bufferPool = new LeakTrackingBufferPoolRule("Test");
+
+    private SimpleServletServer server;
+    private String scheme;
+    private int msgSize;
+    private int inputBufferSize;
+
+    public PerMessageDeflateExtensionTest(String mode, boolean sslMode, String scheme, TestCaseMessageSize msgSize, int bufferSize) throws Exception
+    {
+        server = new SimpleServletServer(new EchoServlet());
+        server.enableSsl(sslMode);
+        server.start();
+
+        this.scheme = scheme;
+        this.msgSize = msgSize.size;
+        this.inputBufferSize = bufferSize;
+    }
+
+    @After
+    public void stopServer()
     {
         server.stop();
     }
 
     /**
      * Default configuration for permessage-deflate
+     * @throws Exception on test failure
      */
     @Test
     public void testPerMessageDeflateDefault() throws Exception
@@ -60,42 +118,84 @@
         Assume.assumeTrue("Server has permessage-deflate registered",
                 server.getWebSocketServletFactory().getExtensionFactory().isAvailable("permessage-deflate"));
 
-        BlockheadClient client = new BlockheadClient(server.getServerUri());
-        client.clearExtensions();
-        client.addExtensions("permessage-deflate");
-        client.setProtocols("echo");
+        Assert.assertThat("server scheme",server.getServerUri().getScheme(),is(scheme));
 
+        int binBufferSize = (int) (msgSize * 1.5);
+        
+        WebSocketPolicy serverPolicy = server.getWebSocketServletFactory().getPolicy();
+        
+        // Ensure binBufferSize is sane (not smaller then other buffers)
+        binBufferSize = Math.max(binBufferSize,serverPolicy.getMaxBinaryMessageSize());
+        binBufferSize = Math.max(binBufferSize,serverPolicy.getMaxBinaryMessageBufferSize());
+        binBufferSize = Math.max(binBufferSize,this.inputBufferSize);
+
+        serverPolicy.setMaxBinaryMessageSize(binBufferSize);
+        serverPolicy.setMaxBinaryMessageBufferSize(binBufferSize);
+
+        WebSocketClient client = new WebSocketClient(server.getSslContextFactory(),null,bufferPool);
+        WebSocketPolicy clientPolicy = client.getPolicy();
+        clientPolicy.setMaxBinaryMessageSize(binBufferSize);
+        clientPolicy.setMaxBinaryMessageBufferSize(binBufferSize);
+        if (inputBufferSize > 0)
+        {
+            clientPolicy.setInputBufferSize(inputBufferSize);
+        }
+        
         try
         {
+            client.start();
             // Make sure the read times out if there are problems with the implementation
-            client.setTimeout(1,TimeUnit.SECONDS);
-            client.connect();
-            client.sendStandardRequest();
-            HttpResponse resp = client.expectUpgradeResponse();
+            client.setMaxIdleTimeout(TimeUnit.SECONDS.toMillis(1));
 
-            Assert.assertThat("Response",resp.getExtensionsHeader(),containsString("permessage-deflate"));
+            CaptureSocket clientSocket = new CaptureSocket();
+            ClientUpgradeRequest request = new ClientUpgradeRequest();
+            request.addExtensions("permessage-deflate");
+            request.setSubProtocols("echo");
 
-            String msg = "Hello";
+            Future<Session> fut = client.connect(clientSocket,server.getServerUri(),request);
 
+            // Wait for connect
+            Session session = fut.get(3,TimeUnit.SECONDS);
+
+            assertThat("Response.extensions",getNegotiatedExtensionList(session),containsString("permessage-deflate"));
+
+            // Create message
+            byte msg[] = new byte[msgSize];
+            Random rand = new Random();
+            rand.setSeed(8080);
+            rand.nextBytes(msg);
+            
+            // Calculate sha1
+            String sha1 = Sha1Sum.calculate(msg);
+            
             // Client sends first message
-            client.write(new TextFrame().setPayload(msg));
+            session.getRemote().sendBytes(ByteBuffer.wrap(msg));
 
-            EventQueue<WebSocketFrame> frames = client.readFrames(1,1000,TimeUnit.MILLISECONDS);
-            WebSocketFrame frame = frames.poll();
-            Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(msg.toString()));
-
-            // Client sends second message
-            client.clearCaptured();
-            msg = "There";
-            client.write(new TextFrame().setPayload(msg));
-
-            frames = client.readFrames(1,1,TimeUnit.SECONDS);
-            frame = frames.poll();
-            Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is(msg.toString()));
+            clientSocket.messages.awaitEventCount(1,1,TimeUnit.SECONDS);
+            String echoMsg = clientSocket.messages.poll();
+            Assert.assertThat("Echo'd Message",echoMsg,is("binary[sha1="+sha1+"]"));
         }
         finally
         {
-            client.close();
+            client.stop();
         }
     }
+
+    private String getNegotiatedExtensionList(Session session)
+    {
+        StringBuilder actual = new StringBuilder();
+        actual.append('[');
+
+        boolean delim = false;
+        for (ExtensionConfig ext : session.getUpgradeResponse().getExtensions())
+        {
+            if (delim)
+                actual.append(", ");
+            actual.append(ext.getName());
+            delim = true;
+        }
+        actual.append(']');
+
+        return actual.toString();
+    }
 }
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java
index 7496ea5..0360c5a 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/RequestHeadersTest.java
@@ -18,7 +18,9 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.net.HttpCookie;
 import java.util.List;
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java
index b507ab5..2c76fd2 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java
@@ -22,6 +22,7 @@
 
 import javax.servlet.http.HttpServlet;
 
+import org.eclipse.jetty.http.HttpVersion;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.SecureRequestCustomizer;
@@ -100,7 +101,7 @@
             https_config.addCustomizer(new SecureRequestCustomizer());
 
             // SSL Connector
-            connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,"http/1.1"),new HttpConnectionFactory(https_config));
+            connector = new ServerConnector(server,new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),new HttpConnectionFactory(https_config));
             connector.setPort(0);
         }
         else
@@ -113,6 +114,7 @@
 
         ServletContextHandler context = new ServletContextHandler();
         context.setContextPath("/");
+        configureServletContextHandler(context);
         server.setHandler(context);
 
         // Serve capture servlet
@@ -137,6 +139,10 @@
         }
     }
 
+    protected void configureServletContextHandler(ServletContextHandler context)
+    {
+    }
+
     public void stop()
     {
         try
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
index 7b12db8..45ea3c0 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/TooFastClientTest.java
@@ -18,12 +18,15 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 
+import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
+import org.eclipse.jetty.io.MappedByteBufferPool;
 import org.eclipse.jetty.toolchain.test.EventQueue;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
@@ -36,8 +39,8 @@
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.Ignore;
 
 /**
  * Test simulating a client that talks too quickly.
@@ -45,7 +48,6 @@
  * There is a class of client that will send the GET+Upgrade Request along with a few websocket frames in a single
  * network packet. This test attempts to perform this behavior as close as possible.
  */
-@Ignore
 public class TooFastClientTest
 {
     private static SimpleServletServer server;
@@ -64,7 +66,8 @@
     }
 
     @Test
-    public void testUpgradeWithWebkitDeflateExtension() throws Exception
+    @Ignore("RELEASE")
+    public void testUpgradeWithSmallFrames() throws Exception
     {
         BlockheadClient client = new BlockheadClient(server.getServerUri());
         try
@@ -83,11 +86,20 @@
             // Add text frames
             Generator generator = new Generator(WebSocketPolicy.newClientPolicy(),
                     new LeakTrackingBufferPoolRule("Generator"));
+            
             String msg1 = "Echo 1";
             String msg2 = "This is also an echooooo!";
             
-            generator.generateWholeFrame(new TextFrame().setPayload(msg1),initialPacket);
-            generator.generateWholeFrame(new TextFrame().setPayload(msg2),initialPacket);
+            TextFrame frame1 = new TextFrame().setPayload(msg1);
+            TextFrame frame2 = new TextFrame().setPayload(msg2);
+            
+            // Need to set frame mask (as these are client frames)
+            byte mask[] = new byte[] { 0x11, 0x22, 0x33, 0x44 };
+            frame1.setMask(mask);
+            frame2.setMask(mask);
+
+            generator.generateWholeFrame(frame1,initialPacket);
+            generator.generateWholeFrame(frame2,initialPacket);
 
             // Write packet to network
             BufferUtil.flipToFlush(initialPacket,0);
@@ -108,4 +120,64 @@
             client.close();
         }
     }
+    
+    /**
+     * Test where were a client sends a HTTP Upgrade to websocket AND enough websocket frame(s)
+     * to completely overfill the {@link org.eclipse.jetty.io.AbstractConnection#getInputBufferSize()}
+     * to test a situation where the WebSocket connection opens with prefill that exceeds 
+     * the normal input buffer sizes.
+     * @throws Exception on test failure
+     */
+    @Test
+    @Ignore("RELEASE")
+    public void testUpgradeWithLargeFrame() throws Exception
+    {
+        BlockheadClient client = new BlockheadClient(server.getServerUri());
+        try
+        {
+            client.connect();
+
+            // Create ByteBuffer representing the initial opening network packet from the client
+            ByteBuffer initialPacket = ByteBuffer.allocate(100 * 1024);
+            BufferUtil.clearToFill(initialPacket);
+
+            // Add upgrade request to packet
+            StringBuilder upgradeRequest = client.generateUpgradeRequest();
+            ByteBuffer upgradeBuffer = BufferUtil.toBuffer(upgradeRequest.toString(),StandardCharsets.UTF_8);
+            initialPacket.put(upgradeBuffer);
+
+            // Add text frames
+            Generator generator = new Generator(WebSocketPolicy.newClientPolicy(),
+                    new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()));
+
+            byte bigMsgBytes[] = new byte[64*1024];
+            Arrays.fill(bigMsgBytes,(byte)'x');
+            String bigMsg = new String(bigMsgBytes, StandardCharsets.UTF_8);
+            
+            // Need to set frame mask (as these are client frames)
+            byte mask[] = new byte[] { 0x11, 0x22, 0x33, 0x44 };
+            TextFrame frame = new TextFrame().setPayload(bigMsg);
+            frame.setMask(mask);
+            generator.generateWholeFrame(frame,initialPacket);
+
+            // Write packet to network
+            BufferUtil.flipToFlush(initialPacket,0);
+            client.writeRaw(initialPacket);
+
+            // Expect upgrade
+            client.expectUpgradeResponse();
+
+            // Read frames (hopefully text frames)
+            EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
+
+            WebSocketFrame tf = frames.poll();
+            Assert.assertThat("Text Frame/msg1",tf.getPayloadAsUTF8(),is(bigMsg));
+        }
+        finally
+        {
+            client.close();
+        }
+    }
+    
+    
 }
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
index 77b2bcd..1fea2cd 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java
@@ -22,8 +22,8 @@
 import static org.junit.Assert.*;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -41,6 +41,7 @@
 import org.eclipse.jetty.websocket.common.events.AbstractEventDriver;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
 import org.eclipse.jetty.websocket.server.helper.RFCSocket;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
@@ -138,7 +139,7 @@
             LOG.debug("onWebSocketText({})",message);
             if (message.equalsIgnoreCase("openSessions"))
             {
-                Set<WebSocketSession> sessions = container.getOpenSessions();
+                Collection<WebSocketSession> sessions = container.getOpenSessions();
 
                 StringBuilder ret = new StringBuilder();
                 ret.append("openSessions.size=").append(sessions.size()).append('\n');
@@ -219,7 +220,7 @@
     @Test
     public void testFastClose() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("fastclose");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -252,7 +253,7 @@
     @Test
     public void testFastFail() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("fastfail");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -291,7 +292,7 @@
         fastClose();
         dropConnection();
 
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("container");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -325,7 +326,7 @@
 
     private void fastClose() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("fastclose");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -352,7 +353,7 @@
 
     private void fastFail() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("fastfail");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -377,7 +378,7 @@
     
     private void dropConnection() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("container");
             client.setTimeout(1,TimeUnit.SECONDS);
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
index d26c32b..d0eeb4b 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketInvalidVersionTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
 
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
 import org.eclipse.jetty.websocket.common.test.HttpResponse;
@@ -47,6 +48,7 @@
 
     /**
      * Test the requirement of responding with an http 400 when using a Sec-WebSocket-Version that is unsupported.
+     * @throws Exception on test failure
      */
     @Test
     public void testRequestVersion29() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java
index 6067529..9484de8 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketOverSSLTest.java
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.websocket.server;
 
+import static org.hamcrest.Matchers.is;
+
 import java.net.URI;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -37,8 +39,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.hamcrest.Matchers.is;
-
 public class WebSocketOverSSLTest
 {
     @Rule
@@ -65,6 +65,7 @@
 
     /**
      * Test the requirement of issuing socket and receiving echo response
+     * @throws Exception on test failure
      */
     @Test
     public void testEcho() throws Exception
@@ -106,6 +107,7 @@
 
     /**
      * Test that server session reports as secure
+     * @throws Exception on test failure
      */
     @Test
     public void testServerSessionIsSecure() throws Exception
@@ -147,6 +149,7 @@
 
     /**
      * Test that server session.upgradeRequest.requestURI reports correctly
+     * @throws Exception on test failure
      */
     @Test
     public void testServerSessionRequestURI() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerSessionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerSessionTest.java
index 7d54f13..fba9d41 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerSessionTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServerSessionTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.net.URI;
 import java.util.concurrent.TimeUnit;
@@ -28,6 +28,7 @@
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
 import org.eclipse.jetty.websocket.common.frames.TextFrame;
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
 import org.eclipse.jetty.websocket.server.helper.SessionServlet;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -36,7 +37,7 @@
 import org.junit.runner.RunWith;
 
 /**
- * Testing various aspects of the server side support for WebSocket {@link Session}
+ * Testing various aspects of the server side support for WebSocket {@link org.eclipse.jetty.websocket.api.Session}
  */
 @RunWith(AdvancedRunner.class)
 public class WebSocketServerSessionTest
@@ -60,7 +61,7 @@
     public void testDisconnect() throws Exception
     {
         URI uri = server.getServerUri().resolve("/test/disconnect");
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.connect();
             client.sendStandardRequest();
@@ -76,7 +77,7 @@
     public void testUpgradeRequestResponse() throws Exception
     {
         URI uri = server.getServerUri().resolve("/test?snack=cashews&amount=handful&brand=off");
-        try (BlockheadClient client = new BlockheadClient(uri))
+        try (IBlockheadClient client = new BlockheadClient(uri))
         {
             client.connect();
             client.sendStandardRequest();
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java
index 1612d89..50c6db2 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketServletRFCTest.java
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.websocket.server;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -45,6 +45,7 @@
 import org.eclipse.jetty.websocket.common.test.UnitGenerator;
 import org.eclipse.jetty.websocket.common.util.Hex;
 import org.eclipse.jetty.websocket.server.helper.RFCServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -81,6 +82,7 @@
 
     /**
      * Test that aggregation of binary frames into a single message occurs
+     * @throws Exception on test failure
      */
     @Test
     public void testBinaryAggregate() throws Exception
@@ -166,6 +168,7 @@
 
     /**
      * Test the requirement of issuing socket and receiving echo response
+     * @throws Exception on test failure
      */
     @Test
     public void testEcho() throws Exception
@@ -195,6 +198,7 @@
     /**
      * Test the requirement of responding with server terminated close code 1011 when there is an unhandled (internal server error) being produced by the
      * WebSocket POJO.
+     * @throws Exception on test failure
      */
     @Test
     public void testInternalError() throws Exception
@@ -233,6 +237,7 @@
      * Test http://tools.ietf.org/html/rfc6455#section-4.1 where server side upgrade handling is supposed to be case insensitive.
      * <p>
      * This test will simulate a client requesting upgrade with all lowercase headers.
+     * @throws Exception on test failure
      */
     @Test
     public void testLowercaseUpgrade() throws Exception
@@ -312,6 +317,7 @@
      * Test http://tools.ietf.org/html/rfc6455#section-4.1 where server side upgrade handling is supposed to be case insensitive.
      * <p>
      * This test will simulate a client requesting upgrade with all uppercase headers.
+     * @throws Exception on test failure
      */
     @Test
     public void testUppercaseUpgrade() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AbstractABCase.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AbstractABCase.java
index 01724a1..a757139 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AbstractABCase.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/AbstractABCase.java
@@ -24,6 +24,7 @@
 
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.StacklessLogging;
 import org.eclipse.jetty.util.log.StdErrLog;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
 import org.eclipse.jetty.websocket.common.Generator;
@@ -175,6 +176,8 @@
     public TestName testname = new TestName();
 
     /**
+     * @param clazz the class to enable
+     * @param enabled true to enable the stack traces (or not)
      * @deprecated use {@link StacklessLogging} in a try-with-resources block instead
      */
     @Deprecated
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase1.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase1.java
index cb927d2..857d241 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase1.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase1.java
@@ -36,6 +36,7 @@
 {
     /**
      * Echo 0 byte TEXT message
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_1() throws Exception
@@ -59,6 +60,7 @@
 
     /**
      * Echo 125 byte TEXT message (uses small 7-bit payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_2() throws Exception
@@ -86,6 +88,7 @@
 
     /**
      * Echo 126 byte TEXT message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_3() throws Exception
@@ -113,6 +116,7 @@
 
     /**
      * Echo 127 byte TEXT message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_4() throws Exception
@@ -140,6 +144,7 @@
 
     /**
      * Echo 128 byte TEXT message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_5() throws Exception
@@ -167,6 +172,7 @@
 
     /**
      * Echo 65535 byte TEXT message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_6() throws Exception
@@ -194,6 +200,7 @@
 
     /**
      * Echo 65536 byte TEXT message (uses large 8 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_7() throws Exception
@@ -225,6 +232,7 @@
      * Only send 1 TEXT frame from client, but in small segments (flushed after each).
      * <p>
      * This is done to test the parsing together of the frame on the server side.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_1_8() throws Exception
@@ -254,6 +262,7 @@
 
     /**
      * Echo 0 byte BINARY message
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_1() throws Exception
@@ -277,6 +286,7 @@
 
     /**
      * Echo 125 byte BINARY message (uses small 7-bit payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_2() throws Exception
@@ -304,6 +314,7 @@
 
     /**
      * Echo 126 byte BINARY message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_3() throws Exception
@@ -331,6 +342,7 @@
 
     /**
      * Echo 127 byte BINARY message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_4() throws Exception
@@ -358,6 +370,7 @@
 
     /**
      * Echo 128 byte BINARY message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_5() throws Exception
@@ -385,6 +398,7 @@
 
     /**
      * Echo 65535 byte BINARY message (uses medium 2 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_6() throws Exception
@@ -412,6 +426,7 @@
 
     /**
      * Echo 65536 byte BINARY message (uses large 8 byte payload length)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_7() throws Exception
@@ -443,6 +458,7 @@
      * Only send 1 BINARY frame from client, but in small segments (flushed after each).
      * <p>
      * This is done to test the parsing together of the frame on the server side.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase1_2_8() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase2.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase2.java
index 31d0cda..a50b2ea 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase2.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase2.java
@@ -42,6 +42,7 @@
 {
     /**
      * Ping without payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_1() throws Exception
@@ -61,6 +62,7 @@
 
     /**
      * 10 pings
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_10() throws Exception
@@ -95,6 +97,7 @@
 
     /**
      * 10 pings, sent slowly
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_11() throws Exception
@@ -130,6 +133,7 @@
 
     /**
      * Ping with small text payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_2() throws Exception
@@ -155,6 +159,7 @@
 
     /**
      * Ping with small binary (non-utf8) payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_3() throws Exception
@@ -180,6 +185,7 @@
 
     /**
      * Ping with 125 byte binary payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_4() throws Exception
@@ -206,6 +212,7 @@
 
     /**
      * Ping with 126 byte binary payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_5() throws Exception
@@ -236,6 +243,7 @@
 
     /**
      * Ping with 125 byte binary payload (slow send)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_6() throws Exception
@@ -263,6 +271,7 @@
 
     /**
      * Unsolicited pong frame without payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_7() throws Exception
@@ -285,6 +294,7 @@
 
     /**
      * Unsolicited pong frame with basic payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_8() throws Exception
@@ -307,6 +317,7 @@
 
     /**
      * Unsolicited pong frame, then ping with basic payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase2_9() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase3.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase3.java
index 214b30c..5b6daca 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase3.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase3.java
@@ -43,6 +43,7 @@
 {
     /**
      * Send small text frame, with RSV1 == true, with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_1() throws Exception
@@ -62,6 +63,7 @@
 
     /**
      * Send small text frame, send again with RSV2 == true, then ping, with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_2() throws Exception
@@ -86,6 +88,7 @@
 
     /**
      * Send small text frame, send again with (RSV1 & RSV2), then ping, with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_3() throws Exception
@@ -110,6 +113,7 @@
 
     /**
      * Send small text frame, send again with (RSV3), then ping, with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_4() throws Exception
@@ -135,6 +139,7 @@
 
     /**
      * Send binary frame with (RSV3 & RSV1), with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_5() throws Exception
@@ -159,6 +164,7 @@
 
     /**
      * Send ping frame with (RSV3 & RSV2), with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_6() throws Exception
@@ -183,6 +189,7 @@
 
     /**
      * Send close frame with (RSV3 & RSV2 & RSV1), with no extensions defined.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase3_7() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase4.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase4.java
index 8b2efce..e0bf1af 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase4.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase4.java
@@ -43,6 +43,7 @@
 {
     /**
      * Send opcode 3 (reserved)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_1_1() throws Exception
@@ -64,6 +65,7 @@
 
     /**
      * Send opcode 4 (reserved), with payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_1_2() throws Exception
@@ -88,6 +90,7 @@
 
     /**
      * Send small text, then frame with opcode 5 (reserved), then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_1_3() throws Exception
@@ -112,6 +115,7 @@
 
     /**
      * Send small text, then frame with opcode 6 (reserved) w/payload, then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_1_4() throws Exception
@@ -138,6 +142,7 @@
 
     /**
      * Send small text, then frame with opcode 7 (reserved) w/payload, then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_1_5() throws Exception
@@ -164,6 +169,7 @@
 
     /**
      * Send opcode 11 (reserved)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_2_1() throws Exception
@@ -185,6 +191,7 @@
 
     /**
      * Send opcode 12 (reserved)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_2_2() throws Exception
@@ -208,6 +215,7 @@
 
     /**
      * Send small text, then frame with opcode 13 (reserved), then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_2_3() throws Exception
@@ -232,6 +240,7 @@
 
     /**
      * Send small text, then frame with opcode 14 (reserved), then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_2_4() throws Exception
@@ -258,6 +267,7 @@
 
     /**
      * Send small text, then frame with opcode 15 (reserved), then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase4_2_5() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase5.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase5.java
index a64f353..5fffc70 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase5.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase5.java
@@ -45,6 +45,7 @@
 {
     /**
      * Send ping fragmented in 2 packets
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_1() throws Exception
@@ -68,6 +69,7 @@
 
     /**
      * Send continuation+fin, then text+fin (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_10() throws Exception
@@ -91,6 +93,7 @@
 
     /**
      * Send continuation+fin, then text+fin (slowly)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_11() throws Exception
@@ -115,6 +118,7 @@
 
     /**
      * Send continuation+!fin, then text+fin
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_12() throws Exception
@@ -138,6 +142,7 @@
 
     /**
      * Send continuation+!fin, then text+fin (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_13() throws Exception
@@ -161,6 +166,7 @@
 
     /**
      * Send continuation+!fin, then text+fin (slowly)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_14() throws Exception
@@ -185,6 +191,7 @@
 
     /**
      * Send text fragmented properly in 2 frames, then continuation!fin, then text unfragmented.
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_15() throws Exception
@@ -211,6 +218,7 @@
 
     /**
      * (continuation!fin, text!fin, continuation+fin) * 2
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_16() throws Exception
@@ -238,6 +246,7 @@
 
     /**
      * (continuation+fin, text!fin, continuation+fin) * 2
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_17() throws Exception
@@ -265,6 +274,7 @@
 
     /**
      * text message fragmented in 2 frames, both frames as opcode=TEXT
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_18() throws Exception
@@ -288,6 +298,7 @@
 
     /**
      * send text message fragmented in 5 frames, with 2 pings and wait between.
+     * @throws Exception on test failure
      */
     @Test
     @Slow
@@ -335,6 +346,7 @@
 
     /**
      * Send pong fragmented in 2 packets
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_2() throws Exception
@@ -358,6 +370,7 @@
 
     /**
      * send text message fragmented in 5 frames, with 2 pings and wait between. (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_20() throws Exception
@@ -399,6 +412,7 @@
 
     /**
      * send text message fragmented in 5 frames, with 2 pings and wait between. (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_20_slow() throws Exception
@@ -441,6 +455,7 @@
 
     /**
      * Send text fragmented in 2 packets
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_3() throws Exception
@@ -465,6 +480,7 @@
 
     /**
      * Send text fragmented in 2 packets (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_4() throws Exception
@@ -489,6 +505,7 @@
 
     /**
      * Send text fragmented in 2 packets (slowly)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_5() throws Exception
@@ -514,6 +531,7 @@
 
     /**
      * Send text fragmented in 2 packets, with ping between them
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_6() throws Exception
@@ -540,6 +558,7 @@
 
     /**
      * Send text fragmented in 2 packets, with ping between them (framewise)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_7() throws Exception
@@ -566,6 +585,7 @@
 
     /**
      * Send text fragmented in 2 packets, with ping between them (slowly)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_8() throws Exception
@@ -593,6 +613,7 @@
 
     /**
      * Send continuation+fin, then text+fin
+     * @throws Exception on test failure
      */
     @Test
     public void testCase5_9() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6.java
index 0f379ab..582798f 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase6.java
@@ -49,6 +49,8 @@
 {
     /**
      * Split a message byte array into a series of fragments (frames + continuations) of 1 byte message contents each.
+     * @param frames the frames
+     * @param msg the message
      */
     protected void fragmentText(List<WebSocketFrame> frames, byte msg[])
     {
@@ -78,6 +80,7 @@
 
     /**
      * text message, 1 frame, 0 length
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_1_1() throws Exception
@@ -101,6 +104,7 @@
 
     /**
      * text message, 0 length, 3 fragments
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_1_2() throws Exception
@@ -126,6 +130,7 @@
 
     /**
      * text message, small length, 3 fragments (only middle frame has payload)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_1_3() throws Exception
@@ -151,6 +156,7 @@
 
     /**
      * valid utf8 text message, 2 fragments (on UTF8 code point boundary)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_2_2() throws Exception
@@ -185,6 +191,7 @@
 
     /**
      * valid utf8 text message, many fragments (1 byte each)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_2_3() throws Exception
@@ -211,6 +218,7 @@
 
     /**
      * valid utf8 text message, many fragments (1 byte each)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_2_4() throws Exception
@@ -236,6 +244,7 @@
 
     /**
      * invalid utf8 text message, many fragments (1 byte each)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase6_3_2() throws Exception
@@ -264,6 +273,7 @@
      * fragment #1 and fragment #3 are both valid in themselves.
      * <p>
      * fragment #2 contains the invalid utf8 code point.
+     * @throws Exception on test failure
      */
     @Test
     @Slow
@@ -299,6 +309,7 @@
      * fragment #2 finishes the UTF8 code point but it is invalid
      * <p>
      * fragment #3 contains the remainder of the message.
+     * @throws Exception on test failure
      */
     @Test
     @Slow
@@ -326,6 +337,7 @@
 
     /**
      * invalid text message, 1 frame/fragment (slowly, and split within code points)
+     * @throws Exception on test failure
      */
     @Test
     @Slow
@@ -378,6 +390,7 @@
 
     /**
      * invalid text message, 1 frame/fragment (slowly, and split within code points)
+     * @throws Exception on test failure
      */
     @Test
     @Slow
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java
index c2827ff..3020f0e 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7.java
@@ -52,6 +52,7 @@
 
     /**
      * Basic message then close frame, normal behavior
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_1() throws Exception
@@ -75,6 +76,7 @@
 
     /**
      * Close frame, then another close frame (send frame ignored)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_2() throws Exception
@@ -98,6 +100,7 @@
 
     /**
      * Close frame, then ping frame (no pong received)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_3() throws Exception
@@ -121,6 +124,7 @@
 
     /**
      * Close frame, then ping frame (no pong received)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_4() throws Exception
@@ -144,6 +148,7 @@
 
     /**
      * Text fin=false, close, then continuation fin=true
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_5() throws Exception
@@ -168,6 +173,7 @@
 
     /**
      * 256k msg, then close, then ping
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_1_6() throws Exception
@@ -197,6 +203,7 @@
 
     /**
      * close with no payload (payload length 0)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_3_1() throws Exception
@@ -219,6 +226,7 @@
 
     /**
      * close with invalid payload (payload length 1)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_3_2() throws Exception
@@ -244,6 +252,7 @@
 
     /**
      * close with valid payload (payload length 2)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_3_3() throws Exception
@@ -266,6 +275,7 @@
 
     /**
      * close with valid payload (with reason)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_3_4() throws Exception
@@ -288,6 +298,7 @@
 
     /**
      * close with valid payload (with 123 byte reason)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_3_5() throws Exception
@@ -314,6 +325,7 @@
 
     /**
      * close with invalid UTF8 in payload
+     * @throws Exception on test failure
      */
     @Test
     public void testCase7_5_1() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java
index 5c97ac8..23729c3 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_BadStatusCodes.java
@@ -83,6 +83,7 @@
 
     /**
      * just the close code, no reason
+     * @throws Exception on test failure
      */
     @Test
     public void testBadStatusCode() throws Exception
@@ -110,6 +111,7 @@
 
     /**
      * the bad close code, with reason
+     * @throws Exception on test failure
      */
     @Test
     public void testBadStatusCodeWithReason() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java
index a0c2256..d006390 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase7_GoodStatusCodes.java
@@ -78,6 +78,7 @@
 
     /**
      * just the close code, no reason
+     * @throws Exception on test failure
      */
     @Test
     public void testStatusCode() throws Exception
@@ -105,6 +106,7 @@
 
     /**
      * the good close code, with reason
+     * @throws Exception on test failure
      */
     @Test
     public void testStatusCodeWithReason() throws Exception
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase9.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase9.java
index 71b93d5..dd7c8d0 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase9.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/TestABCase9.java
@@ -131,6 +131,7 @@
 
     /**
      * Echo 64KB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_1_1() throws Exception
@@ -158,6 +159,7 @@
 
     /**
      * Echo 256KB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_1_2() throws Exception
@@ -185,6 +187,7 @@
 
     /**
      * Echo 1MB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_1_3() throws Exception
@@ -212,6 +215,7 @@
 
     /**
      * Echo 4MB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_1_4() throws Exception
@@ -239,6 +243,7 @@
 
     /**
      * Echo 8MB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -267,6 +272,7 @@
 
     /**
      * Echo 16MB text message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -295,6 +301,7 @@
 
     /**
      * Echo 64KB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_2_1() throws Exception
@@ -321,6 +328,7 @@
 
     /**
      * Echo 256KB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     public void testCase9_2_2() throws Exception
@@ -348,6 +356,7 @@
 
     /**
      * Echo 1MB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -376,6 +385,7 @@
 
     /**
      * Echo 4MB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -404,6 +414,7 @@
 
     /**
      * Echo 8MB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -432,6 +443,7 @@
 
     /**
      * Echo 16MB binary message (1 frame)
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -460,6 +472,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -470,6 +483,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -480,6 +494,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -490,6 +505,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -500,6 +516,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -510,6 +527,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -520,6 +538,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -530,6 +549,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -540,6 +560,7 @@
 
     /**
      * Send 4MB text message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -550,6 +571,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -560,6 +582,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -570,6 +593,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -580,6 +604,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -590,6 +615,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -600,6 +626,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -610,6 +637,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -620,6 +648,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -630,6 +659,7 @@
 
     /**
      * Send 4MB binary message in multiple frames.
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -640,6 +670,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -650,6 +681,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -660,6 +692,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -670,6 +703,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -680,6 +714,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -690,6 +725,7 @@
 
     /**
      * Send 1MB text message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -700,6 +736,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -710,6 +747,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -720,6 +758,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -730,6 +769,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -740,6 +780,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
@@ -750,6 +791,7 @@
 
     /**
      * Send 1MB binary message in 1 frame, but slowly
+     * @throws Exception on test failure
      */
     @Test
     @Stress("High I/O use")
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
index 9a09ee8..bf92c8e 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/browser/BrowserDebugTool.java
@@ -27,8 +27,7 @@
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
-import org.eclipse.jetty.websocket.common.extensions.FrameDebugExtension;
-import org.eclipse.jetty.websocket.common.extensions.compress.PerMessageDeflateExtension;
+import org.eclipse.jetty.websocket.common.extensions.FrameCaptureExtension;
 import org.eclipse.jetty.websocket.server.WebSocketHandler;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
 import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
@@ -93,7 +92,7 @@
         // manually negotiate extensions
         List<ExtensionConfig> negotiated = new ArrayList<>();
         // adding frame debug
-        negotiated.add(new ExtensionConfig("@frame-debug; output-dir=target"));
+        negotiated.add(new ExtensionConfig("@frame-capture; output-dir=target"));
         for (ExtensionConfig config : req.getExtensions())
         {
             if (config.getName().equals("permessage-deflate"))
@@ -134,7 +133,7 @@
                 LOG.debug("Configuring WebSocketServerFactory ...");
 
                 // Registering Frame Debug
-                factory.getExtensionFactory().register("@frame-debug",FrameDebugExtension.class);
+                factory.getExtensionFactory().register("@frame-capture",FrameCaptureExtension.class);
 
                 // Setup the desired Socket to use for all incoming upgrade requests
                 factory.setCreator(BrowserDebugTool.this);
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java
index 8f7dc74..77dae60 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/CaptureSocket.java
@@ -18,12 +18,14 @@
 
 package org.eclipse.jetty.websocket.server.helper;
 
+import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.toolchain.test.EventQueue;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.eclipse.jetty.websocket.common.util.Sha1Sum;
 
 public class CaptureSocket extends WebSocketAdapter
 {
@@ -58,4 +60,18 @@
         // System.out.printf("Received Message \"%s\" [size %d]%n", message, message.length());
         messages.add(message);
     }
+    
+    @Override
+    public void onWebSocketBinary(byte[] payload, int offset, int len)
+    {
+        try
+        {
+            messages.add("binary[sha1="+Sha1Sum.calculate(payload,offset,len)+"]");
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            messages.add("ERROR: Unable to caclulate Binary SHA1: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
 }
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SafariD00.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SafariD00.java
index 6c65aca..67c7e4e 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SafariD00.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SafariD00.java
@@ -18,13 +18,15 @@
 
 package org.eclipse.jetty.websocket.server.helper;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
@@ -54,7 +56,7 @@
      * Open the Socket to the destination endpoint and
      *
      * @return the open java Socket.
-     * @throws IOException
+     * @throws IOException on test failure
      */
     public Socket connect() throws IOException
     {
@@ -75,7 +77,7 @@
     /**
      * Issue an Http websocket (Draft-0) upgrade request using the Safari particulars.
      *
-     * @throws UnsupportedEncodingException
+     * @throws IOException on test failure
      */
     public void issueHandshake() throws IOException
     {
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java
index 4ae7b5d..326a38a 100644
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java
+++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java
@@ -31,6 +31,7 @@
 import org.eclipse.jetty.websocket.common.WebSocketFrame;
 import org.eclipse.jetty.websocket.common.events.AbstractEventDriver;
 import org.eclipse.jetty.websocket.common.test.BlockheadClient;
+import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
 import org.eclipse.jetty.websocket.server.SimpleServletServer;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -62,7 +63,7 @@
     @Test
     public void testListenerRuntimeOnConnect() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("listener-runtime-connect");
             client.setTimeout(1,TimeUnit.SECONDS);
@@ -98,7 +99,7 @@
     @Test
     public void testAnnotatedRuntimeOnConnect() throws Exception
     {
-        try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
+        try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
         {
             client.setProtocols("annotated-runtime-connect");
             client.setTimeout(1,TimeUnit.SECONDS);
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsBenchmarkTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsBenchmarkTest.java
deleted file mode 100644
index 475c70d..0000000
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsBenchmarkTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.toolchain.test.AdvancedRunner;
-import org.eclipse.jetty.toolchain.test.annotation.Stress;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AdvancedRunner.class)
-public class PathMappingsBenchmarkTest
-{
-    public static abstract class AbstractPathMapThread extends Thread
-    {
-        private int iterations;
-        private CyclicBarrier barrier;
-        @SuppressWarnings("unused")
-        private long success;
-        @SuppressWarnings("unused")
-        private long error;
-
-        public AbstractPathMapThread(int iterations, CyclicBarrier barrier)
-        {
-            this.iterations = iterations;
-            this.barrier = barrier;
-        }
-
-        public abstract String getMatchedResource(String path);
-
-        @Override
-        public void run()
-        {
-            int llen = LOOKUPS.length;
-            String path;
-            String expectedResource;
-            String matchedResource;
-            await(barrier);
-            for (int iter = 0; iter < iterations; iter++)
-            {
-                for (int li = 0; li < llen; li++)
-                {
-                    path = LOOKUPS[li][0];
-                    expectedResource = LOOKUPS[li][1];
-                    matchedResource = getMatchedResource(path);
-                    if (matchedResource.equals(expectedResource))
-                    {
-                        success++;
-                    }
-                    else
-                    {
-                        error++;
-                    }
-                }
-            }
-            await(barrier);
-        }
-    }
-
-    public static class PathMapMatchThread extends AbstractPathMapThread
-    {
-        private PathMap<String> pathmap;
-
-        public PathMapMatchThread(PathMap<String> pathmap, int iters, CyclicBarrier barrier)
-        {
-            super(iters,barrier);
-            this.pathmap = pathmap;
-        }
-
-        @Override
-        public String getMatchedResource(String path)
-        {
-            return pathmap.getMatch(path).getValue();
-        }
-    }
-
-    public static class PathMatchThread extends AbstractPathMapThread
-    {
-        private PathMappings<String> pathmap;
-
-        public PathMatchThread(PathMappings<String> pathmap, int iters, CyclicBarrier barrier)
-        {
-            super(iters,barrier);
-            this.pathmap = pathmap;
-        }
-
-        @Override
-        public String getMatchedResource(String path)
-        {
-            return pathmap.getMatch(path).getResource();
-        }
-    }
-
-    private static final Logger LOG = Log.getLogger(PathMappingsBenchmarkTest.class);
-    private static final String[][] LOOKUPS;
-    private int runs = 20;
-    private int threads = 200;
-    private int iters = 10000;
-
-    static
-    {
-        LOOKUPS = new String[][]
-        {
-        // @formatter:off
-         { "/abs/path", "path" },
-         { "/abs/path/longer","longpath" },
-         { "/abs/path/foo","default" },
-         { "/main.css","default" },
-         { "/downloads/script.gz","gzipped" },
-         { "/downloads/distribution.tar.gz","tarball" },
-         { "/downloads/readme.txt","default" },
-         { "/downloads/logs.tgz","default" },
-         { "/animal/horse/mustang","animals" },
-         { "/animal/bird/eagle/bald","birds" },
-         { "/animal/fish/shark/hammerhead","fishes" },
-         { "/animal/insect/ladybug","animals" },
-        // @formatter:on
-        };
-    }
-
-    private static void await(CyclicBarrier barrier)
-    {
-        try
-        {
-            barrier.await();
-        }
-        catch (Exception x)
-        {
-            throw new RuntimeException(x);
-        }
-    }
-
-    @Stress("High CPU")
-    @Test
-    public void testServletPathMap()
-    {
-        // Setup (old) PathMap
-
-        PathMap<String> p = new PathMap<>();
-
-        p.put("/abs/path","path");
-        p.put("/abs/path/longer","longpath");
-        p.put("/animal/bird/*","birds");
-        p.put("/animal/fish/*","fishes");
-        p.put("/animal/*","animals");
-        p.put("*.tar.gz","tarball");
-        p.put("*.gz","gzipped");
-        p.put("/","default");
-
-        final CyclicBarrier barrier = new CyclicBarrier(threads + 1);
-
-        for (int r = 0; r < runs; r++)
-        {
-            for (int t = 0; t < threads; t++)
-            {
-                PathMapMatchThread thread = new PathMapMatchThread(p,iters,barrier);
-                thread.start();
-            }
-            await(barrier);
-            long begin = System.nanoTime();
-            await(barrier);
-            long end = System.nanoTime();
-            long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin);
-            int totalMatches = threads * iters * LOOKUPS.length;
-            LOG.info("jetty-http/PathMap (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed);
-        }
-    }
-
-    @Stress("High CPU")
-    @Test
-    public void testServletPathMappings()
-    {
-        // Setup (new) PathMappings
-
-        PathMappings<String> p = new PathMappings<>();
-
-        p.put(new ServletPathSpec("/abs/path"),"path");
-        p.put(new ServletPathSpec("/abs/path/longer"),"longpath");
-        p.put(new ServletPathSpec("/animal/bird/*"),"birds");
-        p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
-        p.put(new ServletPathSpec("/animal/*"),"animals");
-        p.put(new ServletPathSpec("*.tar.gz"),"tarball");
-        p.put(new ServletPathSpec("*.gz"),"gzipped");
-        p.put(new ServletPathSpec("/"),"default");
-
-        final CyclicBarrier barrier = new CyclicBarrier(threads + 1);
-
-        for (int r = 0; r < runs; r++)
-        {
-            for (int t = 0; t < threads; t++)
-            {
-                PathMatchThread thread = new PathMatchThread(p,iters,barrier);
-                thread.start();
-            }
-            await(barrier);
-            long begin = System.nanoTime();
-            await(barrier);
-            long end = System.nanoTime();
-            long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin);
-            int totalMatches = threads * iters * LOOKUPS.length;
-            LOG.info("jetty-websocket/PathMappings (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed);
-
-        }
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsTest.java
deleted file mode 100644
index d79522b..0000000
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/PathMappingsTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-import static org.hamcrest.Matchers.notNullValue;
-
-import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class PathMappingsTest
-{
-    private void assertMatch(PathMappings<String> pathmap, String path, String expectedValue)
-    {
-        String msg = String.format(".getMatch(\"%s\")",path);
-        MappedResource<String> match = pathmap.getMatch(path);
-        Assert.assertThat(msg,match,notNullValue());
-        String actualMatch = match.getResource();
-        Assert.assertEquals(msg,expectedValue,actualMatch);
-    }
-
-    public void dumpMappings(PathMappings<String> p)
-    {
-        for (MappedResource<String> res : p)
-        {
-            System.out.printf("  %s%n",res);
-        }
-    }
-
-    /**
-     * Test the match order rules with a mixed Servlet and WebSocket path specs
-     * <p>
-     * <ul>
-     * <li>Exact match</li>
-     * <li>Longest prefix match</li>
-     * <li>Longest suffix match</li>
-     * </ul>
-     */
-    @Test
-    public void testMixedMatchOrder()
-    {
-        PathMappings<String> p = new PathMappings<>();
-
-        p.put(new ServletPathSpec("/"),"default");
-        p.put(new ServletPathSpec("/animal/bird/*"),"birds");
-        p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
-        p.put(new ServletPathSpec("/animal/*"),"animals");
-        p.put(new RegexPathSpec("^/animal/.*/chat$"),"animalChat");
-        p.put(new RegexPathSpec("^/animal/.*/cam$"),"animalCam");
-        p.put(new RegexPathSpec("^/entrance/cam$"),"entranceCam");
-
-        // dumpMappings(p);
-
-        assertMatch(p,"/animal/bird/eagle","birds");
-        assertMatch(p,"/animal/fish/bass/sea","fishes");
-        assertMatch(p,"/animal/peccary/javalina/evolution","animals");
-        assertMatch(p,"/","default");
-        assertMatch(p,"/animal/bird/eagle/chat","animalChat");
-        assertMatch(p,"/animal/bird/penguin/chat","animalChat");
-        assertMatch(p,"/animal/fish/trout/cam","animalCam");
-        assertMatch(p,"/entrance/cam","entranceCam");
-    }
-
-    /**
-     * Test the match order rules imposed by the Servlet API.
-     * <p>
-     * <ul>
-     * <li>Exact match</li>
-     * <li>Longest prefix match</li>
-     * <li>Longest suffix match</li>
-     * <li>default</li>
-     * </ul>
-     */
-    @Test
-    public void testServletMatchOrder()
-    {
-        PathMappings<String> p = new PathMappings<>();
-
-        p.put(new ServletPathSpec("/abs/path"),"path");
-        p.put(new ServletPathSpec("/abs/path/longer"),"longpath");
-        p.put(new ServletPathSpec("/animal/bird/*"),"birds");
-        p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
-        p.put(new ServletPathSpec("/animal/*"),"animals");
-        p.put(new ServletPathSpec("*.tar.gz"),"tarball");
-        p.put(new ServletPathSpec("*.gz"),"gzipped");
-        p.put(new ServletPathSpec("/"),"default");
-
-        // dumpMappings(p);
-
-        assertMatch(p,"/abs/path","path");
-        assertMatch(p,"/abs/path/longer","longpath");
-        assertMatch(p,"/abs/path/foo","default");
-        assertMatch(p,"/main.css","default");
-        assertMatch(p,"/downloads/script.gz","gzipped");
-        assertMatch(p,"/downloads/distribution.tar.gz","tarball");
-        assertMatch(p,"/downloads/readme.txt","default");
-        assertMatch(p,"/downloads/logs.tgz","default");
-        assertMatch(p,"/animal/horse/mustang","animals");
-        assertMatch(p,"/animal/bird/eagle/bald","birds");
-        assertMatch(p,"/animal/fish/shark/hammerhead","fishes");
-        assertMatch(p,"/animal/insect/ladybug","animals");
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpecTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpecTest.java
deleted file mode 100644
index 269a056..0000000
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/RegexPathSpecTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-
-public class RegexPathSpecTest
-{
-    public static void assertMatches(PathSpec spec, String path)
-    {
-        String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(true));
-    }
-
-    public static void assertNotMatches(PathSpec spec, String path)
-    {
-        String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(false));
-    }
-
-    @Test
-    public void testExactSpec()
-    {
-        RegexPathSpec spec = new RegexPathSpec("^/a$");
-        assertEquals("Spec.pathSpec","^/a$",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",1,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.EXACT,spec.group);
-
-        assertMatches(spec,"/a");
-
-        assertNotMatches(spec,"/aa");
-        assertNotMatches(spec,"/a/");
-    }
-
-    @Test
-    public void testMiddleSpec()
-    {
-        RegexPathSpec spec = new RegexPathSpec("^/rest/([^/]*)/list$");
-        assertEquals("Spec.pathSpec","^/rest/([^/]*)/list$",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/rest/([^/]*)/list$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",3,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group);
-
-        assertMatches(spec,"/rest/api/list");
-        assertMatches(spec,"/rest/1.0/list");
-        assertMatches(spec,"/rest/2.0/list");
-        assertMatches(spec,"/rest/accounts/list");
-
-        assertNotMatches(spec,"/a");
-        assertNotMatches(spec,"/aa");
-        assertNotMatches(spec,"/aa/bb");
-        assertNotMatches(spec,"/rest/admin/delete");
-        assertNotMatches(spec,"/rest/list");
-    }
-
-    @Test
-    public void testMiddleSpecNoGrouping()
-    {
-        RegexPathSpec spec = new RegexPathSpec("^/rest/[^/]+/list$");
-        assertEquals("Spec.pathSpec","^/rest/[^/]+/list$",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/rest/[^/]+/list$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",3,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group);
-
-        assertMatches(spec,"/rest/api/list");
-        assertMatches(spec,"/rest/1.0/list");
-        assertMatches(spec,"/rest/2.0/list");
-        assertMatches(spec,"/rest/accounts/list");
-
-        assertNotMatches(spec,"/a");
-        assertNotMatches(spec,"/aa");
-        assertNotMatches(spec,"/aa/bb");
-        assertNotMatches(spec,"/rest/admin/delete");
-        assertNotMatches(spec,"/rest/list");
-    }
-
-    @Test
-    public void testPrefixSpec()
-    {
-        RegexPathSpec spec = new RegexPathSpec("^/a/(.*)$");
-        assertEquals("Spec.pathSpec","^/a/(.*)$",spec.getPathSpec());
-        assertEquals("Spec.pattern","^/a/(.*)$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",2,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.group);
-
-        assertMatches(spec,"/a/");
-        assertMatches(spec,"/a/b");
-        assertMatches(spec,"/a/b/c/d/e");
-
-        assertNotMatches(spec,"/a");
-        assertNotMatches(spec,"/aa");
-        assertNotMatches(spec,"/aa/bb");
-    }
-
-    @Test
-    public void testSuffixSpec()
-    {
-        RegexPathSpec spec = new RegexPathSpec("^(.*).do$");
-        assertEquals("Spec.pathSpec","^(.*).do$",spec.getPathSpec());
-        assertEquals("Spec.pattern","^(.*).do$",spec.getPattern().pattern());
-        assertEquals("Spec.pathDepth",0,spec.getPathDepth());
-        assertEquals("Spec.group",PathSpecGroup.SUFFIX_GLOB,spec.group);
-
-        assertMatches(spec,"/a.do");
-        assertMatches(spec,"/a/b/c.do");
-        assertMatches(spec,"/abcde.do");
-        assertMatches(spec,"/abc/efg.do");
-
-        assertNotMatches(spec,"/a");
-        assertNotMatches(spec,"/aa");
-        assertNotMatches(spec,"/aa/bb");
-        assertNotMatches(spec,"/aa/bb.do/more");
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpecTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpecTest.java
deleted file mode 100644
index 42a0d6b..0000000
--- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/pathmap/ServletPathSpecTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.websocket.server.pathmap;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-public class ServletPathSpecTest
-{
-    private void assertBadServletPathSpec(String pathSpec)
-    {
-        try
-        {
-            new ServletPathSpec(pathSpec);
-            fail("Expected IllegalArgumentException for a bad servlet pathspec on: " + pathSpec);
-        }
-        catch (IllegalArgumentException e)
-        {
-            // expected path
-            System.out.println(e);
-        }
-    }
-
-    private void assertMatches(ServletPathSpec spec, String path)
-    {
-        String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(true));
-    }
-
-    private void assertNotMatches(ServletPathSpec spec, String path)
-    {
-        String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path);
-        assertThat(msg,spec.matches(path),is(false));
-    }
-
-    @Test
-    public void testBadServletPathSpecA()
-    {
-        assertBadServletPathSpec("foo");
-    }
-
-    @Test
-    public void testBadServletPathSpecB()
-    {
-        assertBadServletPathSpec("/foo/*.do");
-    }
-
-    @Test
-    public void testBadServletPathSpecC()
-    {
-        assertBadServletPathSpec("foo/*.do");
-    }
-
-    @Test
-    public void testBadServletPathSpecD()
-    {
-        assertBadServletPathSpec("foo/*.*do");
-    }
-
-    @Test
-    public void testBadServletPathSpecE()
-    {
-        assertBadServletPathSpec("*do");
-    }
-
-    @Test
-    public void testDefaultPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec("/");
-        assertEquals("Spec.pathSpec","/",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
-    }
-
-    @Test
-    public void testEmptyPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec("");
-        assertEquals("Spec.pathSpec","/",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
-    }
-
-    @Test
-    public void testExactPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec("/abs/path");
-        assertEquals("Spec.pathSpec","/abs/path",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",2,spec.getPathDepth());
-
-        assertMatches(spec,"/abs/path");
-        assertMatches(spec,"/abs/path/");
-
-        assertNotMatches(spec,"/abs/path/more");
-        assertNotMatches(spec,"/foo");
-        assertNotMatches(spec,"/foo/abs/path");
-        assertNotMatches(spec,"/foo/abs/path/");
-    }
-
-    @Test
-    public void testGetPathInfo()
-    {
-        assertEquals("pathInfo exact",null,new ServletPathSpec("/Foo/bar").getPathInfo("/Foo/bar"));
-        assertEquals("pathInfo prefix","/bar",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/bar"));
-        assertEquals("pathInfo prefix","/*",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/*"));
-        assertEquals("pathInfo prefix","/",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/"));
-        assertEquals("pathInfo prefix",null,new ServletPathSpec("/Foo/*").getPathInfo("/Foo"));
-        assertEquals("pathInfo suffix",null,new ServletPathSpec("*.ext").getPathInfo("/Foo/bar.ext"));
-        assertEquals("pathInfo default",null,new ServletPathSpec("/").getPathInfo("/Foo/bar.ext"));
-
-        assertEquals("pathInfo default","/xxx/zzz",new ServletPathSpec("/*").getPathInfo("/xxx/zzz"));
-    }
-
-    @Test
-    public void testNullPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec(null);
-        assertEquals("Spec.pathSpec","/",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
-    }
-
-    @Test
-    public void testPathMatch()
-    {
-        assertEquals("pathMatch exact","/Foo/bar",new ServletPathSpec("/Foo/bar").getPathMatch("/Foo/bar"));
-        assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/bar"));
-        assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/"));
-        assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo"));
-        assertEquals("pathMatch suffix","/Foo/bar.ext",new ServletPathSpec("*.ext").getPathMatch("/Foo/bar.ext"));
-        assertEquals("pathMatch default","/Foo/bar.ext",new ServletPathSpec("/").getPathMatch("/Foo/bar.ext"));
-
-        assertEquals("pathMatch default","",new ServletPathSpec("/*").getPathMatch("/xxx/zzz"));
-    }
-
-    @Test
-    public void testPrefixPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec("/downloads/*");
-        assertEquals("Spec.pathSpec","/downloads/*",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",2,spec.getPathDepth());
-
-        assertMatches(spec,"/downloads/logo.jpg");
-        assertMatches(spec,"/downloads/distribution.tar.gz");
-        assertMatches(spec,"/downloads/distribution.tgz");
-        assertMatches(spec,"/downloads/distribution.zip");
-
-        assertMatches(spec,"/downloads");
-
-        assertEquals("Spec.pathInfo","/",spec.getPathInfo("/downloads/"));
-        assertEquals("Spec.pathInfo","/distribution.zip",spec.getPathInfo("/downloads/distribution.zip"));
-        assertEquals("Spec.pathInfo","/dist/9.0/distribution.tar.gz",spec.getPathInfo("/downloads/dist/9.0/distribution.tar.gz"));
-    }
-
-    @Test
-    public void testSuffixPathSpec()
-    {
-        ServletPathSpec spec = new ServletPathSpec("*.gz");
-        assertEquals("Spec.pathSpec","*.gz",spec.getPathSpec());
-        assertEquals("Spec.pathDepth",0,spec.getPathDepth());
-
-        assertMatches(spec,"/downloads/distribution.tar.gz");
-        assertMatches(spec,"/downloads/jetty.log.gz");
-
-        assertNotMatches(spec,"/downloads/distribution.zip");
-        assertNotMatches(spec,"/downloads/distribution.tgz");
-        assertNotMatches(spec,"/abs/path");
-
-        assertEquals("Spec.pathInfo",null,spec.getPathInfo("/downloads/distribution.tar.gz"));
-    }
-}
diff --git a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
index 9165916..924d000 100644
--- a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
+++ b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
@@ -12,6 +12,11 @@
 # org.eclipse.jetty.websocket.server.blockhead.LEVEL=DEBUG
 # org.eclipse.jetty.websocket.server.helper.LEVEL=DEBUG
 
+# org.eclipse.jetty.websocket.client.io.ConnectPromise.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.WebSocketSession_OPEN.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.io.IOState.LEVEL=DEBUG
+# org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection_OPEN.LEVEL=DEBUG
+
 ### Show state changes on BrowserDebugTool
 # -- LEAVE THIS AT DEBUG LEVEL --
 org.eclipse.jetty.websocket.server.browser.LEVEL=DEBUG
diff --git a/jetty-websocket/websocket-servlet/pom.xml b/jetty-websocket/websocket-servlet/pom.xml
index 4dbc6f6..196270c 100644
--- a/jetty-websocket/websocket-servlet/pom.xml
+++ b/jetty-websocket/websocket-servlet/pom.xml
@@ -3,7 +3,7 @@
     <parent>
         <groupId>org.eclipse.jetty.websocket</groupId>
         <artifactId>websocket-parent</artifactId>
-        <version>9.2.15-SNAPSHOT</version>
+        <version>9.3.7-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -15,23 +15,6 @@
     </properties>
     <build>
       <plugins>
-           <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>artifact-jar</id>
-                        <goals>
-                            <goal>jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-                <configuration>
-                    <archive>
-                        <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
-                    </archive>
-                </configuration>
-            </plugin>
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
@@ -40,7 +23,6 @@
                     <instructions>
                         <Bundle-Description>Websocket Servlet Interface</Bundle-Description>
                         <Bundle-Classpath />
-                        <_nouses>true</_nouses>
                         <DynamicImport-Package>org.eclipse.jetty.websocket.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}",org.eclipse.jetty.websocket.server.pathmap.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}"</DynamicImport-Package>
                         <Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.websocket.servlet.WebSocketServletFactory)";cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
                     </instructions>
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
index 6062670..30458d3 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
@@ -31,6 +31,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
@@ -107,7 +108,7 @@
 
     /**
      * Return the underlying HttpServletRequest that existed at Upgrade time.
-     * <p/>
+     * <p>
      * Note: many features of the HttpServletRequest are invalid when upgraded,
      * especially ones that deal with body content, streams, readers, and responses.
      *
@@ -150,7 +151,7 @@
 
     /**
      * Return a {@link InetSocketAddress} for the local socket.
-     * <p/>
+     * <p>
      * Warning: this can cause a DNS lookup
      *
      * @return the local socket address
@@ -181,6 +182,7 @@
     }
 
     /**
+     * @return the principal
      * @deprecated use {@link #getUserPrincipal()} instead
      */
     @Deprecated
@@ -229,7 +231,7 @@
 
     /**
      * Return a {@link InetSocketAddress} for the remote socket.
-     * <p/>
+     * <p>
      * Warning: this can cause a DNS lookup
      *
      * @return the remote socket address
@@ -251,7 +253,7 @@
 
     /**
      * Return the HttpSession if it exists.
-     * <p/>
+     * <p>
      * Note: this is equivalent to {@link HttpServletRequest#getSession(boolean)}
      * and will not create a new HttpSession.
      */
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java
index f74e392..4b6914f 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeResponse.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
+
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.websocket.api.UpgradeResponse;
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java
index d9e0c62..0762c80 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketCreator.java
@@ -24,7 +24,7 @@
  * Should you desire filtering of the WebSocket object creation due to criteria such as origin or sub-protocol, then you will be required to implement a custom
  * WebSocketCreator implementation.
  * <p>
- * This has been moved from the WebSocketServlet to a standalone class managed by the WebSocketServerFactory due to need of WebSocket {@link Extension}s that
+ * This has been moved from the WebSocketServlet to a standalone class managed by the WebSocketServerFactory due to need of WebSocket {@link org.eclipse.jetty.websocket.api.extensions.Extension}s that
  * require the ability to create new websockets (such as the mux extension)
  */
 public interface WebSocketCreator
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
index 6b55e08..bf99fc1 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
@@ -20,6 +20,7 @@
 
 import java.io.IOException;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -27,6 +28,7 @@
 
 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
 
 /**
  * Abstract Servlet used to bridge the Servlet API to the WebSocket API.
@@ -128,10 +130,12 @@
             factory = WebSocketServletFactory.Loader.create(policy);
 
             configure(factory);
-
-            factory.init();
             
-            getServletContext().setAttribute(WebSocketServletFactory.class.getName(),factory);
+            ServletContext ctx = getServletContext();
+
+            factory.init(ctx);
+            
+            ctx.setAttribute(WebSocketServletFactory.class.getName(),factory);
         }
         catch (Exception x)
         {
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
index f88ad07..80046b2 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
@@ -22,10 +22,12 @@
 import java.util.Iterator;
 import java.util.ServiceLoader;
 
+import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
+import org.eclipse.jetty.websocket.api.annotations.WebSocket;
 import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
 
 /**
@@ -39,10 +41,10 @@
 
         public static WebSocketServletFactory create(WebSocketPolicy policy) throws ClassNotFoundException, InstantiationException, IllegalAccessException
         {
-            return load(policy).createFactory(policy);
+            return load().createFactory(policy);
         }
 
-        public static WebSocketServletFactory load(WebSocketPolicy policy) throws ClassNotFoundException, InstantiationException, IllegalAccessException
+        public static WebSocketServletFactory load() throws ClassNotFoundException, InstantiationException, IllegalAccessException
         {
             if (INSTANCE != null)
             {
@@ -64,7 +66,7 @@
                         .loadClass("org.eclipse.jetty.websocket.server.WebSocketServerFactory");
                 baseFactory = wssf.newInstance();
             }
-
+            
             INSTANCE = baseFactory;
             return INSTANCE;
         }
@@ -91,7 +93,7 @@
      */
     public WebSocketPolicy getPolicy();
 
-    public void init() throws Exception;
+    public void init(ServletContext servletContext) throws Exception;
 
     public boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response);
 
diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml
index d12891b..a92da17 100644
--- a/jetty-xml/pom.xml
+++ b/jetty-xml/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jetty-xml</artifactId>
@@ -15,30 +15,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <extensions>true</extensions>
-        <executions>
-          <execution>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <!--
-        Required for OSGI
-        -->
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
index c16f36f..f70b86c 100644
--- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
+++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlAppendable.java
@@ -52,7 +52,7 @@
     
     public XmlAppendable(Appendable out, int indent) throws IOException
     {
-        this(out,indent,"UTF-8");
+        this(out,indent,"utf-8");
     }
     
     public XmlAppendable(Appendable out, int indent, String encoding) throws IOException
diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java
index 29edf20..9851706 100644
--- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java
+++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java
@@ -35,7 +35,6 @@
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -51,12 +50,12 @@
 import org.eclipse.jetty.util.ArrayQueue;
 import org.eclipse.jetty.util.LazyList;
 import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.component.LifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.xml.XmlParser.Node;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
@@ -80,16 +79,12 @@
 public class XmlConfiguration
 {
     private static final Logger LOG = Log.getLogger(XmlConfiguration.class);
-
     private static final Class<?>[] __primitives =
             {Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE};
-
     private static final Class<?>[] __boxedPrimitives =
             {Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class};
-
     private static final Class<?>[] __supportedCollections =
-            {ArrayList.class, ArrayQueue.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class,};
-
+            {ArrayList.class, ArrayQueue.class, HashSet.class, Queue.class, List.class, Set.class, Collection.class};
     private static final Iterable<ConfigurationProcessorFactory> __factoryLoader = ServiceLoader.load(ConfigurationProcessorFactory.class);
     private static final XmlParser __parser = initParser();
     private static XmlParser initParser()
@@ -98,6 +93,7 @@
         URL config60 = Loader.getResource(XmlConfiguration.class, "org/eclipse/jetty/xml/configure_6_0.dtd");
         URL config76 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_7_6.dtd");
         URL config90 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_0.dtd");
+        URL config93 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_3.dtd");
         parser.redirectEntity("configure.dtd",config90);
         parser.redirectEntity("configure_1_0.dtd",config60);
         parser.redirectEntity("configure_1_1.dtd",config60);
@@ -106,13 +102,14 @@
         parser.redirectEntity("configure_6_0.dtd",config60);
         parser.redirectEntity("configure_7_6.dtd",config76);
         parser.redirectEntity("configure_9_0.dtd",config90);
+        parser.redirectEntity("configure_9_3.dtd",config93);
 
-        parser.redirectEntity("http://jetty.mortbay.org/configure.dtd",config90);
-        parser.redirectEntity("http://jetty.eclipse.org/configure.dtd",config90);
-        parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd",config90);
+        parser.redirectEntity("http://jetty.mortbay.org/configure.dtd",config93);
+        parser.redirectEntity("http://jetty.eclipse.org/configure.dtd",config93);
+        parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd",config93);
 
-        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN",config90);
-        parser.redirectEntity("-//Jetty//Configure//EN",config90);
+        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN",config93);
+        parser.redirectEntity("-//Jetty//Configure//EN",config93);
 
         return parser;
     }
@@ -150,7 +147,7 @@
      */
     public XmlConfiguration(String configuration) throws SAXException, IOException
     {
-        configuration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://eclipse.org/jetty/configure.dtd\">"
+        configuration = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://eclipse.org/jetty/configure.dtd\">"
                 + configuration;
         InputSource source = new InputSource(new StringReader(configuration));
         synchronized (__parser)
@@ -272,9 +269,11 @@
     public void initializeDefaults(Object object)
     {
     }
+    
 
     private static class JettyXmlConfiguration implements ConfigurationProcessor
     {
+        
         private String _url;
         XmlParser.Node _root;
         XmlConfiguration _configuration;
@@ -295,6 +294,9 @@
                 String loaders = (oClass.getClassLoader()==obj.getClass().getClassLoader())?"":"Object Class and type Class are from different loaders.";
                 throw new IllegalArgumentException("Object of class '"+obj.getClass().getCanonicalName()+"' is not of type '" + oClass.getCanonicalName()+"'. "+loaders+" in "+_url);
             }
+            String id=_root.getAttribute("id");
+            if (id!=null)
+                _configuration.getIdMap().put(id,obj);
             configure(obj,_root,0);
             return obj;
         }
@@ -346,11 +348,13 @@
                 }
                 catch (NoSuchMethodException x)
                 {
-                    throw new IllegalStateException("No suitable constructor on " + oClass, x);
+                    throw new IllegalStateException(String.format("No constructor %s(%s,%s) in %s",oClass,arguments,namedArgMap,_url));
                 }
             }
+            if (id!=null)
+                _configuration.getIdMap().put(id,obj);
+                
             _configuration.initializeDefaults(obj);
-
             configure(obj, _root, index);
             return obj;
         }
@@ -375,10 +379,6 @@
          */
         public void configure(Object obj, XmlParser.Node cfg, int i) throws Exception
         {
-            String id = cfg.getAttribute("id");
-            if (id != null)
-                _configuration.getIdMap().put(id,obj);
-
             // Object already constructed so skip any arguments
             for (; i < cfg.size(); i++)
             {
@@ -425,12 +425,21 @@
                         case "Array":
                             newArray(obj, node);
                             break;
+                        case "Map":
+                            newMap(obj,node);
+                            break;
                         case "Ref":
                             refObj(obj, node);
                             break;
                         case "Property":
                             propertyObj(node);
                             break;
+                        case "SystemProperty":
+                            systemPropertyObj(node);
+                            break;
+                        case "Env":
+                            envObj(node);
+                            break;
                         default:
                             throw new IllegalStateException("Unknown tag: " + tag + " in " + _url);
                     }
@@ -630,7 +639,7 @@
             Map<Object, Object> map = (Map<Object, Object>)obj;
 
             String name = node.getAttribute("name");
-            Object value = value(obj,node);
+            Object value = value(obj, node);
             map.put(name,value);
             if (LOG.isDebugEnabled())
                 LOG.debug("XML " + obj + ".put(" + name + "," + value + ")");
@@ -659,6 +668,8 @@
                 // try calling a getXxx method.
                 Method method = oClass.getMethod("get" + name.substring(0,1).toUpperCase(Locale.ENGLISH) + name.substring(1),(java.lang.Class[])null);
                 obj = method.invoke(obj,(java.lang.Object[])null);
+                if (id!=null)
+                    _configuration.getIdMap().put(id,obj);
                 configure(obj,node,0);
             }
             catch (NoSuchMethodException nsme)
@@ -674,8 +685,6 @@
                     throw nsme;
                 }
             }
-            if (id != null)
-                _configuration.getIdMap().put(id,obj);
             return obj;
         }
 
@@ -688,50 +697,37 @@
          */
         private Object call(Object obj, XmlParser.Node node) throws Exception
         {
-            String id = node.getAttribute("id");
-            Class<?> oClass = nodeClass(node);
-            if (oClass != null)
-                obj = null;
-            else if (obj != null)
-                oClass = obj.getClass();
-            if (oClass == null)
-                throw new IllegalArgumentException(node.toString());
+            AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Name","Class","Arg");
+            String id = aoeNode.getString("Id");
+            String name = aoeNode.getString("Name");
+            String clazz = aoeNode.getString("Class");
+            List<Object> args = aoeNode.getList("Arg");
             
-            int size = 0;
-            int argIndex = node.size();
-            for (int i = 0; i < node.size(); i++)
+            
+            Class<?> oClass;
+            if (clazz!=null)
             {
-                Object o = node.get(i);
-                if (o instanceof String)
-                    continue;
-                if (!((XmlParser.Node)o).getTag().equals("Arg"))
-                {
-                    argIndex = i;
-                    break;
-                }
-                size++;
+                // static call
+                oClass=Loader.loadClass(XmlConfiguration.class,clazz);
+                obj=null;
             }
-
-            Object[] arg = new Object[size];
-            for (int i = 0, j = 0; j < size; i++)
+            else if (obj!=null)
             {
-                Object o = node.get(i);
-                if (o instanceof String)
-                    continue;
-                arg[j++] = value(obj,(XmlParser.Node)o);
+                oClass = obj.getClass();
             }
-
-            String method = node.getAttribute("name");
+            else
+                throw new IllegalArgumentException(node.toString());
+           
             if (LOG.isDebugEnabled())
-                LOG.debug("XML call " + method);
+                LOG.debug("XML call " + name);
 
             try
             {
-                Object n= TypeUtil.call(oClass,method,obj,arg);
+                Object nobj= TypeUtil.call(oClass,name,obj,args.toArray(new Object[args.size()]));
                 if (id != null)
-                    _configuration.getIdMap().put(id,n);
-                configure(n,node,argIndex);
-                return n;
+                    _configuration.getIdMap().put(id,nobj);
+                configure(nobj,node,aoeNode.getNext());
+                return nobj;
             }
             catch (NoSuchMethodException e)
             {
@@ -751,59 +747,44 @@
          */
         private Object newObj(Object obj, XmlParser.Node node) throws Exception
         {
-            Class<?> oClass = nodeClass(node);
-            int argIndex = node.size();
-            
-            Map<String, Object> namedArgMap = new HashMap<>();
-            List<Object> arguments = new LinkedList<>();
-            XmlParser.Node child;
-
-            // Find the <Arg> elements
-            for (int i = 0; i < node.size(); i++)
-            {
-                Object o = node.get(i);
-                if (o instanceof String)
-                {
-                    // Skip raw String nodes
-                    continue;
-                }
-                
-                child = (XmlParser.Node)o;
-                if(child.getTag().equals("Arg"))
-                {
-                    String namedAttribute = child.getAttribute("name");
-                    Object value=value(obj,child);
-                    if (namedAttribute != null)
-                    {
-                        // named arguments
-                        namedArgMap.put(namedAttribute,value);
-                    }
-                    // raw arguments
-                    arguments.add(value);
-                } else {
-                    // The first non <Arg> child is the start of 
-                    // elements that configure the class, such as
-                    // <Set> and <Call> nodes
-                    argIndex = i;
-                    break;
-                }
-            }
+            AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Class","Arg");
+            String id = aoeNode.getString("Id");
+            String clazz = aoeNode.getString("Class");
+            List<XmlParser.Node> argNodes = aoeNode.getNodes("Arg");
 
             if (LOG.isDebugEnabled())
-                LOG.debug("XML new " + oClass);
+                LOG.debug("XML new " + clazz);
+            
+            Class<?> oClass = Loader.loadClass(XmlConfiguration.class,clazz);
+            
+            // Find the <Arg> elements
+            Map<String, Object> namedArgMap = new HashMap<>();
+            List<Object> arguments = new LinkedList<>();
+            for (XmlParser.Node child : argNodes)
+            {
+                String namedAttribute = child.getAttribute("name");
+                Object value=value(obj,child);
+                if (namedAttribute != null)
+                {
+                    // named arguments
+                    namedArgMap.put(namedAttribute,value);
+                }
+                // raw arguments
+                arguments.add(value);
+            }
 
-            Object n;
+            Object nobj;
             try
             {
                 if (namedArgMap.size() > 0)
                 {
                    LOG.debug("using named mapping");
-                   n = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
+                   nobj = TypeUtil.construct(oClass, arguments.toArray(), namedArgMap);
                 }
                 else
                 {
                     LOG.debug("using normal mapping");
-                    n = TypeUtil.construct(oClass, arguments.toArray());
+                    nobj = TypeUtil.construct(oClass, arguments.toArray());
                 }
             }
             catch (NoSuchMethodException e)
@@ -811,9 +792,12 @@
                 throw new IllegalStateException("No suitable constructor: " + node + " on " + obj);
             }
 
-            _configuration.initializeDefaults(n);
-            configure(n,node,argIndex);
-            return n;
+            if (id != null)
+                _configuration.getIdMap().put(id, nobj);
+            
+            _configuration.initializeDefaults(nobj);
+            configure(nobj,node,aoeNode.getNext());
+            return nobj;
         }
 
         /*
@@ -838,10 +822,13 @@
          */
         private Object newArray(Object obj, XmlParser.Node node) throws Exception
         {
+            AttrOrElementNode aoeNode=new AttrOrElementNode(obj,node,"Id","Type","Item");
+            String id = aoeNode.getString("Id");
+            String type = aoeNode.getString("Type");
+            List<XmlParser.Node> items = aoeNode.getNodes("Item");
+            
             // Get the type
             Class<?> aClass = java.lang.Object.class;
-            String type = node.getAttribute("type");
-            final String id = node.getAttribute("id");
             if (type != null)
             {
                 aClass = TypeUtil.fromName(type);
@@ -864,12 +851,11 @@
                     }
                 }
             }
-
+            
             Object al = null;
 
-            for (Object nodeObject : node)
+            for (XmlParser.Node item : items)
             {
-                XmlParser.Node item = (Node)nodeObject;
                 String nid = item.getAttribute("id");
                 Object v = value(obj,item);
                 al = LazyList.add(al,(v == null && aClass.isPrimitive())?0:v);
@@ -888,17 +874,16 @@
          */
         private Object newMap(Object obj, XmlParser.Node node) throws Exception
         {
-            String id = node.getAttribute("id");
+            AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Entry");
+            String id = aoeNode.getString("Id");
+            List<XmlParser.Node> entries = aoeNode.getNodes("Entry");
 
             Map<Object, Object> map = new HashMap<>();
             if (id != null)
-                _configuration.getIdMap().put(id,map);
+                _configuration.getIdMap().put(id, map);
 
-            for (Object o : node)
+            for (XmlParser.Node entry : entries)
             {
-                if (o instanceof String)
-                    continue;
-                XmlParser.Node entry = (XmlParser.Node)o;
                 if (!entry.getTag().equals("Entry"))
                     throw new IllegalStateException("Not an Entry");
 
@@ -945,20 +930,143 @@
          */
         private Object propertyObj(XmlParser.Node node) throws Exception
         {
-            String id = node.getAttribute("id");
-            String name = node.getAttribute("name");
-            String defaultValue = node.getAttribute("default");
-            Object prop;
-            Map<String,String> property_map=_configuration.getProperties();
-            if (property_map != null && property_map.containsKey(name))
-                prop = property_map.get(name);
-            else
-                prop = defaultValue;
+            AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
+            String id = aoeNode.getString("Id");
+            String name = aoeNode.getString("Name",true);
+            List<Object> deprecated = aoeNode.getList("Deprecated");
+            String dftValue = aoeNode.getString("Default");
+
+            // Look for a value
+            Map<String,String> properties = _configuration.getProperties();
+            String value = properties.get(name);
+            
+            // Look for a deprecated name value
+
+            String alternate=null;
+            if (!deprecated.isEmpty())
+            {
+                for (Object d : deprecated)
+                { 
+                    String v = properties.get(StringUtil.valueOf(d));
+                    if (v!=null)
+                    {
+                        if (value==null)
+                            LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
+                        else
+                            LOG.warn("Property '{}' is deprecated, value from '{}' used", d, name);
+                    }
+                    if (alternate==null)
+                        alternate=v;;
+                }
+            }
+
+            // use alternate from deprecated
+            if (value==null)
+                value=alternate;
+            
+            // use default value
+            if (value==null)
+                value=dftValue;
+
+            // Set value if ID set
             if (id != null)
-                _configuration.getIdMap().put(id,prop);
-            if (prop != null)
-                configure(prop,node,0);
-            return prop;
+                _configuration.getIdMap().put(id, value);
+            return value;
+        }
+
+        /*
+         * Get a SystemProperty.
+         *
+         * @param node
+         * @return
+         * @exception Exception
+         */
+        private Object systemPropertyObj(XmlParser.Node node) throws Exception
+        {
+            AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
+            String id = aoeNode.getString("Id");
+            String name = aoeNode.getString("Name",true);
+            List<Object> deprecated = aoeNode.getList("Deprecated");
+            String dftValue = aoeNode.getString("Default");
+
+            // Look for a value
+            String value = System.getProperty(name);
+            
+            // Look for a deprecated name value
+            String alternate=null;
+            if (!deprecated.isEmpty())
+            {
+                for (Object d : deprecated)
+                { 
+                    String v = System.getProperty(StringUtil.valueOf(d));
+                    if (v!=null)
+                    {
+                        if (value==null)
+                            LOG.warn("SystemProperty '{}' is deprecated, use '{}' instead", d, name);
+                        else
+                            LOG.warn("SystemProperty '{}' is deprecated, value from '{}' used", d, name);
+                    }
+                    if (alternate==null)
+                        alternate=v;;
+                }
+            }
+
+            // use alternate from deprecated
+            if (value==null)
+                value=alternate;
+            
+            // use default value
+            if (value==null)
+                value=dftValue;
+
+            // Set value if ID set
+            if (id != null)
+                _configuration.getIdMap().put(id, value);
+
+            return value;
+        }
+        
+        /*
+         * Get a Environment Property.
+         *
+         * @param node
+         * @return
+         * @exception Exception
+         */
+        private Object envObj(XmlParser.Node node) throws Exception
+        {
+            AttrOrElementNode aoeNode=new AttrOrElementNode(node,"Id","Name","Deprecated","Default");
+            String id = aoeNode.getString("Id");
+            String name = aoeNode.getString("Name",true);
+            List<Object> deprecated = aoeNode.getList("Deprecated");
+            String dftValue = aoeNode.getString("Default");
+
+            // Look for a value
+            String value = System.getenv(name);
+            
+            // Look for a deprecated name value
+            if (value==null && !deprecated.isEmpty())
+            {
+                for (Object d : deprecated)
+                {
+                    value = System.getenv(StringUtil.valueOf(d));
+                    if (value!=null)
+                    {
+                        LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
+                        break;
+                    }
+                }
+            }
+            
+            // use default value
+            if (value==null)
+                value=dftValue;
+
+            // Set value if ID set
+            if (id != null)
+                _configuration.getIdMap().put(id, value);
+
+            return value;
         }
 
         /*
@@ -1132,22 +1240,175 @@
             if ("Property".equals(tag))
                 return propertyObj(node);
             if ("SystemProperty".equals(tag))
-            {
-                String name = node.getAttribute("name");
-                String defaultValue = node.getAttribute("default");
-                return System.getProperty(name,defaultValue);
-            }
+                return systemPropertyObj(node);
             if ("Env".equals(tag))
-            {
-                String name = node.getAttribute("name");
-                String defaultValue = node.getAttribute("default");
-                String value=System.getenv(name);
-                return value==null?defaultValue:value;
-            }
+                return envObj(node);
 
             LOG.warn("Unknown value tag: " + node,new Throwable());
             return null;
         }
+        
+
+        private class AttrOrElementNode
+        {
+            final Object _obj;
+            final XmlParser.Node _node;
+            final Set<String> _elements = new HashSet<>();
+            final int _next;
+
+            AttrOrElementNode(XmlParser.Node node,String... elements )
+            {
+                this(null,node,elements);
+            }
+            
+            AttrOrElementNode(Object obj, XmlParser.Node node,String... elements )
+            {
+                _obj=obj;
+                _node=node;
+                for (String e:elements)
+                    _elements.add(e);
+                
+                int next=0;
+                for (Object o: _node)
+                {
+                    if (o instanceof String)
+                    {
+                        if (((String)o).trim().length()==0)
+                        {
+                            next++;
+                            continue;
+                        }
+                        break;
+                    }
+                    
+                    if (!(o instanceof XmlParser.Node))
+                        break;
+                    
+                    XmlParser.Node n = (XmlParser.Node)o;
+                    if (!_elements.contains(n.getTag()))
+                        break;
+                    
+                    next++;
+                }
+                _next=next;
+            }
+
+            public int getNext()
+            {
+                return _next;
+            }
+
+            public String getString(String elementName) throws Exception
+            {
+                return StringUtil.valueOf(get(elementName,false));
+            }
+            
+            public String getString(String elementName, boolean manditory) throws Exception
+            {
+                return StringUtil.valueOf(get(elementName,manditory));
+            }
+            
+            public Object get(String elementName, boolean manditory) throws Exception
+            {
+                String attrName=StringUtil.asciiToLowerCase(elementName);
+                String attr = _node.getAttribute(attrName);
+                Object value=attr;
+                
+                for (int i=0;i<_next;i++)
+                {
+                    Object o = _node.get(i);
+                    if (!(o instanceof XmlParser.Node))
+                        continue;
+                    XmlParser.Node n = (XmlParser.Node)o;
+                    if (elementName.equals(n.getTag()))
+                    {
+                        if (attr!=null)
+                            throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
+
+                        value=value(_obj,n);
+                        break;
+                    }
+                }
+                
+                if (manditory && value==null)
+                    throw new IllegalStateException("Must have attr '"+attrName+"' or element '"+elementName+"'");
+                
+                return value;
+            }
+
+            public List<Object> getList(String elementName) throws Exception
+            {
+                return getList(elementName,false);
+            }
+            
+            public List<Object> getList(String elementName, boolean manditory) throws Exception
+            {
+                String attrName=StringUtil.asciiToLowerCase(elementName);
+                final List<Object> values=new ArrayList<>();
+                
+                String attr = _node.getAttribute(attrName);
+                if (attr!=null)
+                    values.addAll(StringUtil.csvSplit(null,attr,0,attr.length()));
+
+
+                for (int i=0;i<_next;i++)
+                {
+                    Object o = _node.get(i);
+                    if (!(o instanceof XmlParser.Node))
+                        continue;
+                    XmlParser.Node n = (XmlParser.Node)o;
+                    
+                    if (elementName.equals(n.getTag()))
+                    {
+                        if (attr!=null)
+                            throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
+
+                        values.add(value(_obj,n));
+                    }
+                }
+                
+                if (manditory && values.isEmpty())
+                    throw new IllegalStateException("Must have attr '"+attrName+"' or element '"+elementName+"'");
+
+                return values;
+            }
+            
+            public List<XmlParser.Node> getNodes(String elementName) throws Exception
+            {
+                String attrName=StringUtil.asciiToLowerCase(elementName);
+                final List<XmlParser.Node> values=new ArrayList<>();
+                
+                String attr = _node.getAttribute(attrName);
+                if (attr!=null)
+                {
+                    for (String a : StringUtil.csvSplit(null,attr,0,attr.length()))
+                    {
+                        // create a fake node
+                        XmlParser.Node n = new XmlParser.Node(null,elementName,null);
+                        n.add(a);
+                        values.add(n);
+                    }
+                }
+
+                for (int i=0;i<_next;i++)
+                {
+                    Object o = _node.get(i);
+                    if (!(o instanceof XmlParser.Node))
+                        continue;
+                    XmlParser.Node n = (XmlParser.Node)o;
+                    
+                    if (elementName.equals(n.getTag()))
+                    {
+                        if (attr!=null)
+                            throw new IllegalStateException("Cannot have attr '"+attrName+"' and element '"+elementName+"'");
+
+                        values.add(n);
+                    }
+                }
+
+                return values;
+            }
+        }
     }
 
     /**
@@ -1177,7 +1438,6 @@
             {
                 try
                 {
-
                     Properties properties = null;
 
                     // Look for properties from start.jar
@@ -1199,14 +1459,9 @@
                     // If no start.config properties, use clean slate
                     if (properties == null)
                     {
-                        properties = new Properties();
                         // Add System Properties
-                        Enumeration<?> ensysprop = System.getProperties().propertyNames();
-                        while (ensysprop.hasMoreElements())
-                        {
-                            String name = (String)ensysprop.nextElement();
-                            properties.put(name,System.getProperty(name));
-                        }
+                        properties = new Properties();
+                        properties.putAll(System.getProperties());
                     }
 
                     // For all arguments, load properties
@@ -1228,7 +1483,7 @@
                     {
                         if (!args[i].toLowerCase(Locale.ENGLISH).endsWith(".properties") && (args[i].indexOf('=')<0))
                         {
-                            XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURL());
+                            XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURI().toURL());
                             if (last != null)
                                 configuration.getIdMap().putAll(last.getIdMap());
                             if (properties.size() > 0)
diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java
index 3866c14..ab70e15 100644
--- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java
+++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java
@@ -50,11 +50,9 @@
 /**
  * XML Parser wrapper. This class wraps any standard JAXP1.1 parser with convieniant error and
  * entity handlers and a mini dom-like document tree.
- * <P>
+ * <p>
  * By default, the parser is created as a validating parser only if xerces is present. This can be
  * configured by setting the "org.eclipse.jetty.xml.XmlParser.Validating" system property.
- *
- *
  */
 public class XmlParser
 {
@@ -82,9 +80,6 @@
     }
 
     /* ------------------------------------------------------------ */
-    /**
-     * Constructor.
-     */
     public XmlParser(boolean validating)
     {
         setValidating(validating);
@@ -139,10 +134,6 @@
     }
     
     /* ------------------------------------------------------------ */
-    /**
-     * @param name
-     * @param entity
-     */
     public synchronized void redirectEntity(String name, URL entity)
     {
         if (entity != null)
@@ -218,6 +209,10 @@
     /* ------------------------------------------------------------ */
     /**
      * Parse String URL.
+     * @param url the url to the xml to parse
+     * @return the root node of the xml
+     * @throws IOException if unable to load the xml
+     * @throws SAXException if unable to parse the xml
      */
     public synchronized Node parse(String url) throws IOException, SAXException
     {
@@ -229,6 +224,10 @@
     /* ------------------------------------------------------------ */
     /**
      * Parse File.
+     * @param file the file to the xml to parse 
+     * @return the root node of the xml
+     * @throws IOException if unable to load the xml
+     * @throws SAXException if unable to parse the xml
      */
     public synchronized Node parse(File file) throws IOException, SAXException
     {
@@ -240,6 +239,10 @@
     /* ------------------------------------------------------------ */
     /**
      * Parse InputStream.
+     * @param in the input stream of the xml to parse
+     * @return the root node of the xml
+     * @throws IOException if unable to load the xml
+     * @throws SAXException if unable to parse the xml
      */
     public synchronized Node parse(InputStream in) throws IOException, SAXException
     {
@@ -557,6 +560,7 @@
         /* ------------------------------------------------------------ */
         /**
          * Get an array of element attributes.
+         * @return the attributes
          */
         public Attribute[] getAttributes()
         {
@@ -566,7 +570,8 @@
         /* ------------------------------------------------------------ */
         /**
          * Get an element attribute.
-         *
+         * 
+         * @param name the name of the attribute 
          * @return attribute or null.
          */
         public String getAttribute(String name)
@@ -577,7 +582,9 @@
         /* ------------------------------------------------------------ */
         /**
          * Get an element attribute.
-         *
+         * 
+         * @param name the name of the element 
+         * @param dft the default value
          * @return attribute or null.
          */
         public String getAttribute(String name, String dft)
@@ -618,7 +625,7 @@
         /**
          * Get the first child node with the tag.
          *
-         * @param tag
+         * @param tag the name of the tag
          * @return Node or null.
          */
         public Node get(String tag)
@@ -702,6 +709,7 @@
          * Convert to a string.
          *
          * @param tag If false, only _content is shown.
+         * @return the string value
          */
         public synchronized String toString(boolean tag)
         {
@@ -715,6 +723,8 @@
          * Convert to a string.
          *
          * @param tag If false, only _content is shown.
+         * @param trim true to trim the content
+         * @return the trimmed content
          */
         public synchronized String toString(boolean tag, boolean trim)
         {
diff --git a/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd b/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd
index 542bc8c..7d6045b 100644
--- a/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd
+++ b/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd
@@ -274,15 +274,6 @@
 This element allows arbitrary properties to be retrieved by name.
 The name attribute specifies the property name and the optional
 default argument provides a default value.
-
-A Property element can contain a sequence of elements such as Set, Put, Call, etc.
-which act on the retrieved object:
-
- <Property name="Server">
-   <Call id="jdbcIdMgr" name="getAttribute">
-     <Arg>jdbcIdMgr</Arg>
-   </Call>
- </Property>
 -->
 <!ELEMENT Property (%CONFIG;)* >
 <!ATTLIST Property %NAMEATTR; %DEFAULTATTR; %IDATTR; >
diff --git a/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_3.dtd b/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_3.dtd
new file mode 100644
index 0000000..b4f7c1d
--- /dev/null
+++ b/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_3.dtd
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!--
+This is the document type descriptor for the
+org.eclipse.jetty.xml.XmlConfiguration class.  It allows a java object to be
+configured by with a sequence of Set, Put and Call elements.  These tags are
+mapped to methods on the object to be configured as follows:
+
+  <Set  name="Test">value</Set>              ==  obj.setTest("value");
+  <Put  name="Test">value</Put>              ==  obj.put("Test","value");
+  <Call name="test"><Arg>value</Arg></Call>  ==  obj.test("value");
+
+Values themselves may be configured objects that are created with the
+<New> tag or returned from a <Call> tag.
+
+Values are matched to arguments on a best effort approach, but types
+my be specified if a match is not achieved.
+-->
+
+<!ENTITY % CONFIG "Set|Get|Put|Call|New|Ref|Array|Map|Property">
+<!ENTITY % VALUE "#PCDATA|Get|Call|New|Ref|Array|Map|SystemProperty|Env|Property">
+
+<!ENTITY % TYPEATTR "type CDATA #IMPLIED " > <!-- String|Character|Short|Byte|Integer|Long|Boolean|Float|Double|char|short|byte|int|long|boolean|float|double|URL|InetAddress|InetAddrPort| #classname -->
+<!ENTITY % IMPLIEDCLASSATTR "class CDATA #IMPLIED" >
+<!ENTITY % CLASSATTR "class CDATA #REQUIRED" >
+<!ENTITY % NAMEATTR "name CDATA #REQUIRED" >
+<!ENTITY % IMPLIEDNAMEATTR "name CDATA #IMPLIED" >
+<!ENTITY % DEPRECATEDATTR "deprecated CDATA #IMPLIED" >
+<!ENTITY % DEFAULTATTR "default CDATA #IMPLIED" >
+<!ENTITY % IDATTR "id ID #IMPLIED" >
+<!ENTITY % ARGATTR "arg CDATA #IMPLIED" >
+<!ENTITY % ITEMATTR "item CDATA #IMPLIED" >
+<!ENTITY % REFATTR "refid CDATA #IMPLIED" >
+<!ENTITY % REQUIREDIDATTR "id ID #REQUIRED" >
+
+
+<!--
+Configure Element.
+This is the root element that specifies the class of object that
+can be configured:
+
+    <Configure class="com.acme.MyClass"> ... </Configure>
+-->
+<!ELEMENT Configure (Arg*,(%CONFIG;)*) >
+<!ATTLIST Configure %IMPLIEDCLASSATTR; %IDATTR; >
+
+
+<!--
+Set Element.
+This element maps to a call to a setter method or field on the current object.
+The name and optional type attributes are used to select the setter
+method. If the name given is xxx, then a setXxx method is used, or
+the xxx field is used of setXxx cannot be found.
+A Set element can contain value text and/or the value objects returned
+by other elements such as Call, New, SystemProperty, etc.
+If no value type is specified, then white
+space is trimmed out of the value. If it contains multiple value
+elements they are added as strings before being converted to any
+specified type.
+
+A Set with a class attribute is treated as a static set method invocation.
+-->
+<!ELEMENT Set (%VALUE;)* >
+<!ATTLIST Set %NAMEATTR; %TYPEATTR; %IMPLIEDCLASSATTR; >
+
+
+<!--
+Get Element.
+This element maps to a call to a getter method or field on the current object.
+The name attribute is used to select the get method.
+If the name given is xxx, then a getXxx method is used, or
+the xxx field is used if getXxx cannot be found.
+A Get element can contain other elements such as Set, Put, Call, etc.
+which act on the object returned by the get call.
+
+A Get with a class attribute is treated as a static get method or field.
+-->
+<!ELEMENT Get (%CONFIG;)* >
+<!ATTLIST Get %NAMEATTR; %IMPLIEDCLASSATTR; %IDATTR; >
+
+
+<!--
+Put Element.
+This element maps to a call to a put method on the current object,
+which must implement the Map interface. The name attribute is used
+as the put key and the optional type attribute can force the type
+of the value.
+
+A Put element can contain value text and/or value elements such as Call,
+New, SystemProperty, etc. If no value type is specified, then white
+space is trimmed out of the value. If it contains multiple value
+elements they are added as strings before being converted to any
+specified type.
+-->
+<!ELEMENT Put (%VALUE;)* >
+<!ATTLIST Put %NAMEATTR; %TYPEATTR; >
+
+
+<!--
+Id Element.
+This element is the equivalent of the id attribute.
+-->
+<!ELEMENT Id (%VALUE;)* >
+
+
+<!--
+Name element.
+This element is the equivalent of the name attribute.
+-->
+<!ELEMENT Name (%VALUE;)* >
+
+
+<!--
+Deprecated element.
+This element is the equivalent of the deprecated attribute.
+-->
+<!ELEMENT Deprecated (%VALUE;)* >
+
+
+<!--
+Default element.
+This element is the equivalent of the default attribute.
+-->
+<!ELEMENT Default (%VALUE;)* >
+
+
+<!--
+Class element.
+This element is the equivalent of the class attribute.
+-->
+<!ELEMENT Class (%VALUE;)* >
+
+
+<!--
+Type element.
+This element is the equivalent of the type attribute.
+-->
+<!ELEMENT Type (%VALUE;)* >
+
+
+<!--
+Call Element.
+This element maps to an arbitrary call to a method on the current object,
+The name attribute and Arg elements are used to select the method.
+
+A Call element can contain a sequence of Arg elements followed by
+a sequence of other elements such as Set, Put, Call, etc. which act on any object
+returned by the original call:
+
+ <Call id="o2" name="test">
+   <Arg>value1</Arg>
+   <Set name="Test">Value2</Set>
+ </Call>
+
+This is equivalent to:
+
+ Object o2 = o1.test("value1");
+ o2.setTest("value2");
+
+A Call with a class attribute is treated as a static call.
+-->
+<!ELEMENT Call (Id?,Name?,Class?,Arg*,(%CONFIG;)*) >
+<!ATTLIST Call %ARGATTR; %IMPLIEDNAMEATTR; %IMPLIEDCLASSATTR; %IDATTR; >
+
+
+<!--
+Arg Element.
+This element defines a positional or optional named argument for the
+Call and New elements. The optional type attribute can force the type
+of the value.
+
+An Arg element can contain value text and/or value elements such as Call,
+New, SystemProperty, etc. If no value type is specified, then white
+space is trimmed out of the value. If it contains multiple value
+elements they are added as strings before being converted to any
+specified type.
+-->
+<!ELEMENT Arg (%VALUE;)* >
+<!ATTLIST Arg %TYPEATTR; %IMPLIEDNAMEATTR; >
+
+
+<!--
+New Element.
+This element allows the creation of a new object as part of a
+value for elements such as Set, Put, Arg, etc. The class attribute
+determines the type of the new object and the contained Arg elements
+are used to select the constructor for the new object.
+
+A New element can contain a sequence of Arg elements followed by
+a sequence of elements such as Set, Put, Call, etc. elements
+which act on the new object:
+
+ <New id="o" class="com.acme.MyClass">
+   <Arg>value1</Arg>
+   <Set name="test">Value2</Set>
+ </New>
+
+This is equivalent to:
+
+ Object o = new com.acme.MyClass("value1");
+ o.setTest("Value2");
+-->
+<!ELEMENT New (Id?,Name?,Class?,Arg*,(%CONFIG;)*) >
+<!ATTLIST New %IDATTR; %IMPLIEDCLASSATTR; %ARGATTR; >
+
+
+<!--
+Ref Element.
+This element allows a previously created object to be referenced by id.  The
+attribute refid is used to specify the id of another object (the attribute id can
+also be used, but it's use is deprecated).
+A Ref element can contain a sequence of elements such as Set, Put, Call, etc.
+which act on the referenced object.
+
+ <Ref refid="myobject">
+   <Set name="Test">Value2</Set>
+ </New>
+-->
+<!ELEMENT Ref (%CONFIG;)* >
+<!ATTLIST Ref %IDATTR; %REFATTR;>
+
+
+<!--
+Array Element.
+This element allows the creation of a new array as part of a
+value of elements such as Set, Put, Arg, etc. The type attribute determines
+the type of the new array and the contained Item elements
+are used for each element of the array:
+
+ <Array type="java.lang.String">
+   <Item>value0</Item>
+   <Item><New class="java.lang.String"><Arg>value1</Arg></New></Item>
+ </Array>
+
+This is equivalent to:
+ String[] a = new String[] { "value0", new String("value1") };
+-->
+<!ELEMENT Array (Id?,Type?,Item*) >
+<!ATTLIST Array %IDATTR;%TYPEATTR;%ITEMATTR; >
+
+
+<!--
+Map Element.
+This element allows the creation of a new map as part of a
+value of elements such as Set, Put, Arg, etc. The type attribute determines
+the type of the new array and the contained Item elements
+are used for each element of the array:
+
+ <Map>
+   <Entry>
+     <Item>keyName</Item>
+     <Item><New class="java.lang.String"><Arg>value1</Arg></New></Item>
+   </Entry>
+ </Map>
+
+This is equivalent to:
+ Map m = new HashMap();
+ m.put("keyName", new String("value1"));
+-->
+<!ELEMENT Map (Id?,Entry*) >
+<!ATTLIST Map %IDATTR; >
+<!ELEMENT Entry (Item,Item) >
+
+
+<!--
+Item Element.
+This element defines an entry for the Array or Map Entry elements.
+The optional type attribute can force the type of the value.
+
+An Item element can contain value text and/or the value object of
+elements such as Call, New, SystemProperty, etc. If no value type
+is specified, then white space is trimmed out of the value.
+If it contains multiple value elements they are added as strings
+before being converted to any specified type.
+-->
+<!ELEMENT Item (%VALUE;)* >
+<!ATTLIST Item %TYPEATTR; %IDATTR; >
+
+
+<!--
+System Property Element.
+This element allows JVM System properties to be retrieved as
+part of the value of elements such as Set, Put, Arg, etc.
+The name attribute specifies the property name and the optional
+default argument provides a default value.
+
+ <SystemProperty name="Test" default="value" />
+
+This is equivalent to:
+
+ System.getProperty("Test","value");
+-->
+<!ELEMENT SystemProperty (Id?,Name?,Deprecated*,Default?) >
+<!ATTLIST SystemProperty %IMPLIEDNAMEATTR; %DEFAULTATTR; %DEPRECATEDATTR; %IDATTR; >
+
+
+<!--
+Environment variable Element.
+This element allows OS Environment variables to be retrieved as
+part of the value of elements such as Set, Put, Arg, etc.
+The name attribute specifies the env variable name and the optional
+default argument provides a default value.
+
+ <Env name="Test" default="value" />
+
+This is equivalent to:
+
+ String v=System.getEnv("Test");
+ if (v==null) v="value";
+
+-->
+<!ELEMENT Env (Id?,Name?,Deprecated*,Default?) >
+<!ATTLIST Env %IMPLIEDNAMEATTR; %DEFAULTATTR; %DEPRECATEDATTR; %IDATTR; >
+
+
+<!--
+Property Element.
+This element allows arbitrary properties to be retrieved by name.
+The name attribute specifies the property name and the optional
+default argument provides a default value.
+-->
+<!ELEMENT Property (Id?,Name?,Deprecated*,Default?) >
+<!ATTLIST Property %IMPLIEDNAMEATTR; %DEFAULTATTR; %DEPRECATEDATTR; %IDATTR; >
diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java
index d0fe3b9..2b5b3b0 100644
--- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java
+++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java
@@ -49,7 +49,7 @@
         out.closeTag();
 
         String expected = "" +
-                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                 "<test>\n" +
                 "  <tag/>\n" +
                 "  <tag name=\"attr value\" noval=\"\" quotes=\"&apos;&quot;\"/>\n" +
diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java
index e7e8ca4..18708db 100644
--- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java
+++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java
@@ -18,6 +18,18 @@
 
 package org.eclipse.jetty.xml;
 
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
@@ -25,20 +37,9 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import java.io.ByteArrayInputStream;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
 public class XmlConfigurationTest
 {
-    protected String _configure="org/eclipse/jetty/xml/configure.xml";
+    protected String[] _configure=new String [] {"org/eclipse/jetty/xml/configureWithAttr.xml","org/eclipse/jetty/xml/configureWithElements.xml"};
 
     private static final String STRING_ARRAY_XML = "<Array type=\"String\"><Item type=\"String\">String1</Item><Item type=\"String\">String2</Item></Array>";
     private static final String INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
@@ -54,161 +55,169 @@
     @Test
     public void testPassedObject() throws Exception
     {
-        TestConfiguration.VALUE=77;
-        Map<String,String> properties = new HashMap<>();
-        properties.put("whatever", "xxx");
+        for (String configure : _configure)
+        {
+            Map<String,String> properties = new HashMap<>();
+            properties.put("whatever", "xxx");
+            TestConfiguration.VALUE=77;
+            URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
+            XmlConfiguration configuration = new XmlConfiguration(url);
+            TestConfiguration tc = new TestConfiguration("tc");
+            configuration.getProperties().putAll(properties);
+            configuration.configure(tc);
 
-        URL url = XmlConfigurationTest.class.getClassLoader().getResource(_configure);
-        XmlConfiguration configuration = new XmlConfiguration(url);
-        TestConfiguration tc = new TestConfiguration("tc");
-        configuration.getProperties().putAll(properties);
-        configuration.configure(tc);
+            assertEquals("Set String","SetValue",tc.testObject);
+            assertEquals("Set Type",2,tc.testInt);
 
-        assertEquals("Set String","SetValue",tc.testObject);
-        assertEquals("Set Type",2,tc.testInt);
+            assertEquals(18080, tc.propValue);
 
-        assertEquals(18080, tc.propValue);
+            assertEquals("Put","PutValue",tc.get("Test"));
+            assertEquals("Put dft","2",tc.get("TestDft"));
+            assertEquals("Put type",2,tc.get("TestInt"));
 
-        assertEquals("Put","PutValue",tc.get("Test"));
-        assertEquals("Put dft","2",tc.get("TestDft"));
-        assertEquals("Put type",2,tc.get("TestInt"));
+            assertEquals("Trim","PutValue",tc.get("Trim"));
+            assertEquals("Null",null,tc.get("Null"));
+            assertEquals("NullTrim",null,tc.get("NullTrim"));
 
-        assertEquals("Trim","PutValue",tc.get("Trim"));
-        assertEquals("Null",null,tc.get("Null"));
-        assertEquals("NullTrim",null,tc.get("NullTrim"));
+            assertEquals("ObjectTrim",1.2345,tc.get("ObjectTrim"));
+            assertEquals("Objects","-1String",tc.get("Objects"));
+            assertEquals( "ObjectsTrim", "-1String",tc.get("ObjectsTrim"));
+            assertEquals( "String", "\n    PutValue\n  ",tc.get("String"));
+            assertEquals( "NullString", "",tc.get("NullString"));
+            assertEquals( "WhiteSpace", "\n  ",tc.get("WhiteSpace"));
+            assertEquals( "ObjectString", "\n    1.2345\n  ",tc.get("ObjectString"));
+            assertEquals( "ObjectsString", "-1String",tc.get("ObjectsString"));
+            assertEquals( "ObjectsWhiteString", "-1\n  String",tc.get("ObjectsWhiteString"));
 
-        assertEquals("ObjectTrim",1.2345,tc.get("ObjectTrim"));
-        assertEquals("Objects","-1String",tc.get("Objects"));
-        assertEquals( "ObjectsTrim", "-1String",tc.get("ObjectsTrim"));
-        assertEquals( "String", "\n    PutValue\n  ",tc.get("String"));
-        assertEquals( "NullString", "",tc.get("NullString"));
-        assertEquals( "WhiteSpace", "\n  ",tc.get("WhiteSpace"));
-        assertEquals( "ObjectString", "\n    1.2345\n  ",tc.get("ObjectString"));
-        assertEquals( "ObjectsString", "-1String",tc.get("ObjectsString"));
-        assertEquals( "ObjectsWhiteString", "-1\n  String",tc.get("ObjectsWhiteString"));
+            assertEquals( "SystemProperty", System.getProperty("user.dir")+"/stuff",tc.get("SystemProperty"));
+            assertEquals( "Env", System.getenv("HOME"),tc.get("Env"));
 
-        assertEquals( "SystemProperty", System.getProperty("user.dir")+"/stuff",tc.get("SystemProperty"));
-        assertEquals( "Env", System.getenv("HOME"),tc.get("Env"));
-
-        assertEquals( "Property", "xxx", tc.get("Property"));
+            assertEquals( "Property", "xxx", tc.get("Property"));
 
 
-        assertEquals( "Called", "Yes",tc.get("Called"));
+            assertEquals( "Called", "Yes",tc.get("Called"));
 
-        assertTrue(TestConfiguration.called);
+            assertTrue(TestConfiguration.called);
 
-        assertEquals("oa[0]","Blah",tc.oa[0]);
-        assertEquals("oa[1]","1.2.3.4:5678",tc.oa[1]);
-        assertEquals("oa[2]",1.2345,tc.oa[2]);
-        assertEquals("oa[3]",null,tc.oa[3]);
+            assertEquals("oa[0]","Blah",tc.oa[0]);
+            assertEquals("oa[1]","1.2.3.4:5678",tc.oa[1]);
+            assertEquals("oa[2]",1.2345,tc.oa[2]);
+            assertEquals("oa[3]",null,tc.oa[3]);
 
-        assertEquals("ia[0]",1,tc.ia[0]);
-        assertEquals("ia[1]",2,tc.ia[1]);
-        assertEquals("ia[2]",3,tc.ia[2]);
-        assertEquals("ia[3]",0,tc.ia[3]);
+            assertEquals("ia[0]",1,tc.ia[0]);
+            assertEquals("ia[1]",2,tc.ia[1]);
+            assertEquals("ia[2]",3,tc.ia[2]);
+            assertEquals("ia[3]",0,tc.ia[3]);
 
-        TestConfiguration tc2=tc.nested;
-        assertTrue(tc2!=null);
-        assertEquals( "Called(bool)",true,tc2.get("Arg"));
+            TestConfiguration tc2=tc.nested;
+            assertTrue(tc2!=null);
+            assertEquals( "Called(bool)",true,tc2.get("Arg"));
 
-        assertEquals("nested config",null,tc.get("Arg"));
-        assertEquals("nested config",true,tc2.get("Arg"));
+            assertEquals("nested config",null,tc.get("Arg"));
+            assertEquals("nested config",true,tc2.get("Arg"));
 
-        assertEquals("nested config","Call1",tc2.testObject);
-        assertEquals("nested config",4,tc2.testInt);
-        assertEquals( "nested call", "http://www.eclipse.com/",tc2.url.toString());
+            assertEquals("nested config","Call1",tc2.testObject);
+            assertEquals("nested config",4,tc2.testInt);
+            assertEquals( "nested call", "http://www.eclipse.com/",tc2.url.toString());
 
-        assertEquals("static to field",tc.testField1,77);
-        assertEquals("field to field",tc.testField2,2);
-        assertEquals("literal to static",TestConfiguration.VALUE,42);
+            assertEquals("static to field",tc.testField1,77);
+            assertEquals("field to field",tc.testField2,2);
+            assertEquals("literal to static",TestConfiguration.VALUE,42);
+            
+            assertEquals("value0",((Map<String,String>)configuration.getIdMap().get("map")).get("key0"));
+            assertEquals("value1",((Map<String,String>)configuration.getIdMap().get("map")).get("key1"));
+        }
     }
 
     @Test
     public void testNewObject() throws Exception
     {
-        TestConfiguration.VALUE=71;
-        Map<String,String> properties = new HashMap<>();
-        properties.put("whatever", "xxx");
-
-        URL url = XmlConfigurationTest.class.getClassLoader().getResource(_configure);
-        final AtomicInteger count = new AtomicInteger(0);
-        XmlConfiguration configuration = new XmlConfiguration(url)
+        for (String configure : _configure)
         {
-            @Override
-            public void initializeDefaults(Object object)
+            TestConfiguration.VALUE=71;
+            Map<String,String> properties = new HashMap<>();
+            properties.put("whatever", "xxx");
+            
+            URL url = XmlConfigurationTest.class.getClassLoader().getResource(configure);
+            final AtomicInteger count = new AtomicInteger(0);
+            XmlConfiguration configuration = new XmlConfiguration(url)
             {
-                if (object instanceof TestConfiguration)
+                @Override
+                public void initializeDefaults(Object object)
                 {
-                    count.incrementAndGet();
-                    ((TestConfiguration)object).setNested(null);
-                    ((TestConfiguration)object).setTestString("NEW DEFAULT");
+                    if (object instanceof TestConfiguration)
+                    {
+                        count.incrementAndGet();
+                        ((TestConfiguration)object).setNested(null);
+                        ((TestConfiguration)object).setTestString("NEW DEFAULT");
+                    }
                 }
-            }
-        };
-        configuration.getProperties().putAll(properties);
-        TestConfiguration tc = (TestConfiguration)configuration.configure();
+            };
+            configuration.getProperties().putAll(properties);
+            TestConfiguration tc = (TestConfiguration)configuration.configure();
 
-        assertEquals(3,count.get());
-        
-        assertEquals("NEW DEFAULT",tc.getTestString());
-        assertEquals("nested",tc.getNested().getTestString());
-        assertEquals("NEW DEFAULT",tc.getNested().getNested().getTestString());
-        
-        assertEquals("Set String","SetValue",tc.testObject);
-        assertEquals("Set Type",2,tc.testInt);
+            assertEquals(3,count.get());
 
-        assertEquals(18080, tc.propValue);
+            assertEquals("NEW DEFAULT",tc.getTestString());
+            assertEquals("nested",tc.getNested().getTestString());
+            assertEquals("NEW DEFAULT",tc.getNested().getNested().getTestString());
 
-        assertEquals("Put","PutValue",tc.get("Test"));
-        assertEquals("Put dft","2",tc.get("TestDft"));
-        assertEquals("Put type",2,tc.get("TestInt"));
+            assertEquals("Set String","SetValue",tc.testObject);
+            assertEquals("Set Type",2,tc.testInt);
 
-        assertEquals("Trim","PutValue",tc.get("Trim"));
-        assertEquals("Null",null,tc.get("Null"));
-        assertEquals("NullTrim",null,tc.get("NullTrim"));
+            assertEquals(18080, tc.propValue);
 
-        assertEquals("ObjectTrim",1.2345,tc.get("ObjectTrim"));
-        assertEquals("Objects","-1String",tc.get("Objects"));
-        assertEquals( "ObjectsTrim", "-1String",tc.get("ObjectsTrim"));
-        assertEquals( "String", "\n    PutValue\n  ",tc.get("String"));
-        assertEquals( "NullString", "",tc.get("NullString"));
-        assertEquals( "WhiteSpace", "\n  ",tc.get("WhiteSpace"));
-        assertEquals( "ObjectString", "\n    1.2345\n  ",tc.get("ObjectString"));
-        assertEquals( "ObjectsString", "-1String",tc.get("ObjectsString"));
-        assertEquals( "ObjectsWhiteString", "-1\n  String",tc.get("ObjectsWhiteString"));
+            assertEquals("Put","PutValue",tc.get("Test"));
+            assertEquals("Put dft","2",tc.get("TestDft"));
+            assertEquals("Put type",2,tc.get("TestInt"));
 
-        assertEquals( "SystemProperty", System.getProperty("user.dir")+"/stuff",tc.get("SystemProperty"));
-        assertEquals( "Property", "xxx", tc.get("Property"));
+            assertEquals("Trim","PutValue",tc.get("Trim"));
+            assertEquals("Null",null,tc.get("Null"));
+            assertEquals("NullTrim",null,tc.get("NullTrim"));
+
+            assertEquals("ObjectTrim",1.2345,tc.get("ObjectTrim"));
+            assertEquals("Objects","-1String",tc.get("Objects"));
+            assertEquals( "ObjectsTrim", "-1String",tc.get("ObjectsTrim"));
+            assertEquals( "String", "\n    PutValue\n  ",tc.get("String"));
+            assertEquals( "NullString", "",tc.get("NullString"));
+            assertEquals( "WhiteSpace", "\n  ",tc.get("WhiteSpace"));
+            assertEquals( "ObjectString", "\n    1.2345\n  ",tc.get("ObjectString"));
+            assertEquals( "ObjectsString", "-1String",tc.get("ObjectsString"));
+            assertEquals( "ObjectsWhiteString", "-1\n  String",tc.get("ObjectsWhiteString"));
+
+            assertEquals( "SystemProperty", System.getProperty("user.dir")+"/stuff",tc.get("SystemProperty"));
+            assertEquals( "Property", "xxx", tc.get("Property"));
 
 
-        assertEquals( "Called", "Yes",tc.get("Called"));
+            assertEquals( "Called", "Yes",tc.get("Called"));
 
-        assertTrue(TestConfiguration.called);
+            assertTrue(TestConfiguration.called);
 
-        assertEquals("oa[0]","Blah",tc.oa[0]);
-        assertEquals("oa[1]","1.2.3.4:5678",tc.oa[1]);
-        assertEquals("oa[2]",1.2345,tc.oa[2]);
-        assertEquals("oa[3]",null,tc.oa[3]);
+            assertEquals("oa[0]","Blah",tc.oa[0]);
+            assertEquals("oa[1]","1.2.3.4:5678",tc.oa[1]);
+            assertEquals("oa[2]",1.2345,tc.oa[2]);
+            assertEquals("oa[3]",null,tc.oa[3]);
 
-        assertEquals("ia[0]",1,tc.ia[0]);
-        assertEquals("ia[1]",2,tc.ia[1]);
-        assertEquals("ia[2]",3,tc.ia[2]);
-        assertEquals("ia[3]",0,tc.ia[3]);
+            assertEquals("ia[0]",1,tc.ia[0]);
+            assertEquals("ia[1]",2,tc.ia[1]);
+            assertEquals("ia[2]",3,tc.ia[2]);
+            assertEquals("ia[3]",0,tc.ia[3]);
 
-        TestConfiguration tc2=tc.nested;
-        assertTrue(tc2!=null);
-        assertEquals( "Called(bool)",true,tc2.get("Arg"));
+            TestConfiguration tc2=tc.nested;
+            assertTrue(tc2!=null);
+            assertEquals( "Called(bool)",true,tc2.get("Arg"));
 
-        assertEquals("nested config",null,tc.get("Arg"));
-        assertEquals("nested config",true,tc2.get("Arg"));
+            assertEquals("nested config",null,tc.get("Arg"));
+            assertEquals("nested config",true,tc2.get("Arg"));
 
-        assertEquals("nested config","Call1",tc2.testObject);
-        assertEquals("nested config",4,tc2.testInt);
-        assertEquals( "nested call", "http://www.eclipse.com/",tc2.url.toString());
+            assertEquals("nested config","Call1",tc2.testObject);
+            assertEquals("nested config",4,tc2.testInt);
+            assertEquals( "nested call", "http://www.eclipse.com/",tc2.url.toString());
 
-        assertEquals("static to field",71,tc.testField1);
-        assertEquals("field to field",2,tc.testField2);
-        assertEquals("literal to static",42,TestConfiguration.VALUE);
+            assertEquals("static to field",71,tc.testField1);
+            assertEquals("field to field",2,tc.testField2);
+            assertEquals("literal to static",42,TestConfiguration.VALUE);
+        }
     }
 
 
@@ -219,8 +228,8 @@
             new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"Test\">SetValue</Set><Set name=\"Test\" type=\"int\">2</Set></Configure>");
         TestConfiguration tc = new TestConfiguration();
         configuration.configure(tc);
-        assertEquals("Set String 3","SetValue",tc.testObject);
-        assertEquals("Set Type 3",2,tc.testInt);
+        assertEquals("Set String 3", "SetValue", tc.testObject);
+        assertEquals("Set Type 3", 2, tc.testInt);
     }
 
     @Test
@@ -233,7 +242,7 @@
         assertThat("tc.getList() returns null as it's not configured yet",tc.getList(),is(nullValue()));
         xmlConfiguration.configure(tc);
         assertThat("tc.getList() returns not null",tc.getList(),not(nullValue()));
-        assertThat("tc.getList() has two entries as specified in the xml",tc.getList().size(),is(2));
+        assertThat("tc.getList() has two entries as specified in the xml", tc.getList().size(), is(2));
     }
 
     @Test
@@ -248,7 +257,7 @@
         assertThat("tc.getList() returns null as it's not configured yet",tc.getList(),is(nullValue()));
         xmlConfiguration.configure(tc);
         assertThat("tc.getList() returns not null",tc.getList(),not(nullValue()));
-        assertThat("tc.getList() has two entries as specified in the xml",tc.getList().size(),is(2));
+        assertThat("tc.getList() has two entries as specified in the xml", tc.getList().size(), is(2));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -270,7 +279,7 @@
         assertThat("tc.getList() returns null as it's not configured yet",tc.getSet(),is(nullValue()));
         xmlConfiguration.configure(tc);
         assertThat("tc.getList() returns not null",tc.getSet(),not(nullValue()));
-        assertThat("tc.getList() has two entries as specified in the xml",tc.getSet().size(),is(2));
+        assertThat("tc.getList() has two entries as specified in the xml", tc.getSet().size(), is(2));
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -290,7 +299,7 @@
         TestConfiguration tc = new TestConfiguration();
         assertThat("tc.getList() returns null as it's not configured yet",tc.getList(),is(nullValue()));
         xmlConfiguration.configure(tc);
-        assertThat("tc.getList() has two entries as specified in the xml",tc.getList().size(),is(2));
+        assertThat("tc.getList() has two entries as specified in the xml", tc.getList().size(), is(2));
     }
 
     @Test
@@ -301,7 +310,7 @@
         TestConfiguration tc = new TestConfiguration();
         assertThat("tc.getList() returns null as it's not configured yet",tc.getList(),is(nullValue()));
         xmlConfiguration.configure(tc);
-        assertThat("tc.getList() has two entries as specified in the xml",tc.getList().size(),is(2));
+        assertThat("tc.getList() has two entries as specified in the xml", tc.getList().size(), is(2));
     }
 
     @Test(expected=NoSuchMethodException.class)
@@ -310,7 +319,7 @@
         XmlConfiguration xmlConfiguration = new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"LinkedList\">"
                 + INT_ARRAY_XML + "</Set></Configure>");
         TestConfiguration tc = new TestConfiguration();
-        assertThat("tc.getSet() returns null as it's not configured yet",tc.getList(),is(nullValue()));
+        assertThat("tc.getSet() returns null as it's not configured yet", tc.getList(), is(nullValue()));
         xmlConfiguration.configure(tc);
     }
 
@@ -320,9 +329,9 @@
         XmlConfiguration xmlConfiguration = new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"ArrayList\">"
                 + INT_ARRAY_XML + "</Set></Configure>");
         TestConfiguration tc = new TestConfiguration();
-        assertThat("tc.getSet() returns null as it's not configured yet",tc.getList(),is(nullValue()));
+        assertThat("tc.getSet() returns null as it's not configured yet", tc.getList(), is(nullValue()));
         xmlConfiguration.configure(tc);
-        assertThat("tc.getSet() has two entries as specified in the xml",tc.getList().size(),is(2));
+        assertThat("tc.getSet() has two entries as specified in the xml", tc.getList().size(), is(2));
     }
 
     @Test
@@ -331,9 +340,9 @@
         XmlConfiguration xmlConfiguration = new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"Set\">"
                 + STRING_ARRAY_XML + "</Set></Configure>");
         TestConfiguration tc = new TestConfiguration();
-        assertThat("tc.getSet() returns null as it's not configured yet",tc.getSet(),is(nullValue()));
+        assertThat("tc.getSet() returns null as it's not configured yet", tc.getSet(), is(nullValue()));
         xmlConfiguration.configure(tc);
-        assertThat("tc.getSet() has two entries as specified in the xml",tc.getSet().size(),is(2));
+        assertThat("tc.getSet() has two entries as specified in the xml", tc.getSet().size(), is(2));
     }
 
     @Test
@@ -342,9 +351,9 @@
         XmlConfiguration xmlConfiguration = new XmlConfiguration("<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\"><Set name=\"Set\">"
                 + INT_ARRAY_XML + "</Set></Configure>");
         TestConfiguration tc = new TestConfiguration();
-        assertThat("tc.getSet() returns null as it's not configured yet",tc.getSet(),is(nullValue()));
+        assertThat("tc.getSet() returns null as it's not configured yet", tc.getSet(), is(nullValue()));
         xmlConfiguration.configure(tc);
-        assertThat("tc.getSet() has two entries as specified in the xml",tc.getSet().size(),is(2));
+        assertThat("tc.getSet() has two entries as specified in the xml", tc.getSet().size(), is(2));
     }
 
     @Test
@@ -590,7 +599,7 @@
         Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
         Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
         Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
-        Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
+        Assert.assertEquals("nested third parameter not wired correctly", "arg3", atc.getNested().getThird());
     }
 
     @Test
@@ -618,7 +627,7 @@
         Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
         Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
         Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
-        Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
+        Assert.assertEquals("nested third parameter not wired correctly", "arg3", atc.getNested().getThird());
     }
 
     @Test
@@ -645,7 +654,7 @@
         Assert.assertEquals("third parameter not wired correctly","arg3", atc.getThird());
         Assert.assertEquals("nested first parameter not wired correctly","arg1", atc.getNested().getFirst());
         Assert.assertEquals("nested second parameter not wired correctly","arg2", atc.getNested().getSecond());
-        Assert.assertEquals("nested third parameter not wired correctly","arg3", atc.getNested().getThird());
+        Assert.assertEquals("nested third parameter not wired correctly", "arg3", atc.getNested().getThird());
     }
 
     public static class NativeHolder
@@ -779,4 +788,117 @@
             
         }
     }
+
+    @Test
+    public void testWithMultiplePropertyNamesWithNoPropertyThenDefaultIsChosen() throws Exception
+    {
+        // No properties
+        String defolt = "baz";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\"><Property name=\"wibble\" deprecated=\"foo,bar\" default=\"" + defolt + "\"/></Set>  " +
+                "</Configure>");
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(defolt, config.getFirst());
+    }
+
+    @Test
+    public void testWithMultiplePropertyNamesWithFirstPropertyThenFirstIsChosen() throws Exception
+    {
+        String name = "foo";
+        String value = "foo";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\"><Property name=\"" + name + "\" deprecated=\"other,bar\" default=\"baz\"/></Set>  " +
+                "</Configure>");
+        xmlConfiguration.getProperties().put(name, value);
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(value, config.getFirst());
+    }
+
+    @Test
+    public void testWithMultiplePropertyNamesWithSecondPropertyThenSecondIsChosen() throws Exception
+    {
+        String name = "bar";
+        String value = "bar";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\"><Property name=\"foo\" deprecated=\"" + name + "\" default=\"baz\"/></Set>  " +
+                "</Configure>");
+        xmlConfiguration.getProperties().put(name, value);
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(value, config.getFirst());
+    }
+
+    @Test
+    public void testWithMultiplePropertyNamesWithDeprecatedThenThirdIsChosen() throws Exception
+    {
+        String name = "bar";
+        String value = "bar";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\"><Property name=\"foo\" deprecated=\"other," + name + "\" default=\"baz\"/></Set>  " +
+                "</Configure>");
+        xmlConfiguration.getProperties().put(name, value);
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(value, config.getFirst());
+    }
+
+    @Test
+    public void testWithMultiplePropertyNameElementsWithDeprecatedThenThirdIsChosen() throws Exception
+    {
+        String name = "bar";
+        String value = "bar";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\">" +
+                "  <Property>  " +
+                "    <Name>foo</Name>" +
+                "    <Deprecated>foo</Deprecated>" +
+                "    <Deprecated>"+name+"</Deprecated>" +
+                "    <Default>baz</Default>" +
+                "  </Property>  " +
+                "  </Set>  " +
+                "</Configure>");
+        xmlConfiguration.getProperties().put(name, value);
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(value, config.getFirst());
+    }
+
+    @Test
+    public void testPropertyNotFoundWithPropertyInDefaultValue() throws Exception
+    {
+        String name = "bar";
+        String value = "bar";
+        String defaultValue = "_<Property name=\"bar\"/>_<Property name=\"bar\"/>_";
+        String expectedValue = "_" + value + "_" + value + "_";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\">" +
+                "    <Property>" +
+                "      <Name>not_found</Name>" +
+                "      <Default>" + defaultValue + "</Default>" +
+                "    </Property>" +
+                "  </Set>  " +
+                "</Configure>");
+        xmlConfiguration.getProperties().put(name, value);
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(expectedValue, config.getFirst());
+    }
+
+    @Test
+    public void testPropertyNotFoundWithPropertyInDefaultValueNotFoundWithDefault() throws Exception
+    {
+        String value = "bar";
+        XmlConfiguration xmlConfiguration = new XmlConfiguration("" +
+                "<Configure class=\"org.eclipse.jetty.xml.DefaultTestConfiguration\">" +
+                "  <Set name=\"first\">" +
+                "    <Property name=\"not_found\">" +
+                "      <Default><Property name=\"also_not_found\" default=\"" + value + "\"/></Default>" +
+                "    </Property>" +
+                "  </Set>  " +
+                "</Configure>");
+        DefaultTestConfiguration config = (DefaultTestConfiguration)xmlConfiguration.configure();
+        assertEquals(value, config.getFirst());
+    }
 }
diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java
index a15a34e..bc536b3 100644
--- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java
+++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java
@@ -31,24 +31,12 @@
     {
         XmlParser parser = new XmlParser();
 
-        URL configURL = XmlConfiguration.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure_6_0.dtd");
+        URL configURL = XmlConfiguration.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure_9_3.dtd");
         parser.redirectEntity("configure.dtd", configURL);
-        parser.redirectEntity("configure_1_3.dtd", configURL);
         parser.redirectEntity("http://jetty.eclipse.org/configure.dtd", configURL);
         parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", configURL);
-        parser.redirectEntity("http://jetty.eclipse.org/configure_1_3.dtd", configURL);
-        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.3//EN", configURL);
-        parser.redirectEntity("configure_1_2.dtd", configURL);
-        parser.redirectEntity("http://jetty.eclipse.org/configure_1_2.dtd", configURL);
-        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.2//EN", configURL);
-        parser.redirectEntity("configure_1_1.dtd", configURL);
-        parser.redirectEntity("http://jetty.eclipse.org/configure_1_1.dtd", configURL);
-        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.1//EN", configURL);
-        parser.redirectEntity("configure_1_0.dtd", configURL);
-        parser.redirectEntity("http://jetty.eclipse.org/configure_1_0.dtd", configURL);
-        parser.redirectEntity("-//Mort Bay Consulting//DTD Configure 1.0//EN", configURL);
 
-        URL url = XmlParserTest.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure.xml");
+        URL url = XmlParserTest.class.getClassLoader().getResource("org/eclipse/jetty/xml/configureWithAttr.xml");
         XmlParser.Node testDoc = parser.parse(url.toString());
         String testDocStr = testDoc.toString().trim();
 
diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml
deleted file mode 100644
index 46c8571..0000000
--- a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configure.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
-
-<Configure class="org.eclipse.jetty.xml.TestConfiguration">
-  <Arg name="name">name</Arg>
-
-  <Set name="Test">SetValue</Set>
-  <Set name="Test" type="int"><Property name="does.not.exist" default="2"/></Set>
-  
-  <Set name="PropertyTest"><Property name="anIntegerNoActualPropDefined" default="18080"/></Set>
-
-  <Put name="Test">PutValue</Put>
-  <Put name="TestDft">2</Put>
-  <Put name="TestInt" type="int">2</Put>
-
-  <Put name="Trim">
-    PutValue
-  </Put>
-
-  <Put name="Null"></Put>
-
-  <Put name="NullTrim">
-  </Put>
-
-  <Put name="Object"><New class="java.lang.Double">
-      <Arg>1.2345</Arg>
-  </New></Put>
- 
-  <Put name="ObjectTrim">
-    <New class="java.lang.Double">
-      <Arg>1.2345</Arg>
-    </New>
-  </Put>
-
-  <Put name="Objects"><New class="java.lang.Integer">
-      <Arg>-1</Arg>
-  </New><New class="java.lang.String">
-      <Arg>String</Arg>
-  </New></Put>
-
-
-  <Put name="ObjectsTrim">
-    <New class="java.lang.Integer">
-      <Arg>-1</Arg>
-  </New><New class="java.lang.String">
-      <Arg>String</Arg>
-  </New></Put>
-
-
-  <Put name="String" type="String">
-    PutValue
-  </Put>
-
-  <Put name="NullString" type="String"></Put>
-
-  <Put name="WhiteSpace" type="String">
-  </Put>
-
-  <Put name="ObjectString" type="String">
-    <New class="java.lang.Double">
-      <Arg>1.2345</Arg>
-    </New>
-  </Put>
-
-  <Put name="ObjectsString" type="String"><New class="java.lang.Integer">
-      <Arg>-1</Arg>
-  </New><New class="java.lang.String">
-      <Arg>String</Arg>
-  </New></Put>
-
-
-  <Put name="ObjectsWhiteString">
-    <New class="java.lang.Integer">
-      <Arg>-1</Arg>
-  </New>
-  <New class="java.lang.String">
-      <Arg>String</Arg>
-  </New></Put>
-
-  <Put name="SystemProperty" ><SystemProperty name="user.dir"/>/stuff</Put>
-  <Put name="Property"><Property name="whatever" default="xxx"/></Put>
-  <Put name="SomethingElse"><SystemProperty name="floople" default="xxx"/></Put>
-  <Put name="Boolean" type="Boolean">True</Put>
-  <Put name="Float" type="Float">2.3</Put>
-  <Put name="Env"><Env name="HOME"/></Put>
-
-  <Set name="nested">
-    <New class="org.eclipse.jetty.xml.TestConfiguration">
-      <Set name="testString">nested</Set>
-      <Set name="nested">
-        <New class="org.eclipse.jetty.xml.TestConfiguration">
-        </New>
-      </Set>
-    </New>
-  </Set>
-
-  <Call name="call">
-  </Call>
-
-  <Call name="call">
-    <Arg type="boolean">false</Arg>
-  </Call>
-
-  <Call name="call">
-    <Arg type="boolean">true</Arg>
-    <Put name="nested">put</Put>
-    <Set name="Test">Call1</Set>
-    <Set name="Test" type="int">4</Set>
-    <Call name="call">
-      <Arg type="URL">http://www.eclipse.com/</Arg>
-      <Arg type="boolean">false</Arg>
-    </Call>
-  </Call>
-
-  <Get name="String">
-     <Call name="toString"/>
-  </Get>
-
-  <Call name="callStatic" class="org.eclipse.jetty.xml.TestConfiguration"/>
-
-  <Call name="call">
-    <Arg><Array type="java.lang.Object">
-      <Item>Blah</Item>
-      <Item type="String">1.2.3.4:5678</Item>
-      <Item><New class="java.lang.Double"><Arg>1.2345</Arg></New></Item>
-      <Item></Item>
-    </Array></Arg>
-  </Call>
-
-  <Call name="call">
-    <Arg><Array type="int">
-      <Item type="int">1</Item>
-      <Item type="int">2</Item>
-      <Item type="int">3</Item>
-      <Item></Item>
-    </Array></Arg>
-  </Call>
-
-  <Set name="testField1"><Get class="org.eclipse.jetty.xml.TestConfiguration" name="VALUE"/></Set>
-  <Set name="testField2"><Get name="testInt"/></Set>
-  <Set name="VALUE" type="int">42</Set>
-
-</Configure>
-
-
diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithAttr.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithAttr.xml
new file mode 100644
index 0000000..8377987
--- /dev/null
+++ b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithAttr.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure class="org.eclipse.jetty.xml.TestConfiguration">
+  <Arg name="name">name</Arg>
+
+  <Set name="Test">SetValue</Set>
+  <Set name="Test" type="int"><Property name="does.not.exist" default="2"/></Set>
+  
+  <Set name="PropertyTest"><Property name="anIntegerNoActualPropDefined" default="18080"/></Set>
+
+  <Put name="Test">PutValue</Put>
+  <Put name="TestDft">2</Put>
+  <Put name="TestInt" type="int">2</Put>
+
+  <Put name="Trim">
+    PutValue
+  </Put>
+
+  <Put name="Null"></Put>
+
+  <Put name="NullTrim">
+  </Put>
+
+  <Put name="Object"><New class="java.lang.Double" arg="1.2345"/></Put>
+ 
+  <Put name="ObjectTrim">
+    <New class="java.lang.Double" arg="1.2345"/>
+  </Put>
+
+  <Put name="Objects"><New class="java.lang.Integer" arg="-1"/><New class="java.lang.String" arg="String"/></Put>
+
+  <Put name="ObjectsTrim">
+    <New class="java.lang.Integer" arg="-1">
+  </New><New class="java.lang.String" arg="String">
+  </New></Put>
+
+  <Put name="String" type="String">
+    PutValue
+  </Put>
+
+  <Put name="NullString" type="String"></Put>
+
+  <Put name="WhiteSpace" type="String">
+  </Put>
+
+  <Put name="ObjectString" type="String">
+    <New class="java.lang.Double">
+      <Arg>1.2345</Arg>
+    </New>
+  </Put>
+
+  <Put name="ObjectsString" type="String"><New class="java.lang.Integer" arg="-1"/><New class="java.lang.String" arg="String"/></Put>
+
+  <Put name="ObjectsWhiteString">
+    <New class="java.lang.Integer" arg="-1">
+  </New>
+  <New class="java.lang.String" arg="String">
+  </New></Put>
+
+  <Put name="SystemProperty" ><SystemProperty name="user.dir"/>/stuff</Put>
+  <Put name="Property"><Property name="whatever" default="xxx"/></Put>
+  <Put name="SomethingElse"><SystemProperty name="floople" default="xxx"/></Put>
+  <Put name="Boolean" type="Boolean">True</Put>
+  <Put name="Float" type="Float">2.3</Put>
+  <Put name="Env"><Env name="HOME"/></Put>
+
+  <Set name="nested">
+    <New class="org.eclipse.jetty.xml.TestConfiguration">
+      <Set name="testString">nested</Set>
+      <Set name="nested">
+        <New class="org.eclipse.jetty.xml.TestConfiguration">
+        </New>
+      </Set>
+    </New>
+  </Set>
+
+  <Call name="call">
+  </Call>
+
+  <Call name="call">
+    <Arg type="boolean">false</Arg>
+  </Call>
+
+  <Call name="call">
+    <Arg type="boolean">true</Arg>
+    <Put name="nested">put</Put>
+    <Set name="Test">Call1</Set>
+    <Set name="Test" type="int">4</Set>
+    <Call name="call">
+      <Arg type="URL">http://www.eclipse.com/</Arg>
+      <Arg type="boolean">false</Arg>
+    </Call>
+  </Call>
+
+  <Get name="String">
+     <Call name="toString"/>
+  </Get>
+
+  <Call name="callStatic" class="org.eclipse.jetty.xml.TestConfiguration"/>
+
+  <Call name="call">
+    <Arg><Array type="java.lang.Object">
+      <Item>Blah</Item>
+      <Item type="String">1.2.3.4:5678</Item>
+      <Item><New class="java.lang.Double"><Arg>1.2345</Arg></New></Item>
+      <Item></Item>
+    </Array></Arg>
+  </Call>
+
+  <Call name="call">
+    <Arg><Array type="int">
+      <Item type="int">1</Item>
+      <Item type="int">2</Item>
+      <Item type="int">3</Item>
+      <Item></Item>
+    </Array></Arg>
+  </Call>
+
+  <Set name="testField1"><Get class="org.eclipse.jetty.xml.TestConfiguration" name="VALUE"/></Set>
+  <Set name="testField2"><Get name="testInt"/></Set>
+  <Set name="VALUE" type="int">42</Set>
+
+  <Map id="map">
+    <Entry>
+      <Item id="key0">key0</Item>
+      <Item id="value0">value0</Item>
+    </Entry>
+    <Entry>
+      <Item id="key1">key1</Item>
+      <Item id="value1">value1</Item>
+    </Entry>
+  </Map>
+
+</Configure>
+
+
diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithElements.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithElements.xml
new file mode 100644
index 0000000..e4fa88d
--- /dev/null
+++ b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/configureWithElements.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
+
+<Configure class="org.eclipse.jetty.xml.TestConfiguration">
+  <Arg name="name">name</Arg>
+
+  <Set name="Test">SetValue</Set>
+  <Set name="Test" type="int"><Property><Name>does.not.exist</Name><Default>2</Default></Property></Set>
+  
+  <Set name="PropertyTest"><Property><Name>anIntegerNoActualPropDefined</Name><Default>18080</Default></Property></Set>
+
+  <Put name="Test">PutValue</Put>
+  <Put name="TestDft">2</Put>
+  <Put name="TestInt" type="int">2</Put>
+
+  <Put name="Trim">
+    PutValue
+  </Put>
+
+  <Put name="Null"></Put>
+
+  <Put name="NullTrim">
+  </Put>
+
+  <Put name="Object"><New class="java.lang.Double">
+      <Arg>1.2345</Arg>
+  </New></Put>
+ 
+  <Put name="ObjectTrim">
+    <New class="java.lang.Double">
+      <Arg>1.2345</Arg>
+    </New>
+  </Put>
+
+  <Put name="Objects"><New class="java.lang.Integer">
+      <Arg>-1</Arg>
+  </New><New class="java.lang.String">
+      <Arg>String</Arg>
+  </New></Put>
+
+
+  <Put name="ObjectsTrim">
+    <New class="java.lang.Integer">
+      <Arg>-1</Arg>
+  </New><New class="java.lang.String">
+      <Arg>String</Arg>
+  </New></Put>
+
+
+  <Put name="String" type="String">
+    PutValue
+  </Put>
+
+  <Put name="NullString" type="String"></Put>
+
+  <Put name="WhiteSpace" type="String">
+  </Put>
+
+  <Put name="ObjectString" type="String">
+    <New class="java.lang.Double">
+      <Arg>1.2345</Arg>
+    </New>
+  </Put>
+
+  <Put name="ObjectsString" type="String"><New class="java.lang.Integer">
+      <Arg>-1</Arg>
+  </New><New>
+      <Class>java.lang.String</Class>
+      <Arg>String</Arg>
+  </New></Put>
+
+
+  <Put name="ObjectsWhiteString">
+    <New>
+      <Class>java.lang.Integer</Class>
+      <Arg>-1</Arg>
+  </New>
+  <New>
+      <Class>java.lang.String</Class>
+      <Arg>String</Arg>
+  </New></Put>
+
+  <Put name="SystemProperty" ><SystemProperty><Name>user.dir</Name></SystemProperty>/stuff</Put>
+  <Put name="Property"><Property><Name>whatever</Name><Default>xxx</Default></Property></Put>
+  <Put name="SomethingElse"><SystemProperty name="floople" default="xxx"/></Put>
+  <Put name="Boolean" type="Boolean">True</Put>
+  <Put name="Float" type="Float">2.3</Put>
+  <Put name="Env"><Env name="HOME"/></Put>
+
+  <Set name="nested">
+    <New>
+      <Class>org.eclipse.jetty.xml.TestConfiguration</Class>
+      <Set name="testString">nested</Set>
+      <Set name="nested">
+        <New class="org.eclipse.jetty.xml.TestConfiguration">
+        </New>
+      </Set>
+    </New>
+  </Set>
+
+  <Call name="call">
+  </Call>
+
+  <Call name="call">
+    <Arg type="boolean">false</Arg>
+  </Call>
+
+  <Call name="call">
+    <Arg type="boolean">true</Arg>
+    <Put name="nested">put</Put>
+    <Set name="Test">Call1</Set>
+    <Set name="Test" type="int">4</Set>
+    <Call>
+      <Name>call</Name>
+      <Arg type="URL">http://www.eclipse.com/</Arg>
+      <Arg type="boolean">false</Arg>
+    </Call>
+  </Call>
+
+  <Get name="String">
+     <Call name="toString"/>
+  </Get>
+
+  <Call>
+    <Name>callStatic</Name>
+    <Class>org.eclipse.jetty.xml.TestConfiguration</Class>
+  </Call>
+
+  <Call>
+    <Name>call</Name>
+    <Arg><Array type="java.lang.Object">
+      <Item>Blah</Item>
+      <Item type="String">1.2.3.4:5678</Item>
+      <Item><New class="java.lang.Double"><Arg>1.2345</Arg></New></Item>
+      <Item></Item>
+    </Array></Arg>
+  </Call>
+
+  <Call>
+    <Name>call</Name>
+    <Arg><Array>
+      <Id>array</Id>
+      <Type>int</Type>
+      <Item type="int">1</Item>
+      <Item type="int">2</Item>
+      <Item type="int">3</Item>
+      <Item></Item>
+    </Array></Arg>
+  </Call>
+
+  <Set name="testField1"><Get class="org.eclipse.jetty.xml.TestConfiguration" name="VALUE"/></Set>
+  <Set name="testField2"><Get name="testInt"/></Set>
+  <Set name="VALUE" type="int">42</Set>
+  
+  <Map>
+    <Id>map</Id>
+    <Entry>
+      <Item id="key0">key0</Item>
+      <Item id="value0">value0</Item>
+    </Entry>
+    <Entry>
+      <Item id="key1">key1</Item>
+      <Item id="value1">value1</Item>
+    </Entry>
+  </Map>
+
+</Configure>
+
+
diff --git a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml
index e1c1808..c8e20ce 100644
--- a/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml
+++ b/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure_9_3.dtd">
 <Configure class="java.lang.Object">
 </Configure>
diff --git a/pom.xml b/pom.xml
index fc6bcf0..eb942f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,23 +3,22 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-parent</artifactId>
-    <version>23</version>
+    <version>25</version>
   </parent>
   <artifactId>jetty-project</artifactId>
-  <version>9.2.15-SNAPSHOT</version>
+  <version>9.3.7-SNAPSHOT</version>
   <name>Jetty :: Project</name>
   <url>http://www.eclipse.org/jetty</url>
   <packaging>pom</packaging>
   <properties>
     <jetty.url>http://www.eclipse.org/jetty</jetty.url>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <build-support-version>1.1</build-support-version>
+    <build-support-version>1.4</build-support-version>
     <slf4j-version>1.6.6</slf4j-version>
     <jetty-test-policy-version>1.2</jetty-test-policy-version>
-    <npn.api.version>1.1.1.v20141010</npn.api.version>
     <alpn.api.version>1.1.2.v20150522</alpn.api.version>
+    <jsp.version>8.0.27</jsp.version>
     <!-- default values are unsupported, but required to be defined for reactor sanity reasons -->
-    <npn.version>undefined</npn.version>
     <alpn.version>undefined</alpn.version>
   </properties>
   <scm>
@@ -33,9 +32,12 @@
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.3</version>
         <configuration>
-          <source>1.7</source>
-          <target>1.7</target>
+          <source>1.8</source>
+          <target>1.8</target>
+          <testSource>1.8</testSource>
+          <testTarget>1.8</testTarget>
           <verbose>false</verbose>
         </configuration>
       </plugin>
@@ -135,8 +137,8 @@
                   <message>[ERROR] OLD MAVEN [${maven.version}] in use, Jetty ${project.version} requires Maven 3.0.0 or newer</message>
                 </requireMavenVersion>
                 <requireJavaVersion>
-                  <version>[1.7.0-40,)</version>
-                  <message>[ERROR] OLD JDK [${java.version}] in use. Jetty ${project.version} requires JDK 1.7.0_40 or newer</message>
+                  <version>[1.8.0,)</version>
+                  <message>[ERROR] OLD JDK [${java.version}] in use. Jetty ${project.version} requires JDK 1.8.0 or newer</message>
                 </requireJavaVersion>
                 <versionTxtRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.VersionTxtRule" />
                 <versionOsgiRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.RequireOsgiCompatibleVersionRule" />
@@ -187,7 +189,7 @@
           </execution>
         </executions>
         <configuration>
-          <targetJdk>1.7</targetJdk>
+          <targetJdk>1.8</targetJdk>
           <rulesets>
             <ruleset>jetty/pmd_logging_ruleset.xml</ruleset>
           </rulesets>
@@ -224,6 +226,8 @@
             <exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/DefaultPolicyLoader.java</exclude>
             <exclude>jetty-policy/src/main/java/org/eclipse/jetty/policy/loader/PolicyFileScanner.java</exclude>
             <exclude>jetty-ant/**</exclude>
+            <exclude>jetty-infinispan/**</exclude>
+            <exclude>tests/test-sessions/test-infinispan-sessions/**</exclude>
           </excludes>
         </configuration>
         <executions>
@@ -236,6 +240,28 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>manifest</goal>
+            </goals>
+           </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+         <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+         </archive>
+        </configuration>
+     </plugin>
+
     </plugins>
     <pluginManagement>
       <plugins>
@@ -268,7 +294,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
-          <version>2.17</version>
+          <version>2.18.1</version>
           <configuration>
             <argLine>-showversion -Xmx1g -Xms1g -XX:+PrintGCDetails</argLine>
             <failIfNoTests>false</failIfNoTests>
@@ -292,15 +318,20 @@
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
           <configuration>
+            <supportedProjectTypes>
+              <supportedProjectType>jar</supportedProjectType>
+              <supportedProjectType>maven-plugin</supportedProjectType>
+            </supportedProjectTypes>
             <instructions>
               <Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName>
-              <Bundle-RequiredExecutionEnvironment>JavaSE-1.7</Bundle-RequiredExecutionEnvironment>
+              <Bundle-Description>Jetty module for ${project.name}</Bundle-Description>
+              <Bundle-RequiredExecutionEnvironment>JavaSE-1.8</Bundle-RequiredExecutionEnvironment>
               <Bundle-DocURL>${jetty.url}</Bundle-DocURL>
               <Bundle-Vendor>Eclipse Jetty Project</Bundle-Vendor>
               <Bundle-Classpath>.</Bundle-Classpath>
               <Export-Package>${bundle-symbolic-name}.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
               <Bundle-Copyright>Copyright (c) 2008-2016 Mort Bay Consulting Pty. Ltd.</Bundle-Copyright>
-              <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
+              <Import-Package>javax.servlet*;version="[2.6.0,3.2)",javax.transaction*;version="[1.1,1.3)",org.eclipse.jetty*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",*</Import-Package>
             </instructions>
           </configuration>
         </plugin>
@@ -342,10 +373,10 @@
             <detectJavaApiLink>true</detectJavaApiLink>
             <excludePackageNames>com.acme.*;org.slf4j.*;org.mortbay.*</excludePackageNames>
             <links>
-              <link>http://docs.oracle.com/javase/7/docs/api/</link>
+              <link>http://docs.oracle.com/javase/8/docs/api/</link>
               <link>http://docs.oracle.com/javaee/7/api/</link>
+              <link>http://junit.org/javadoc/latest/</link>
               <link>http://download.eclipse.org/jetty/stable-9/apidocs/</link>
-              <link>http://junit.sourceforge.net/javadoc/</link>
             </links>
             <tags>
               <tag>
@@ -353,6 +384,56 @@
                 <placement>X</placement>
                 <head />
               </tag>
+              <tag>
+                <name>phase</name>
+                <placement>t</placement>
+                <head>Phase:</head>
+              </tag>
+              <tag>
+                <name>goal</name>
+                <placement>t</placement>
+                <head>Goal:</head>
+              </tag>
+              <tag>
+                <name>description</name>
+                <placement>a</placement>
+                <head>Description:</head>
+              </tag>
+              <tag>
+                <name>parameter</name>
+                <placement>f</placement>
+                <head>Parameter:</head>
+              </tag>
+              <tag>
+                <name>required</name>
+                <placement>f</placement>
+                <head>Required:</head>
+              </tag>
+              <tag>
+                <name>readonly</name>
+                <placement>f</placement>
+                <head>Read-Only:</head>
+              </tag>
+              <tag>
+                <name>execute</name>
+                <placement>X</placement>
+                <head />
+              </tag>
+              <tag>
+                <name>requiresDependencyResolution</name>
+                <placement>X</placement>
+                <head />
+              </tag>
+              <tag>
+                <name>requiresProject</name>
+                <placement>X</placement>
+                <head />
+              </tag>
+              <tag>
+                <name>threadSafe</name>
+                <placement>X</placement>
+                <head />
+              </tag>
             </tags>
             <header>
               <![CDATA[
@@ -373,7 +454,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-pmd-plugin</artifactId>
-          <version>2.7.1</version>
+          <version>3.4</version>
         </plugin>
       </plugins>
     </pluginManagement>
@@ -414,34 +495,23 @@
       </plugin>
     </plugins>
   </reporting>
-  <repositories>
-    <repository>
-      <snapshots>
-        <enabled>true</enabled>
-      </snapshots>
-      <id>sonatype-snapshots</id>
-      <name>Sonatype Jetty Snapshots</name>
-      <url>https://oss.sonatype.org/content/groups/jetty</url>
-    </repository>
-  </repositories>
   <modules>
     <module>jetty-ant</module>
     <module>jetty-util</module>
     <module>jetty-jmx</module>
     <module>jetty-io</module>
     <module>jetty-http</module>
+    <module>jetty-http2</module>
     <module>jetty-continuation</module>
     <module>jetty-server</module>
     <module>jetty-xml</module>
     <module>jetty-security</module>
     <module>jetty-servlet</module>
     <module>jetty-webapp</module>
-    <module>jetty-spdy</module>
     <module>jetty-fcgi</module>
     <module>jetty-websocket</module>
     <module>jetty-servlets</module>
     <module>jetty-util-ajax</module>
-    <module>jetty-jsp</module>
     <module>apache-jsp</module>
     <module>apache-jstl</module>
     <module>jetty-maven-plugin</module>
@@ -459,6 +529,8 @@
     <module>jetty-jaspi</module>
     <module>jetty-rewrite</module>
     <module>jetty-nosql</module>
+    <module>jetty-infinispan</module>
+    <module>jetty-gcloud</module>
     <module>tests</module>
     <module>examples</module>
     <module>jetty-quickstart</module>
@@ -516,106 +588,29 @@
       </dependency>
 
       <dependency>
-        <groupId>javax.servlet.jsp</groupId>
-        <artifactId>javax.servlet.jsp-api</artifactId>
-        <version>2.3.1</version>
-      </dependency>
-
-      <dependency>
-        <groupId>org.glassfish.web</groupId>
-        <artifactId>javax.servlet.jsp</artifactId>
-        <version>2.3.2</version>
-      </dependency>
-
-      <dependency>
-        <groupId>org.eclipse.jetty.toolchain</groupId>
-        <artifactId>jetty-jsp-jdt</artifactId>
-        <version>2.3.3</version>
-      </dependency>
-
-
-      <dependency>
-        <groupId>javax.el</groupId>
-        <artifactId>javax.el-api</artifactId>
-        <version>3.0.0</version>
-      </dependency>
-
-      <dependency>
-        <groupId>org.glassfish</groupId>
-        <artifactId>javax.el</artifactId>
-        <version>3.0.0</version>
-      </dependency>
-
-      <dependency>
         <groupId>org.mortbay.jasper</groupId>
         <artifactId>apache-jsp</artifactId>
-        <version>8.0.9.M3</version>
+        <version>${jsp.version}</version>
       </dependency>
 
       <dependency>
-        <groupId>org.eclipse.jetty.orbit</groupId>
-        <artifactId>org.eclipse.jdt.core</artifactId>
-       <version>3.8.2.v20130121</version>
-       <exclusions>
-          <exclusion>
-            <groupId>org.eclipse.jetty.orbit</groupId>
-            <artifactId>javax.servlet</artifactId>
-         </exclusion>
-        </exclusions>
+        <groupId>org.eclipse.jdt.core.compiler</groupId>
+        <artifactId>ecj</artifactId>
+       <version>4.4.2</version>
       </dependency>
 
     <!-- JSTL Impl -->
     <dependency>
-       <groupId>org.glassfish.web</groupId>
-       <artifactId>javax.servlet.jsp.jstl</artifactId>
-       <version>1.2.2</version>
-      <exclusions>
-        <exclusion>
-          <groupId>javax.servlet.jsp.jstl</groupId>
-          <artifactId>jstl-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>javax.servlet</groupId>
-          <artifactId>servlet-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>javax.servlet.jsp</groupId>
-          <artifactId>jsp-api</artifactId>
-        </exclusion>
-        <exclusion>
-          <groupId>javax.el</groupId>
-          <artifactId>el-api</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-
-    <dependency>
       <groupId>org.apache.taglibs</groupId>
       <artifactId>taglibs-standard-impl</artifactId>
-      <version>1.2.1</version>
+      <version>1.2.5</version>
     </dependency>
 
      <!-- JSTL API -->
       <dependency>
-        <groupId>org.eclipse.jetty.orbit</groupId>
-        <artifactId>javax.servlet.jsp.jstl</artifactId>
-        <version>1.2.0.v201105211821</version>
-        <exclusions>
-          <exclusion>
-            <groupId>org.eclipse.jetty.orbit</groupId>
-            <artifactId>javax.servlet</artifactId>
-          </exclusion>
-          <exclusion>
-            <groupId>org.eclipse.jetty.orbit</groupId>
-            <artifactId>javax.servlet.jsp</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-
-      <dependency>
         <groupId>org.apache.taglibs</groupId>
         <artifactId>taglibs-standard-spec</artifactId>
-        <version>1.2.1</version>
+        <version>1.2.5</version>
       </dependency>
 
 
@@ -649,7 +644,7 @@
       <dependency>
         <groupId>org.eclipse.jetty.toolchain</groupId>
         <artifactId>jetty-test-helper</artifactId>
-        <version>3.0</version>
+        <version>3.1</version>
       </dependency>
       <dependency>
         <groupId>org.eclipse.jetty.toolchain</groupId>
@@ -710,10 +705,50 @@
    -->
   <profiles>
     <profile>
+      <id>config</id>
+      <activation>
+        <file>
+          <exists>src/main/config</exists>
+        </file>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>package</phase>
+                <goals>
+                  <goal>single</goal>
+                </goals>
+                <configuration>
+                  <descriptorRefs>
+                    <descriptorRef>config</descriptorRef>
+                  </descriptorRefs>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <profile>
       <id>eclipse-release</id>
       <modules>
         <module>aggregates/jetty-all</module>
       </modules>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <configuration>
+              <source>1.8</source>
+              <target>1.8</target>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
     </profile>
     <profile>
       <id>ci</id>
@@ -785,40 +820,17 @@
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-javadoc-plugin</artifactId>
-            <configuration>
-              <excludePackageNames>com.acme</excludePackageNames>
-              <links>
-                <link>http://docs.oracle.com/javase/7/docs/api/</link>
-                <link>http://docs.oracle.com/javaee/6/api</link>
-                <link>http://junit.sourceforge.net/javadoc/</link>
-              </links>
-              <tags>
-                <tag>
-                  <name>org.apache.xbean.XBean</name>
-                  <placement>X</placement>
-                  <head />
-                </tag>
-              </tags>
-              <header>
-                <![CDATA[
-                    <script type="text/javascript">
-                      var _gaq = _gaq || [];
-                      _gaq.push(['_setAccount', 'UA-1149868-7']);
-                      _gaq.push(['_trackPageview']);
-                      (function() {
-                        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-                        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-                        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-                      })();
-                   </script>
-                ]]>
-              </header>
-            </configuration>
           </plugin>
         </plugins>
       </build>
     </profile>
     <profile>
+      <id>compact3</id>
+      <modules>
+        <module>aggregates/jetty-all-compact3</module>
+      </modules>
+    </profile>
+    <profile>
       <id>api-change</id>
       <build>
         <plugins>
@@ -844,175 +856,6 @@
       </build>
     </profile>
     <profile>
-      <id>7u40</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_40</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.6.v20130911</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u45</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_45</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.6.v20130911</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u51</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_51</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.6.v20130911</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u55</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_55</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.8.v20141013</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u60</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_60</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.8.v20141013</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u65</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_65</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.8.v20141013</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u67</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_67</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.8.v20141013</npn.version>
-        <alpn.version>7.1.0.v20141016</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u71</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_71</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.9.v20141016</npn.version>
-        <alpn.version>7.1.2.v20141202</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u72</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_72</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.9.v20141016</npn.version>
-        <alpn.version>7.1.2.v20141202</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u75</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_75</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.10.v20150130</npn.version>
-        <alpn.version>7.1.3.v20150130</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u76</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_76</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.10.v20150130</npn.version>
-        <alpn.version>7.1.3.v20150130</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u79</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_79</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.10.v20150130</npn.version>
-        <alpn.version>7.1.3.v20150130</alpn.version>
-      </properties>
-    </profile>
-    <profile>
-      <id>7u80</id>
-      <activation>
-        <property>
-          <name>java.version</name>
-          <value>1.7.0_80</value>
-        </property>
-      </activation>
-      <properties>
-        <npn.version>1.1.11.v20150415</npn.version>
-        <alpn.version>7.1.3.v20150130</alpn.version>
-      </properties>
-    </profile>
-    <profile>
       <id>8u00</id>
       <activation>
         <property>
diff --git a/tests/pom.xml b/tests/pom.xml
index 8e3233d..3899822 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty</groupId>
     <artifactId>jetty-project</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>org.eclipse.jetty.tests</groupId>
@@ -32,6 +32,13 @@
   <build>
     <plugins>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <additionalparam>-Xdoclint:none</additionalparam>
+        </configuration>
+      </plugin>
+      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <configuration>
@@ -49,5 +56,6 @@
     <module>test-integration</module>
     <module>test-quickstart</module>
     <module>test-jmx</module>
+    <module>test-http-client-transport</module>
   </modules>
 </project>
diff --git a/tests/test-cdi/cdi-client/pom.xml b/tests/test-cdi/cdi-client/pom.xml
deleted file mode 100644
index 3419c3b..0000000
--- a/tests/test-cdi/cdi-client/pom.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-// ========================================================================
-// Copyright (c) Webtide LLC
-// 
-// 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.apache.org/licenses/LICENSE-2.0.txt
-//
-// You may elect to redistribute this code under either of these licenses. 
-// ========================================================================
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.tests</groupId>
-    <artifactId>test-cdi-parent</artifactId>
-    <version>9.2.4-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>cdi-client</artifactId>
-  <packaging>jar</packaging>
-  <name>Jetty Tests :: CDI :: Clients</name>
-  <url>http://www.eclipse.org/jetty</url>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <bundle-symbolic-name>${project.groupId}.cdi.clients</bundle-symbolic-name>
-  </properties>
-  <dependencies>
-  </dependencies>
-</project>
diff --git a/tests/test-cdi/cdi-webapp-it/pom.xml b/tests/test-cdi/cdi-webapp-it/pom.xml
deleted file mode 100644
index ac3baf2..0000000
--- a/tests/test-cdi/cdi-webapp-it/pom.xml
+++ /dev/null
@@ -1,215 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-// ========================================================================
-// Copyright (c) Webtide LLC
-// 
-// 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.apache.org/licenses/LICENSE-2.0.txt
-//
-// You may elect to redistribute this code under either of these licenses. 
-// ========================================================================
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.tests</groupId>
-    <artifactId>test-cdi-parent</artifactId>
-    <version>9.2.4-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>cdi-webapp-it</artifactId>
-  <packaging>jar</packaging>
-  <name>Jetty Tests :: CDI :: WebApp Integration Tests</name>
-  <url>http://www.eclipse.org/jetty</url>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    <bundle-symbolic-name>${project.groupId}.cdi.webapp.it</bundle-symbolic-name>
-    <scripts-dir>${project.basedir}/src/test/scripts</scripts-dir>
-    <test-base-dir>${project.build.directory}/test-base</test-base-dir>
-    <test-home-dir>${project.build.directory}/test-home</test-home-dir>
-  </properties>
-  <dependencies>
-    <dependency>
-      <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-distribution</artifactId>
-      <version>${project.version}</version>
-      <type>zip</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.tests</groupId>
-      <artifactId>cdi-webapp</artifactId>
-      <version>${project.version}</version>
-      <type>war</type>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.eclipse.jetty.toolchain</groupId>
-      <artifactId>jetty-test-helper</artifactId>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>copy-apps-for-testing</id>
-            <phase>process-test-resources</phase>
-            <goals>
-              <goal>copy-dependencies</goal>
-            </goals>
-            <configuration>
-              <includeArtifactIds>cdi-webapp</includeArtifactIds>
-              <includeScope>runtime</includeScope>
-              <includeTypes>war</includeTypes>
-              <overwriteSnapshots>true</overwriteSnapshots>
-              <overwriteReleases>true</overwriteReleases>
-              <stripVersion>true</stripVersion>
-              <outputDirectory>${test-base-dir}/webapps</outputDirectory>
-            </configuration>
-          </execution>
-          <execution>
-            <id>unpack-jetty-distro</id>
-            <phase>process-test-resources</phase>
-            <goals>
-              <goal>unpack-dependencies</goal>
-            </goals>
-            <configuration>
-              <includeArtifactIds>jetty-distribution</includeArtifactIds>
-              <includeScope>runtime</includeScope>
-              <includeTypes>zip</includeTypes>
-              <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
-              <outputDirectory>${test-home-dir}</outputDirectory>
-              <overWriteSnapshots>true</overWriteSnapshots>
-              <overWriteIfNewer>true</overWriteIfNewer>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-failsafe-plugin</artifactId>
-        <version>2.17</version>
-        <executions>
-          <execution>
-            <goals>
-              <goal>integration-test</goal>
-              <goal>verify</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <version>1.7</version>
-        <executions>
-          <execution>
-            <id>start-jetty</id>
-            <phase>pre-integration-test</phase>
-            <goals>
-              <goal>run</goal>
-            </goals>
-            <configuration>
-              <target>
-                <property name="jetty.home" location="${test-home-dir}/jetty-distribution-${project.version}"/>
-                <property name="jetty.base" location="${test-base-dir}"/>
-                <echo>Integration Test : Setup Jetty</echo>
-                <exec executable="${run.command}"
-                      dir="${scripts-dir}"
-                      spawn="false">
-                  <arg value="${run.command.xtra}"/>
-                  <arg value="${setup.script}"/>
-                  <arg file="${java.home}"/>
-                  <arg file="${jetty.home}"/>
-                  <arg file="${jetty.base}"/>
-                </exec>
-
-                <echo>Integration Test : Starting Jetty ...</echo>
-                <exec executable="${run.command}"
-                      dir="${scripts-dir}"
-                      spawn="true">
-                  <arg value="${run.command.xtra}"/>
-                  <arg value="${start.script}"/>
-                  <arg file="${java.home}"/>
-                  <arg file="${jetty.home}"/>
-                  <arg file="${jetty.base}"/>
-                </exec>
-                <waitfor maxwait="5" maxwaitunit="second"
-                  checkevery="100" checkeveryunit="millisecond">
-                  <http url="http://localhost:58080/cdi-webapp/"/>
-                </waitfor>
-                <echo>Integration Test : Jetty is now available</echo>
-              </target>
-            </configuration>
-          </execution>
-          <execution>
-            <id>stop-jetty</id>
-            <phase>post-integration-test</phase>
-            <goals>
-              <goal>run</goal>
-            </goals>
-            <configuration>
-              <target>
-                <property name="jetty.home" location="${test-home-dir}/jetty-distribution-${project.version}"/>
-                <property name="jetty.base" location="${test-base-dir}"/>
-                <echo>Integration Test : Stop Jetty</echo>
-                <exec executable="${run.command}"
-                      dir="${scripts-dir}"
-                      spawn="false">
-                  <arg value="${run.command.xtra}"/>
-                  <arg value="${stop.script}"/>
-                  <arg file="${java.home}"/>
-                  <arg file="${jetty.home}"/>
-                  <arg file="${jetty.base}"/>
-                </exec>
-              </target>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-  <profiles>
-    <profile>
-      <id>it-windows</id>
-      <activation>
-        <os>
-          <family>Windows</family>
-        </os>
-      </activation>
-      <properties>
-        <run.command>cmd</run.command>
-        <run.command.xtra>/c</run.command.xtra>
-        <start.script>start-jetty.bat</start.script>
-        <stop.script>stop-jetty.bat</stop.script>
-      </properties>
-    </profile>
-    <profile>
-      <id>it-unix</id>
-      <activation>
-        <os>
-          <family>unix</family>
-        </os>
-      </activation>
-      <properties>
-        <run.command>sh</run.command>
-        <run.command.xtra>--</run.command.xtra>
-        <setup.script>setup-jetty.sh</setup.script>
-        <start.script>start-jetty.sh</start.script>
-        <stop.script>stop-jetty.sh</stop.script>
-      </properties>
-    </profile>
-  </profiles>
-</project>
diff --git a/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java b/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java
deleted file mode 100644
index 9c0b232..0000000
--- a/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/HelloIT.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.tests;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.net.URI;
-
-import org.eclipse.jetty.toolchain.test.SimpleRequest;
-import org.junit.Test;
-
-/**
- * Basic tests for a simple @WebServlet with no CDI
- */
-public class HelloIT
-{
-    @Test
-    public void testBasic() throws Exception
-    {
-        URI serverURI = new URI("http://localhost:58080/cdi-webapp/");
-        SimpleRequest req = new SimpleRequest(serverURI);
-        assertThat(req.getString("hello"),is("Hello World"));
-    }
-}
diff --git a/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java b/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java
deleted file mode 100644
index 9de7130..0000000
--- a/tests/test-cdi/cdi-webapp-it/src/test/java/org/eclipse/jetty/tests/ServerInfoIT.java
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.tests;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.net.URI;
-
-import org.eclipse.jetty.toolchain.test.SimpleRequest;
-import org.junit.Test;
-
-public class ServerInfoIT
-{
-    @Test
-    public void testGET() throws Exception {
-        URI serverURI = new URI("http://localhost:58080/cdi-webapp/");
-        SimpleRequest req = new SimpleRequest(serverURI);
-        assertThat(req.getString("serverinfo"),is("Hello World"));
-    }
-}
diff --git a/tests/test-cdi/cdi-webapp-it/src/test/scripts/setup-jetty.sh b/tests/test-cdi/cdi-webapp-it/src/test/scripts/setup-jetty.sh
deleted file mode 100755
index c1c2ad6..0000000
--- a/tests/test-cdi/cdi-webapp-it/src/test/scripts/setup-jetty.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-JAVA_HOME=$1
-JETTY_HOME=$2
-JETTY_BASE=$3
-
-echo \${java.home}  : $JAVA_HOME
-echo \${jetty.home} : $JETTY_HOME
-echo \${jetty.base} : $JETTY_BASE
-
-cd "$JETTY_BASE"
-
-"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
-    --approve-all-licenses \
-    --add-to-start=deploy,http,annotations,cdi,logging
-
-"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
-    --version
-
diff --git a/tests/test-cdi/cdi-webapp-it/src/test/scripts/start-jetty.sh b/tests/test-cdi/cdi-webapp-it/src/test/scripts/start-jetty.sh
deleted file mode 100755
index 1d0f9eb..0000000
--- a/tests/test-cdi/cdi-webapp-it/src/test/scripts/start-jetty.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-JAVA_HOME=$1
-JETTY_HOME=$2
-JETTY_BASE=$3
-
-echo \${java.home}  : $JAVA_HOME
-echo \${jetty.home} : $JETTY_HOME
-echo \${jetty.base} : $JETTY_BASE
-
-cd "$JETTY_BASE"
-
-"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
-    jetty.port=58080 \
-    STOP.PORT=58181 STOP.KEY=it
-
-
diff --git a/tests/test-cdi/cdi-webapp/pom.xml b/tests/test-cdi/cdi-webapp/pom.xml
deleted file mode 100644
index 117fe10..0000000
--- a/tests/test-cdi/cdi-webapp/pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  // ========================================================================
-  // Copyright (c) Webtide LLC
-  //
-  // 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.apache.org/licenses/LICENSE-2.0.txt
-  //
-  // You may elect to redistribute this code under either of these licenses.
-  // ========================================================================
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.tests</groupId>
-    <artifactId>test-cdi-parent</artifactId>
-    <version>9.2.4-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>cdi-webapp</artifactId>
-  <packaging>war</packaging>
-  <name>Jetty Tests :: CDI :: WebApp</name>
-  <url>http://www.eclipse.org/jetty</url>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <bundle-symbolic-name>${project.groupId}.cdi.webapp</bundle-symbolic-name>
-  </properties>
-  <dependencies>
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>javax.servlet-api</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>javax.enterprise</groupId>
-      <artifactId>cdi-api</artifactId>
-      <version>1.1</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>javax.websocket</groupId>
-      <artifactId>javax.websocket-api</artifactId>
-      <scope>provided</scope>
-    </dependency>
-  </dependencies>
-  <build>
-    <finalName>cdi-webapp</finalName>
-  </build>
-</project>
diff --git a/tests/test-cdi/pom.xml b/tests/test-cdi/pom.xml
deleted file mode 100644
index 307d8e1..0000000
--- a/tests/test-cdi/pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-// ========================================================================
-// Copyright (c) Webtide LLC
-// 
-// 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.apache.org/licenses/LICENSE-2.0.txt
-//
-// You may elect to redistribute this code under either of these licenses. 
-// ========================================================================
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <parent>
-    <groupId>org.eclipse.jetty.tests</groupId>
-    <artifactId>tests-parent</artifactId>
-    <version>9.2.4-SNAPSHOT</version>
-  </parent>
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>test-cdi-parent</artifactId>
-  <packaging>pom</packaging>
-  <name>Jetty Tests :: CDI Parent</name>
-  <url>http://www.eclipse.org/jetty</url>
-  <modules>
-    <module>cdi-webapp</module>
-    <module>cdi-webapp-it</module>
-    <module>cdi-client</module>
-  </modules>
-</project>
diff --git a/tests/test-continuation/pom.xml b/tests/test-continuation/pom.xml
index b8de79a..f7de0fe 100644
--- a/tests/test-continuation/pom.xml
+++ b/tests/test-continuation/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -28,6 +28,9 @@
   <packaging>jar</packaging>
   <name>Test :: Continuation</name>
   <description>Asynchronous API</description>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.continuation</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java b/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java
deleted file mode 100644
index a9ed265..0000000
--- a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java
+++ /dev/null
@@ -1,509 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.continuation;
-
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-
-public abstract class ContinuationBase
-{
-    protected SuspendServlet _servlet=new SuspendServlet();
-    protected int _port;
-
-    protected void doNormal(String type) throws Exception
-    {
-        String response=process(null,null);
-        assertContains(type,response);
-        assertContains("NORMAL",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: onComplete",response);
-    }
-
-    protected void doSleep() throws Exception
-    {
-        String response=process("sleep=200",null);
-        assertContains("SLEPT",response);
-        assertNotContains("history: onTimeout",response);
-        assertNotContains("history: onComplete",response);
-    }
-
-    protected void doSuspend() throws Exception
-    {
-        String response=process("suspend=200",null);
-        assertContains("TIMEOUT",response);
-        assertContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendWaitResume() throws Exception
-    {
-        String response=process("suspend=200&resume=10",null);
-        assertContains("RESUMED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendResume() throws Exception
-    {
-        String response=process("suspend=200&resume=0",null);
-        assertContains("RESUMED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendWaitComplete() throws Exception
-    {
-        String response=process("suspend=200&complete=50",null);
-        assertContains("COMPLETED",response);
-        assertContains("history: initial",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-        assertNotContains("history: !initial",response);
-    }
-
-    protected void doSuspendComplete() throws Exception
-    {
-        String response=process("suspend=200&complete=0",null);
-        assertContains("COMPLETED",response);
-        assertContains("history: initial",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-        assertNotContains("history: !initial",response);
-    }
-
-    protected void doSuspendWaitResumeSuspendWaitResume() throws Exception
-    {
-        String response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(2,count(response,"history: resume"));
-        assertEquals(0,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("RESUMED",response);
-    }
-
-    protected void doSuspendWaitResumeSuspendComplete() throws Exception
-    {
-        String response=process("suspend=1000&resume=10&suspend2=1000&complete2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(1,count(response,"history: resume"));
-        assertEquals(0,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("COMPLETED",response);
-    }
-
-    protected void doSuspendWaitResumeSuspend() throws Exception
-    {
-        String response=process("suspend=1000&resume=10&suspend2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(1,count(response,"history: resume"));
-        assertEquals(1,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("TIMEOUT",response);
-    }
-
-    protected void doSuspendTimeoutSuspendResume() throws Exception
-    {
-        String response=process("suspend=10&suspend2=1000&resume2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(1,count(response,"history: resume"));
-        assertEquals(1,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("RESUMED",response);
-    }
-
-    protected void doSuspendTimeoutSuspendComplete() throws Exception
-    {
-        String response=process("suspend=10&suspend2=1000&complete2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(0,count(response,"history: resume"));
-        assertEquals(1,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("COMPLETED",response);
-    }
-
-    protected void doSuspendTimeoutSuspend() throws Exception
-    {
-        String response=process("suspend=10&suspend2=10",null);
-        assertEquals(2,count(response,"history: suspend"));
-        assertEquals(0,count(response,"history: resume"));
-        assertEquals(2,count(response,"history: onTimeout"));
-        assertEquals(1,count(response,"history: onComplete"));
-        assertContains("TIMEOUT",response);
-    }
-
-    protected void doSuspendThrowResume() throws Exception
-    {
-        String response=process("suspend=200&resume=10&undispatch=true",null);
-        assertContains("RESUMED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendResumeThrow() throws Exception
-    {
-        String response=process("suspend=200&resume=0&undispatch=true",null);
-        assertContains("RESUMED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendThrowComplete() throws Exception
-    {
-        String response=process("suspend=200&complete=10&undispatch=true",null);
-        assertContains("COMPLETED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-    protected void doSuspendCompleteThrow() throws Exception
-    {
-        String response=process("suspend=200&complete=0&undispatch=true",null);
-        assertContains("COMPLETED",response);
-        assertNotContains("history: onTimeout",response);
-        assertContains("history: onComplete",response);
-    }
-
-
-    private int count(String responses,String substring)
-    {
-        int count=0;
-        int i=responses.indexOf(substring);
-        while (i>=0)
-        {
-            count++;
-            i=responses.indexOf(substring,i+substring.length());
-        }
-
-        return count;
-    }
-
-    protected void assertContains(String content,String response)
-    {
-        assertThat(response,startsWith("HTTP/1.1 200 OK"));
-        assertThat(response,containsString(content));
-    }
-
-    protected void assertNotContains(String content,String response)
-    {
-        assertThat(response,startsWith("HTTP/1.1 200 OK"));
-        assertThat(response,not(containsString(content)));
-    }
-
-    public synchronized String process(String query,String content) throws Exception
-    {
-        String request = "GET /";
-
-        if (query!=null)
-            request+="?"+query;
-        request+=" HTTP/1.1\r\n"+
-        "Host: localhost\r\n"+
-        "Connection: close\r\n";
-        if (content==null)
-            request+="\r\n";
-        else
-        {
-            request+="Content-Length: "+content.length()+"\r\n";
-            request+="\r\n" + content;
-        }
-
-        int port=_port;
-        String response=null;
-        try (Socket socket = new Socket("localhost",port);)
-        {
-            socket.setSoTimeout(10000);
-            socket.getOutputStream().write(request.getBytes(StandardCharsets.UTF_8));
-            socket.getOutputStream().flush();
-
-            response = toString(socket.getInputStream());
-        }
-        catch(Exception e)
-        {
-            System.err.println("failed on port "+port);
-            e.printStackTrace();
-            throw e;
-        }
-        return response;
-    }
-
-
-    protected abstract String toString(InputStream in) throws IOException;
-
-
-    private static class SuspendServlet extends HttpServlet
-    {
-        private Timer _timer=new Timer();
-
-        public SuspendServlet()
-        {}
-
-        /* ------------------------------------------------------------ */
-        @Override
-        protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
-        {
-            final Continuation continuation = ContinuationSupport.getContinuation(request);
-
-            response.addHeader("history",continuation.getClass().toString());
-
-            int read_before=0;
-            long sleep_for=-1;
-            long suspend_for=-1;
-            long suspend2_for=-1;
-            long resume_after=-1;
-            long resume2_after=-1;
-            long complete_after=-1;
-            long complete2_after=-1;
-            boolean undispatch=false;
-
-            if (request.getParameter("read")!=null)
-                read_before=Integer.parseInt(request.getParameter("read"));
-            if (request.getParameter("sleep")!=null)
-                sleep_for=Integer.parseInt(request.getParameter("sleep"));
-            if (request.getParameter("suspend")!=null)
-                suspend_for=Integer.parseInt(request.getParameter("suspend"));
-            if (request.getParameter("suspend2")!=null)
-                suspend2_for=Integer.parseInt(request.getParameter("suspend2"));
-            if (request.getParameter("resume")!=null)
-                resume_after=Integer.parseInt(request.getParameter("resume"));
-            if (request.getParameter("resume2")!=null)
-                resume2_after=Integer.parseInt(request.getParameter("resume2"));
-            if (request.getParameter("complete")!=null)
-                complete_after=Integer.parseInt(request.getParameter("complete"));
-            if (request.getParameter("complete2")!=null)
-                complete2_after=Integer.parseInt(request.getParameter("complete2"));
-            if (request.getParameter("undispatch")!=null)
-                undispatch=Boolean.parseBoolean(request.getParameter("undispatch"));
-
-            if (continuation.isInitial())
-            {
-                response.addHeader("history","initial");
-                if (read_before>0)
-                {
-                    byte[] buf=new byte[read_before];
-                    request.getInputStream().read(buf);
-                }
-                else if (read_before<0)
-                {
-                    InputStream in = request.getInputStream();
-                    int b=in.read();
-                    while(b!=-1)
-                        b=in.read();
-                }
-
-                if (suspend_for>=0)
-                {
-                    if (suspend_for>0)
-                        continuation.setTimeout(suspend_for);
-                    continuation.addContinuationListener(__listener);
-                    response.addHeader("history","suspend");
-                    continuation.suspend(response);
-
-                    if (complete_after>0)
-                    {
-                        TimerTask complete = new TimerTask()
-                        {
-                            @Override
-                            public void run()
-                            {
-                                try
-                                {
-                                    response.setStatus(200);
-                                    response.getOutputStream().println("COMPLETED\n");
-                                    continuation.complete();
-                                }
-                                catch(Exception e)
-                                {
-                                    e.printStackTrace();
-                                }
-                            }
-                        };
-                        synchronized (_timer)
-                        {
-                            _timer.schedule(complete,complete_after);
-                        }
-                    }
-                    else if (complete_after==0)
-                    {
-                        response.setStatus(200);
-                        response.getOutputStream().println("COMPLETED\n");
-                        continuation.complete();
-                    }
-                    else if (resume_after>0)
-                    {
-                        TimerTask resume = new TimerTask()
-                        {
-                            @Override
-                            public void run()
-                            {
-                                ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume");
-                                continuation.resume();
-                            }
-                        };
-                        synchronized (_timer)
-                        {
-                            _timer.schedule(resume,resume_after);
-                        }
-                    }
-                    else if (resume_after==0)
-                    {
-                        ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume");
-                        continuation.resume();
-                    }
-
-                    if (undispatch)
-                        continuation.undispatch();
-                }
-                else if (sleep_for>=0)
-                {
-                    try
-                    {
-                        Thread.sleep(sleep_for);
-                    }
-                    catch (InterruptedException e)
-                    {
-                        e.printStackTrace();
-                    }
-                    response.setStatus(200);
-                    response.getOutputStream().println("SLEPT\n");
-                }
-                else
-                {
-                    response.setStatus(200);
-                    response.getOutputStream().println("NORMAL\n");
-                }
-            }
-            else
-            {
-                response.addHeader("history","!initial");
-                if (suspend2_for>=0 && request.getAttribute("2nd")==null)
-                {
-                    request.setAttribute("2nd","cycle");
-
-                    if (suspend2_for>0)
-                        continuation.setTimeout(suspend2_for);
-                    // continuation.addContinuationListener(__listener);
-                    response.addHeader("history","suspend");
-                    continuation.suspend(response);
-
-                    if (complete2_after>0)
-                    {
-                        TimerTask complete = new TimerTask()
-                        {
-                            @Override
-                            public void run()
-                            {
-                                try
-                                {
-                                    response.setStatus(200);
-                                    response.getOutputStream().println("COMPLETED\n");
-                                    continuation.complete();
-                                }
-                                catch(Exception e)
-                                {
-                                    e.printStackTrace();
-                                }
-                            }
-                        };
-                        synchronized (_timer)
-                        {
-                            _timer.schedule(complete,complete2_after);
-                        }
-                    }
-                    else if (complete2_after==0)
-                    {
-                        response.setStatus(200);
-                        response.getOutputStream().println("COMPLETED\n");
-                        continuation.complete();
-                    }
-                    else if (resume2_after>0)
-                    {
-                        TimerTask resume = new TimerTask()
-                        {
-                            @Override
-                            public void run()
-                            {
-                                response.addHeader("history","resume");
-                                continuation.resume();
-                            }
-                        };
-                        synchronized (_timer)
-                        {
-                            _timer.schedule(resume,resume2_after);
-                        }
-                    }
-                    else if (resume2_after==0)
-                    {
-                        response.addHeader("history","resume");
-                        continuation.resume();
-                    }
-                    if (undispatch)
-                        continuation.undispatch();
-                    return;
-                }
-                else if (continuation.isExpired())
-                {
-                    response.setStatus(200);
-                    response.getOutputStream().println("TIMEOUT\n");
-                }
-                else if (continuation.isResumed())
-                {
-                    response.setStatus(200);
-                    response.getOutputStream().println("RESUMED\n");
-                }
-                else
-                {
-                    response.setStatus(200);
-                    response.getOutputStream().println("unknown???\n");
-                }
-            }
-        }
-    }
-
-
-    private static ContinuationListener __listener = new ContinuationListener()
-    {
-        @Override
-        public void onComplete(Continuation continuation)
-        {
-            ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onComplete");
-        }
-
-        @Override
-        public void onTimeout(Continuation continuation)
-        {
-            ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onTimeout");
-        }
-
-    };
-}
diff --git a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java b/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java
deleted file mode 100644
index 2d7a4f6..0000000
--- a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.continuation;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.RequestLog;
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.handler.RequestLogHandler;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.IO;
-import org.eclipse.jetty.util.component.AbstractLifeCycle;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-
-
-public class ContinuationTest extends ContinuationBase
-{
-    protected Server _server = new Server();
-    protected ServletHandler _servletHandler;
-    protected ServerConnector _connector;
-    FilterHolder _filter;
-    protected List<String> _log = new ArrayList<String>();
-
-    @Before
-    public void setUp() throws Exception
-    {
-        _connector = new ServerConnector(_server);
-        _server.setConnectors(new Connector[]{ _connector });
-
-        _log.clear();
-        RequestLogHandler requestLogHandler = new RequestLogHandler();
-        requestLogHandler.setRequestLog(new Log());
-        _server.setHandler(requestLogHandler);
-        
-        ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.NO_SECURITY|ServletContextHandler.NO_SESSIONS);
-        requestLogHandler.setHandler(servletContext);
-        
-        _servletHandler=servletContext.getServletHandler();
-        ServletHolder holder=new ServletHolder(_servlet);
-        holder.setAsyncSupported(true);
-        _servletHandler.addServletWithMapping(holder,"/");
-        
-        _server.start();
-        _port=_connector.getLocalPort();
-    }
-
-    @After
-    public void tearDown() throws Exception
-    {
-        Assert.assertEquals(1,_log.size());
-        Assert.assertTrue(_log.get(0).startsWith("200 "));
-        Assert.assertTrue(_log.get(0).endsWith(" /"));
-        _server.stop();
-    }
-    
-    @Test
-    public void testContinuation() throws Exception
-    {
-        doNormal("Servlet3Continuation");
-    }
-
-    @Test
-    public void testSleep() throws Exception
-    {
-        doSleep();
-    }
-
-    @Test
-    public void testSuspend() throws Exception
-    {
-        doSuspend();
-    }
-
-    @Test
-    public void testSuspendWaitResume() throws Exception
-    {
-        doSuspendWaitResume();
-    }
-
-    @Test
-    public void testSuspendResume() throws Exception
-    {
-        doSuspendResume();
-    }
-
-    @Test
-    public void testSuspendWaitComplete() throws Exception
-    {
-        doSuspendWaitComplete();
-    }
-
-    @Test
-    public void testSuspendComplete() throws Exception
-    {
-        doSuspendComplete();
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspendWaitResume() throws Exception
-    {
-        doSuspendWaitResumeSuspendWaitResume();
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspendComplete() throws Exception
-    {
-        doSuspendWaitResumeSuspendComplete();
-    }
-
-    @Test
-    public void testSuspendWaitResumeSuspend() throws Exception
-    {
-        doSuspendWaitResumeSuspend();
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspendResume() throws Exception
-    {
-        doSuspendTimeoutSuspendResume();
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspendComplete() throws Exception
-    {
-        doSuspendTimeoutSuspendComplete();
-    }
-
-    @Test
-    public void testSuspendTimeoutSuspend() throws Exception
-    {
-        doSuspendTimeoutSuspend();
-    }
-
-    @Test
-    public void testSuspendThrowResume() throws Exception
-    {
-        doSuspendThrowResume();
-    }
-
-    @Test
-    public void testSuspendResumeThrow() throws Exception
-    {
-        doSuspendResumeThrow();
-    }
-
-    @Test
-    public void testSuspendThrowComplete() throws Exception
-    {
-        doSuspendThrowComplete();
-    }
-
-    @Test
-    public void testSuspendCompleteThrow() throws Exception
-    {
-        doSuspendCompleteThrow();
-    }
-    
-    @Override
-    protected String toString(InputStream in) throws IOException
-    {
-        return IO.toString(in);
-    }
-    
-    class Log extends AbstractLifeCycle implements RequestLog
-    {
-        @Override
-        public void log(Request request, Response response)
-        {
-            _log.add(response.getStatus()+" "+response.getContentCount()+" "+request.getRequestURI());
-        }
-        
-    }
-}
diff --git a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationsTest.java b/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationsTest.java
new file mode 100644
index 0000000..3968bfe
--- /dev/null
+++ b/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationsTest.java
@@ -0,0 +1,655 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.continuation;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.RequestLog;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ContinuationsTest
+{
+    @SuppressWarnings("serial")
+    public static class SneakyList extends ArrayList<String> {
+        @Override
+        public boolean add(String e)
+        {
+            System.err.printf("add(%s)%n",e);
+            return super.add(e);
+        }
+    };
+    
+    @Parameters(name="{0}")
+    public static List<Object[]> data()
+    {
+        List<Object[]> setup = new ArrayList<>();
+        
+        // Servlet3 / AsyncContext Setup
+        {
+            String description = "Servlet 3 Setup";
+            Class<? extends Continuation> expectedImplClass = Servlet3Continuation.class;
+            List<String> log = new ArrayList<>();
+            RequestLogHandler servlet3Setup = new RequestLogHandler();
+            servlet3Setup.setRequestLog(new Log(log));
+        
+            ServletContextHandler servletContext = new ServletContextHandler();
+            servlet3Setup.setHandler(servletContext);
+        
+            ServletHandler servletHandler=servletContext.getServletHandler();
+            List<String> history = new SneakyList();
+            Listener listener = new Listener(history);
+            ServletHolder holder=new ServletHolder(new SuspendServlet(history, listener));
+            holder.setAsyncSupported(true);
+            servletHandler.addServletWithMapping(holder, "/");
+            setup.add(new Object[]{description,servlet3Setup,history,listener,expectedImplClass,log});
+        }
+        
+        // Faux Continuations Setup
+        {
+            String description = "Faux Setup";
+            Class<? extends Continuation> expectedImplClass = FauxContinuation.class;
+            
+            // no log for this setup
+            List<String> log = null;
+            
+            ServletContextHandler fauxSetup = new ServletContextHandler();
+            ServletHandler servletHandler=fauxSetup.getServletHandler();
+            List<String> history = new SneakyList();
+            Listener listener = new Listener(history);
+            ServletHolder holder=new ServletHolder(new SuspendServlet(history, listener));
+            servletHandler.addServletWithMapping(holder,"/");
+    
+            FilterHolder filter= servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",null);
+            filter.setInitParameter("debug","true");
+            filter.setInitParameter("faux","true");
+            setup.add(new Object[]{description,fauxSetup,history,listener,expectedImplClass,log});
+        }
+        
+        return setup;
+    }
+    
+    @Parameter(0)
+    public String setupDescription;
+    
+    @Parameter(1)
+    public Handler setupHandler;
+    
+    @Parameter(2)
+    public List<String> history;
+    
+    @Parameter(3)
+    public Listener listener;
+    
+    @Parameter(4)
+    public Class<? extends Continuation> expectedImplClass;
+    
+    @Parameter(5)
+    public List<String> log;
+
+    @Test
+    public void testNormal() throws Exception
+    {
+        String response = process(null, null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("NORMAL"));
+        assertThat(history, hasItem(expectedImplClass.getName()));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, not(hasItem("onComplete")));
+    }
+
+    @Test
+    public void testSleep() throws Exception
+    {
+        String response = process("sleep=200", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("SLEPT"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, not(hasItem("onComplete")));
+    }
+
+    @Test
+    public void testSuspend() throws Exception
+    {
+        String response = process("suspend=200", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("TIMEOUT"));
+        assertThat(history, hasItem("onTimeout"));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendWaitResume() throws Exception
+    {
+        String response = process("suspend=200&resume=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendResume() throws Exception
+    {
+        String response = process("suspend=200&resume=0", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendWaitComplete() throws Exception
+    {
+        String response = process("suspend=200&complete=50", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertThat(history, hasItem("initial"));
+        assertThat(history, not(hasItem("!initial")));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendComplete() throws Exception
+    {
+        String response = process("suspend=200&complete=0", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertThat(history, hasItem("initial"));
+        assertThat(history, not(hasItem("!initial")));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendWaitResumeSuspendWaitResume() throws Exception
+    {
+        String response = process("suspend=1000&resume=10&suspend2=1000&resume2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(2, count(history, "resume"));
+        assertEquals(0, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendWaitResumeSuspendComplete() throws Exception
+    {
+        String response = process("suspend=1000&resume=10&suspend2=1000&complete2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(1, count(history, "resume"));
+        assertEquals(0, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendWaitResumeSuspend() throws Exception
+    {
+        String response = process("suspend=1000&resume=10&suspend2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("TIMEOUT"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(1, count(history, "resume"));
+        assertEquals(1, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendTimeoutSuspendResume() throws Exception
+    {
+        String response = process("suspend=10&suspend2=1000&resume2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(1, count(history, "resume"));
+        assertEquals(1, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendTimeoutSuspendComplete() throws Exception
+    {
+        String response = process("suspend=10&suspend2=1000&complete2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(0, count(history, "resume"));
+        assertEquals(1, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendTimeoutSuspend() throws Exception
+    {
+        String response = process("suspend=10&suspend2=10", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("TIMEOUT"));
+        assertEquals(2, count(history, "suspend"));
+        assertEquals(0, count(history, "resume"));
+        assertEquals(2, count(history, "onTimeout"));
+        assertEquals(1, count(history, "onComplete"));
+    }
+
+    @Test
+    public void testSuspendThrowResume() throws Exception
+    {
+        String response = process("suspend=200&resume=10&undispatch=true", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendResumeThrow() throws Exception
+    {
+        String response = process("suspend=200&resume=0&undispatch=true", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("RESUMED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendThrowComplete() throws Exception
+    {
+        String response = process("suspend=200&complete=10&undispatch=true", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    @Test
+    public void testSuspendCompleteThrow() throws Exception
+    {
+        String response = process("suspend=200&complete=0&undispatch=true", null);
+        assertThat(response, startsWith("HTTP/1.1 200 OK"));
+        assertThat(response, containsString("COMPLETED"));
+        assertThat(history, not(hasItem("onTimeout")));
+        assertThat(history, hasItem("onComplete"));
+    }
+
+    private long count(List<String> history, String value)
+    {
+        return history.stream()
+                .filter(value::equals)
+                .count();
+    }
+
+    private String process(String query, String content) throws Exception
+    {
+        Server server = new Server();
+        
+        try {
+            ServerConnector connector = new ServerConnector(server);
+            server.addConnector(connector);
+            if(log != null) {
+                log.clear();
+            }
+            history.clear();
+            server.setHandler(this.setupHandler);
+        
+            server.start();
+            int port=connector.getLocalPort();
+            
+            StringBuilder request = new StringBuilder("GET /");
+    
+            if (query != null)
+                request.append("?").append(query);
+    
+            request.append(" HTTP/1.1\r\n")
+                    .append("Host: localhost\r\n")
+                    .append("Connection: close\r\n");
+    
+            if (content == null)
+            {
+                request.append("\r\n");
+            }
+            else
+            {
+                request.append("Content-Length: ").append(content.length()).append("\r\n");
+                request.append("\r\n").append(content);
+            }
+    
+            try (Socket socket = new Socket("localhost", port))
+            {
+                socket.setSoTimeout(10000);
+                socket.getOutputStream().write(request.toString().getBytes(StandardCharsets.UTF_8));
+                socket.getOutputStream().flush();
+                return toString(socket.getInputStream());
+            }
+        } finally {
+            server.stop();
+            
+            if (log != null)
+            {
+                assertThat("Log.size", log.size(),is(1));
+                String entry = log.get(0);
+                assertThat("Log entry", entry, startsWith("200 "));
+                assertThat("Log entry", entry, endsWith(" /"));
+            }
+        }
+    }
+
+    protected String toString(InputStream in) throws IOException
+    {
+        return IO.toString(in);
+    }
+
+    @SuppressWarnings("serial")
+    private static class SuspendServlet extends HttpServlet
+    {
+        private final Timer _timer = new Timer();
+        private final List<String> history;
+        private final ContinuationListener listener;
+
+        public SuspendServlet(List<String> history, ContinuationListener listener)
+        {
+            this.history = history;
+            this.listener = listener;
+        }
+
+        @Override
+        protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
+        {
+            final Continuation continuation = ContinuationSupport.getContinuation(request);
+
+            history.add(continuation.getClass().getName());
+
+            int read_before = 0;
+            long sleep_for = -1;
+            long suspend_for = -1;
+            long suspend2_for = -1;
+            long resume_after = -1;
+            long resume2_after = -1;
+            long complete_after = -1;
+            long complete2_after = -1;
+            boolean undispatch = false;
+
+            if (request.getParameter("read") != null)
+                read_before = Integer.parseInt(request.getParameter("read"));
+            if (request.getParameter("sleep") != null)
+                sleep_for = Integer.parseInt(request.getParameter("sleep"));
+            if (request.getParameter("suspend") != null)
+                suspend_for = Integer.parseInt(request.getParameter("suspend"));
+            if (request.getParameter("suspend2") != null)
+                suspend2_for = Integer.parseInt(request.getParameter("suspend2"));
+            if (request.getParameter("resume") != null)
+                resume_after = Integer.parseInt(request.getParameter("resume"));
+            if (request.getParameter("resume2") != null)
+                resume2_after = Integer.parseInt(request.getParameter("resume2"));
+            if (request.getParameter("complete") != null)
+                complete_after = Integer.parseInt(request.getParameter("complete"));
+            if (request.getParameter("complete2") != null)
+                complete2_after = Integer.parseInt(request.getParameter("complete2"));
+            if (request.getParameter("undispatch") != null)
+                undispatch = Boolean.parseBoolean(request.getParameter("undispatch"));
+
+            if (continuation.isInitial())
+            {
+                history.add("initial");
+                if (read_before > 0)
+                {
+                    byte[] buf = new byte[read_before];
+                    request.getInputStream().read(buf);
+                }
+                else if (read_before < 0)
+                {
+                    InputStream in = request.getInputStream();
+                    int b = in.read();
+                    while (b != -1)
+                        b = in.read();
+                }
+
+                if (suspend_for >= 0)
+                {
+                    if (suspend_for > 0)
+                        continuation.setTimeout(suspend_for);
+                    continuation.addContinuationListener(listener);
+                    history.add("suspend");
+                    continuation.suspend(response);
+
+                    if (complete_after > 0)
+                    {
+                        TimerTask complete = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    response.setStatus(200);
+                                    response.getOutputStream().println("COMPLETED");
+                                    continuation.complete();
+                                }
+                                catch (Exception e)
+                                {
+                                    e.printStackTrace();
+                                }
+                            }
+                        };
+                        _timer.schedule(complete, complete_after);
+                    }
+                    else if (complete_after == 0)
+                    {
+                        response.setStatus(200);
+                        response.getOutputStream().println("COMPLETED");
+                        continuation.complete();
+                    }
+                    else if (resume_after > 0)
+                    {
+                        TimerTask resume = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                history.add("resume");
+                                continuation.resume();
+                            }
+                        };
+                        _timer.schedule(resume, resume_after);
+                    }
+                    else if (resume_after == 0)
+                    {
+                        history.add("resume");
+                        continuation.resume();
+                    }
+
+                    if (undispatch)
+                    {
+                        continuation.undispatch();
+                    }
+                }
+                else if (sleep_for >= 0)
+                {
+                    try
+                    {
+                        Thread.sleep(sleep_for);
+                    }
+                    catch (InterruptedException e)
+                    {
+                        e.printStackTrace();
+                    }
+                    response.setStatus(200);
+                    response.getOutputStream().println("SLEPT");
+                }
+                else
+                {
+                    response.setStatus(200);
+                    response.getOutputStream().println("NORMAL");
+                }
+            }
+            else
+            {
+                history.add("!initial");
+                if (suspend2_for >= 0 && request.getAttribute("2nd") == null)
+                {
+                    request.setAttribute("2nd", "cycle");
+
+                    if (suspend2_for > 0)
+                        continuation.setTimeout(suspend2_for);
+
+                    history.add("suspend");
+                    continuation.suspend(response);
+
+                    if (complete2_after > 0)
+                    {
+                        TimerTask complete = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                try
+                                {
+                                    response.setStatus(200);
+                                    response.getOutputStream().println("COMPLETED");
+                                    continuation.complete();
+                                }
+                                catch (Exception e)
+                                {
+                                    e.printStackTrace();
+                                }
+                            }
+                        };
+                        _timer.schedule(complete, complete2_after);
+                    }
+                    else if (complete2_after == 0)
+                    {
+                        response.setStatus(200);
+                        response.getOutputStream().println("COMPLETED");
+                        continuation.complete();
+                    }
+                    else if (resume2_after > 0)
+                    {
+                        TimerTask resume = new TimerTask()
+                        {
+                            @Override
+                            public void run()
+                            {
+                                history.add("resume");
+                                continuation.resume();
+                            }
+                        };
+                        _timer.schedule(resume, resume2_after);
+                    }
+                    else if (resume2_after == 0)
+                    {
+                        history.add("resume");
+                        continuation.resume();
+                    }
+
+                    if (undispatch)
+                    {
+                        continuation.undispatch();
+                    }
+                }
+                else if (continuation.isExpired())
+                {
+                    response.setStatus(200);
+                    response.getOutputStream().println("TIMEOUT");
+                }
+                else if (continuation.isResumed())
+                {
+                    response.setStatus(200);
+                    response.getOutputStream().println("RESUMED");
+                }
+                else
+                {
+                    response.setStatus(200);
+                    response.getOutputStream().println("UNKNOWN");
+                }
+            }
+        }
+    }
+
+    private static class Listener implements ContinuationListener
+    {
+        private final List<String> history;
+
+        public Listener(List<String> history)
+        {
+            this.history = history;
+        }
+
+        @Override
+        public void onComplete(Continuation continuation)
+        {
+            history.add("onComplete");
+        }
+
+        @Override
+        public void onTimeout(Continuation continuation)
+        {
+            history.add("onTimeout");
+        }
+    }
+    
+    public static class Log extends AbstractLifeCycle implements RequestLog
+    {
+        private final List<String> log;
+        
+        public Log(List<String> log) {
+            this.log = log;
+        }
+        
+        @Override
+        public void log(Request request, Response response)
+        {
+            int status = response.getCommittedMetaData().getStatus();
+            long written = response.getHttpChannel().getBytesWritten();
+            log.add(status+" "+written+" "+request.getRequestURI());
+        }
+    }
+}
diff --git a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java b/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
deleted file mode 100644
index 92ac2e5..0000000
--- a/tests/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.continuation;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.IO;
-
-
-public class FauxContinuationTest extends ContinuationBase
-{
-    protected Server _server = new Server();
-    protected ServletHandler _servletHandler;
-    protected ServerConnector _connector;
-    FilterHolder _filter;
-
-    protected void setUp() throws Exception
-    {
-        _connector = new ServerConnector(_server);
-        _server.setConnectors(new Connector[]{ _connector });
-        ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.NO_SECURITY|ServletContextHandler.NO_SESSIONS);
-        _server.setHandler(servletContext);
-        _servletHandler=servletContext.getServletHandler();
-        ServletHolder holder=new ServletHolder(_servlet);
-        _servletHandler.addServletWithMapping(holder,"/");
-        
-        _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",null);
-        _filter.setInitParameter("debug","true");
-        _filter.setInitParameter("faux","true");
-        _server.start();
-        _port=_connector.getLocalPort();
-        
-    }
-
-    protected void tearDown() throws Exception
-    {
-        _server.stop();
-    }
-
-    public void testContinuation() throws Exception
-    {
-        doNormal("FauxContinuation");
-    }
-    
-    public void testSleep() throws Exception
-    {
-        doSleep();
-    }
-
-    public void testSuspend() throws Exception
-    {
-        doSuspend();
-    }
-
-    public void testSuspendWaitResume() throws Exception
-    {
-        doSuspendWaitResume();
-    }
-
-    public void testSuspendResume() throws Exception
-    {
-        doSuspendResume();
-    }
-
-    public void testSuspendWaitComplete() throws Exception
-    {
-        doSuspendWaitComplete();
-    }
-
-    public void testSuspendComplete() throws Exception
-    {
-        doSuspendComplete();
-    }
-
-    public void testSuspendWaitResumeSuspendWaitResume() throws Exception
-    {
-        doSuspendWaitResumeSuspendWaitResume();
-    }
-    
-    public void testSuspendWaitResumeSuspendComplete() throws Exception
-    {
-        doSuspendWaitResumeSuspendComplete();
-    }
-
-    public void testSuspendWaitResumeSuspend() throws Exception
-    {
-        doSuspendWaitResumeSuspend();
-    }
-
-    public void testSuspendTimeoutSuspendResume() throws Exception
-    {
-        doSuspendTimeoutSuspendResume();
-    }
-
-    public void testSuspendTimeoutSuspendComplete() throws Exception
-    {
-        doSuspendTimeoutSuspendComplete();
-    }
-
-    public void testSuspendTimeoutSuspend() throws Exception
-    {
-        doSuspendTimeoutSuspend();
-    }
-
-    public void testSuspendThrowResume() throws Exception
-    {
-        doSuspendThrowResume();
-    }
-
-    public void testSuspendResumeThrow() throws Exception
-    {
-        doSuspendResumeThrow();
-    }
-
-    public void testSuspendThrowComplete() throws Exception
-    {
-        doSuspendThrowComplete();
-    }
-
-    public void testSuspendCompleteThrow() throws Exception
-    {
-        doSuspendCompleteThrow();
-    }
-    
-    
-    
-    protected String toString(InputStream in) throws IOException
-    {
-        return IO.toString(in);
-    }
-    
-}
diff --git a/tests/test-continuation/src/test/resources/jetty-logging.properties b/tests/test-continuation/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..d1e0e0c
--- /dev/null
+++ b/tests/test-continuation/src/test/resources/jetty-logging.properties
@@ -0,0 +1,3 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+org.eclipse.jetty.LEVEL=WARN
+# org.eclipse.jetty.server.LEVEL=DEBUG
diff --git a/tests/test-http-client-transport/pom.xml b/tests/test-http-client-transport/pom.xml
new file mode 100644
index 0000000..6d086cb
--- /dev/null
+++ b/tests/test-http-client-transport/pom.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <groupId>org.eclipse.jetty.tests</groupId>
+        <artifactId>tests-parent</artifactId>
+        <version>9.3.7-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>test-http-client-transport</artifactId>
+    <packaging>jar</packaging>
+    <name>Test :: HTTP Client Transports</name>
+
+    <properties>
+        <bundle-symbolic-name>${project.groupId}.client.http</bundle-symbolic-name>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.mortbay.jetty.alpn</groupId>
+                                    <artifactId>alpn-boot</artifactId>
+                                    <version>${alpn.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>false</overWrite>
+                                    <outputDirectory>${project.build.directory}/alpn</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <!-- DO NOT DEPLOY (or Release) -->
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-http-client-transport</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.fcgi</groupId>
+            <artifactId>fcgi-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.toolchain</groupId>
+            <artifactId>jetty-test-helper</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
new file mode 100644
index 0000000..a47a861
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
@@ -0,0 +1,224 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpClientTransport;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI;
+import org.eclipse.jetty.fcgi.server.ServerFCGIConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public abstract class AbstractTest
+{
+    @Parameterized.Parameters(name = "transport: {0}")
+    public static Object[] parameters() throws Exception
+    {
+        return Transport.values();
+    }
+
+    @Rule
+    public final TestTracker tracker = new TestTracker();
+
+    protected final Transport transport;
+    protected SslContextFactory sslContextFactory;
+    protected Server server;
+    protected ServerConnector connector;
+    protected HttpClient client;
+
+    public AbstractTest(Transport transport)
+    {
+        this.transport = transport;
+    }
+
+    public void start(Handler handler) throws Exception
+    {
+        startServer(handler);
+        startClient();
+    }
+
+    protected void startServer(Handler handler) throws Exception
+    {
+        sslContextFactory = new SslContextFactory();
+        sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
+        sslContextFactory.setKeyStorePassword("storepwd");
+        sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
+        sslContextFactory.setTrustStorePassword("storepwd");
+        sslContextFactory.setUseCipherSuitesOrder(true);
+        sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
+        QueuedThreadPool serverThreads = new QueuedThreadPool();
+        serverThreads.setName("server");
+        server = new Server(serverThreads);
+        connector = new ServerConnector(server, provideServerConnectionFactory(transport));
+        server.addConnector(connector);
+        server.setHandler(handler);
+        server.start();
+    }
+
+    private void startClient() throws Exception
+    {
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
+        client = newHttpClient(provideClientTransport(transport), sslContextFactory);
+        client.setExecutor(clientThreads);
+        client.start();
+    }
+
+    private ConnectionFactory[] provideServerConnectionFactory(Transport transport)
+    {
+        List<ConnectionFactory> result = new ArrayList<>();
+        switch (transport)
+        {
+            case HTTP:
+            {
+                result.add(new HttpConnectionFactory(new HttpConfiguration()));
+                break;
+            }
+            case HTTPS:
+            {
+                HttpConfiguration configuration = new HttpConfiguration();
+                configuration.addCustomizer(new SecureRequestCustomizer());
+                HttpConnectionFactory http = new HttpConnectionFactory(configuration);
+                SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, http.getProtocol());
+                result.add(ssl);
+                result.add(http);
+                break;
+            }
+            case H2C:
+            {
+                result.add(new HTTP2CServerConnectionFactory(new HttpConfiguration()));
+                break;
+            }
+            case H2:
+            {
+                HttpConfiguration configuration = new HttpConfiguration();
+                configuration.addCustomizer(new SecureRequestCustomizer());
+                HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(configuration);
+                ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory("h2");
+                SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
+                result.add(ssl);
+                result.add(alpn);
+                result.add(h2);
+                break;
+            }
+            case FCGI:
+            {
+                result.add(new ServerFCGIConnectionFactory(new HttpConfiguration()));
+                break;
+            }
+            default:
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+        return result.toArray(new ConnectionFactory[result.size()]);
+    }
+
+    private HttpClientTransport provideClientTransport(Transport transport)
+    {
+        switch (transport)
+        {
+            case HTTP:
+            case HTTPS:
+            {
+                return new HttpClientTransportOverHTTP(1);
+            }
+            case H2C:
+            case H2:
+            {
+                HTTP2Client http2Client = newHTTP2Client();
+                return new HttpClientTransportOverHTTP2(http2Client);
+            }
+            case FCGI:
+            {
+                return new HttpClientTransportOverFCGI(1, false, "");
+            }
+            default:
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+    }
+
+    protected HttpClient newHttpClient(HttpClientTransport transport, SslContextFactory sslContextFactory)
+    {
+        return new HttpClient(transport, sslContextFactory);
+    }
+
+    protected HTTP2Client newHTTP2Client()
+    {
+        HTTP2Client http2Client = new HTTP2Client();
+        http2Client.setSelectors(1);
+        return http2Client;
+    }
+
+    protected String newURI()
+    {
+        switch (transport)
+        {
+            case HTTP:
+            case H2C:
+            case FCGI:
+                return "http://localhost:" + connector.getLocalPort();
+            case HTTPS:
+            case H2:
+                return "https://localhost:" + connector.getLocalPort();
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    @After
+    public void stop() throws Exception
+    {
+        if (client != null)
+            client.stop();
+        if (server != null)
+            server.stop();
+    }
+
+    protected enum Transport
+    {
+        HTTP, HTTPS, H2C, H2, FCGI
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncRequestContentTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncRequestContentTest.java
new file mode 100644
index 0000000..34ff587
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncRequestContentTest.java
@@ -0,0 +1,191 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.util.DeferredContentProvider;
+import org.eclipse.jetty.client.util.InputStreamContentProvider;
+import org.eclipse.jetty.client.util.OutputStreamContentProvider;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AsyncRequestContentTest extends AbstractTest
+{
+    public AsyncRequestContentTest(Transport transport)
+    {
+        super(transport);
+    }
+
+    @Test
+    public void testEmptyDeferredContent() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        DeferredContentProvider contentProvider = new DeferredContentProvider();
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testDeferredContent() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        DeferredContentProvider contentProvider = new DeferredContentProvider();
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        contentProvider.offer(ByteBuffer.wrap(new byte[1]));
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testEmptyInputStream() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        InputStreamContentProvider contentProvider =
+                new InputStreamContentProvider(new ByteArrayInputStream(new byte[0]));
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testInputStream() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        InputStreamContentProvider contentProvider =
+                new InputStreamContentProvider(new ByteArrayInputStream(new byte[1]));
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testEmptyOutputStream() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        OutputStreamContentProvider contentProvider = new OutputStreamContentProvider();
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testOutputStream() throws Exception
+    {
+        start(new ConsumeInputHandler());
+
+        OutputStreamContentProvider contentProvider = new OutputStreamContentProvider();
+        CountDownLatch latch = new CountDownLatch(1);
+        client.POST(newURI())
+                .content(contentProvider)
+                .send(result ->
+                {
+                    if (result.isSucceeded() &&
+                            result.getResponse().getStatus() == HttpStatus.OK_200)
+                        latch.countDown();
+                });
+        OutputStream output = contentProvider.getOutputStream();
+        output.write(new byte[1]);
+        output.flush();
+        contentProvider.close();
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    private static class ConsumeInputHandler extends AbstractHandler
+    {
+        @Override
+        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+        {
+            baseRequest.setHandled(true);
+            ServletInputStream input = request.getInputStream();
+            while (true)
+            {
+                int read = input.read();
+                if (read < 0)
+                    break;
+            }
+            response.setStatus(HttpStatus.OK_200);
+        }
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpChannelAssociationTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpChannelAssociationTest.java
new file mode 100644
index 0000000..0ab8d67
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpChannelAssociationTest.java
@@ -0,0 +1,228 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.HttpClientTransport;
+import org.eclipse.jetty.client.HttpDestination;
+import org.eclipse.jetty.client.HttpExchange;
+import org.eclipse.jetty.client.api.Connection;
+import org.eclipse.jetty.client.http.HttpChannelOverHTTP;
+import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
+import org.eclipse.jetty.fcgi.client.http.HttpChannelOverFCGI;
+import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI;
+import org.eclipse.jetty.fcgi.client.http.HttpConnectionOverFCGI;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.http.HttpChannelOverHTTP2;
+import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
+import org.eclipse.jetty.http2.client.http.HttpConnectionOverHTTP2;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.eclipse.jetty.util.Promise;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpChannelAssociationTest extends AbstractTest
+{
+    public HttpChannelAssociationTest(Transport transport)
+    {
+        super(transport);
+    }
+
+    @Test
+    public void testAssociationFailedAbortsRequest() throws Exception
+    {
+        startServer(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+            }
+        });
+
+        client = new HttpClient(newHttpClientTransport(transport, exchange -> false), sslContextFactory);
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
+        client.setExecutor(clientThreads);
+        client.start();
+
+        CountDownLatch latch = new CountDownLatch(1);
+        client.newRequest(newURI())
+                .send(result ->
+                {
+                    if (result.isFailed())
+                        latch.countDown();
+                });
+
+        Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void testIdleTimeoutJustBeforeAssociation() throws Exception
+    {
+        startServer(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+            }
+        });
+
+        long idleTimeout = 1000;
+        client = new HttpClient(newHttpClientTransport(transport, exchange ->
+        {
+            // We idle timeout just before the association,
+            // we must be able to send the request successfully.
+            sleep(2 * idleTimeout);
+            return true;
+        }), sslContextFactory);
+        QueuedThreadPool clientThreads = new QueuedThreadPool();
+        clientThreads.setName("client");
+        client.setExecutor(clientThreads);
+        client.setIdleTimeout(idleTimeout);
+        client.start();
+
+        CountDownLatch latch = new CountDownLatch(1);
+        client.newRequest(newURI())
+                .send(result ->
+                {
+                    if (result.isSucceeded())
+                        latch.countDown();
+                });
+
+        Assert.assertTrue(latch.await(5 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    private HttpClientTransport newHttpClientTransport(Transport transport, Predicate<HttpExchange> code)
+    {
+        switch (transport)
+        {
+            case HTTP:
+            case HTTPS:
+            {
+                return new HttpClientTransportOverHTTP(1)
+                {
+                    @Override
+                    protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
+                    {
+                        return new HttpConnectionOverHTTP(endPoint, destination, promise)
+                        {
+                            @Override
+                            protected HttpChannelOverHTTP newHttpChannel()
+                            {
+                                return new HttpChannelOverHTTP(this)
+                                {
+                                    @Override
+                                    public boolean associate(HttpExchange exchange)
+                                    {
+                                        return code.test(exchange) && super.associate(exchange);
+                                    }
+                                };
+                            }
+                        };
+                    }
+                };
+            }
+            case H2C:
+            case H2:
+            {
+                HTTP2Client http2Client = new HTTP2Client();
+                http2Client.setSelectors(1);
+                return new HttpClientTransportOverHTTP2(http2Client)
+                {
+                    @Override
+                    protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session)
+                    {
+                        return new HttpConnectionOverHTTP2(destination, session)
+                        {
+                            @Override
+                            protected HttpChannelOverHTTP2 newHttpChannel()
+                            {
+                                return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession())
+                                {
+                                    @Override
+                                    public boolean associate(HttpExchange exchange)
+                                    {
+                                        return code.test(exchange) && super.associate(exchange);
+                                    }
+                                };
+                            }
+                        };
+                    }
+                };
+            }
+            case FCGI:
+            {
+                return new HttpClientTransportOverFCGI(1, false, "")
+                {
+                    @Override
+                    protected HttpConnectionOverFCGI newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise)
+                    {
+                        return new HttpConnectionOverFCGI(endPoint, destination, promise, isMultiplexed())
+                        {
+                            @Override
+                            protected HttpChannelOverFCGI newHttpChannel(int id, org.eclipse.jetty.client.api.Request request)
+                            {
+                                return new HttpChannelOverFCGI(this, getFlusher(), id, request.getIdleTimeout())
+                                {
+                                    @Override
+                                    public boolean associate(HttpExchange exchange)
+                                    {
+                                        return code.test(exchange) && super.associate(exchange);
+                                    }
+                                };
+                            }
+                        };
+                    }
+                };
+            }
+            default:
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+    }
+
+    private void sleep(long time)
+    {
+        try
+        {
+            Thread.sleep(time);
+        }
+        catch (InterruptedException x)
+        {
+            throw new RuntimeException(x);
+        }
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java
new file mode 100644
index 0000000..2774e9f
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java
@@ -0,0 +1,170 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.api.Result;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.Test;
+
+// TODO: these tests seems to fail spuriously, figure out why.
+@Ignore
+public class HttpClientConnectTimeoutTest extends AbstractTest
+{
+    public HttpClientConnectTimeoutTest(Transport transport)
+    {
+        super(transport);
+    }
+
+    @Test
+    public void testConnectTimeout() throws Exception
+    {
+        final String host = "10.255.255.1";
+        final int port = 80;
+        int connectTimeout = 1000;
+        assumeConnectTimeout(host, port, connectTimeout);
+
+        start(null);
+        client.stop();
+        client.setConnectTimeout(connectTimeout);
+        client.start();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Request request = client.newRequest(host, port);
+        request.send(new Response.CompleteListener()
+        {
+            @Override
+            public void onComplete(Result result)
+            {
+                if (result.isFailed())
+                    latch.countDown();
+            }
+        });
+
+        Assert.assertTrue(latch.await(2 * connectTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertNotNull(request.getAbortCause());
+    }
+
+    @Test
+    public void testConnectTimeoutIsCancelledByShorterRequestTimeout() throws Exception
+    {
+        String host = "10.255.255.1";
+        int port = 80;
+        int connectTimeout = 2000;
+        assumeConnectTimeout(host, port, connectTimeout);
+
+        start(null);
+        client.stop();
+        client.setConnectTimeout(connectTimeout);
+        client.start();
+
+        final AtomicInteger completes = new AtomicInteger();
+        final CountDownLatch latch = new CountDownLatch(2);
+        Request request = client.newRequest(host, port);
+        request.timeout(connectTimeout / 2, TimeUnit.MILLISECONDS)
+                .send(new Response.CompleteListener()
+                {
+                    @Override
+                    public void onComplete(Result result)
+                    {
+                        completes.incrementAndGet();
+                        latch.countDown();
+                    }
+                });
+
+        Assert.assertFalse(latch.await(2 * connectTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertEquals(1, completes.get());
+        Assert.assertNotNull(request.getAbortCause());
+    }
+
+    @Test
+    public void retryAfterConnectTimeout() throws Exception
+    {
+        final String host = "10.255.255.1";
+        final int port = 80;
+        int connectTimeout = 1000;
+        assumeConnectTimeout(host, port, connectTimeout);
+
+        start(null);
+        client.stop();
+        client.setConnectTimeout(connectTimeout);
+        client.start();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Request request = client.newRequest(host, port);
+        request.send(new Response.CompleteListener()
+        {
+            @Override
+            public void onComplete(Result result)
+            {
+                if (result.isFailed())
+                {
+                    // Retry
+                    client.newRequest(host, port).send(new Response.CompleteListener()
+                    {
+                        @Override
+                        public void onComplete(Result result)
+                        {
+                            if (result.isFailed())
+                                latch.countDown();
+                        }
+                    });
+                }
+            }
+        });
+
+        Assert.assertTrue(latch.await(3 * connectTimeout, TimeUnit.MILLISECONDS));
+        Assert.assertNotNull(request.getAbortCause());
+    }
+
+    private void assumeConnectTimeout(String host, int port, int connectTimeout) throws IOException
+    {
+        try (Socket socket = new Socket())
+        {
+            // Try to connect to a private address in the 10.x.y.z range.
+            // These addresses are usually not routed, so an attempt to
+            // connect to them will hang the connection attempt, which is
+            // what we want to simulate in this test.
+            socket.connect(new InetSocketAddress(host, port), connectTimeout);
+            // Abort the test if we can connect.
+            Assume.assumeTrue(false);
+        }
+        catch (SocketTimeoutException x)
+        {
+            // Expected timeout during connect, continue the test.
+            Assume.assumeTrue(true);
+        }
+        catch (Throwable x)
+        {
+            // Abort if any other exception happens.
+            Assume.assumeTrue(false);
+        }
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java
new file mode 100644
index 0000000..f88e6a5
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientIdleTimeoutTest.java
@@ -0,0 +1,122 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpClientIdleTimeoutTest extends AbstractTest
+{
+    private long idleTimeout = 1000;
+
+    public HttpClientIdleTimeoutTest(Transport transport)
+    {
+        super(transport);
+    }
+
+    @Test
+    public void testClientIdleTimeout() throws Exception
+    {
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+            }
+        });
+        client.stop();
+        client.setIdleTimeout(idleTimeout);
+        client.start();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        client.newRequest(newURI()).send(result ->
+        {
+            if (result.isFailed())
+                latch.countDown();
+        });
+
+        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testRequestIdleTimeout() throws Exception
+    {
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                AsyncContext asyncContext = request.startAsync();
+                asyncContext.setTimeout(0);
+            }
+        });
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        client.newRequest(newURI())
+                .idleTimeout(idleTimeout, TimeUnit.MILLISECONDS)
+                .send(result ->
+                {
+                    if (result.isFailed())
+                        latch.countDown();
+                });
+
+        Assert.assertTrue(latch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testServerIdleTimeout() throws Exception
+    {
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+            }
+        });
+        connector.setIdleTimeout(idleTimeout);
+
+        ContentResponse response1 = client.newRequest(newURI()).send();
+        Assert.assertEquals(HttpStatus.OK_200, response1.getStatus());
+
+        // Let the server idle timeout.
+        Thread.sleep(2 * idleTimeout);
+
+        // Make sure we can make another request successfully.
+        ContentResponse response2 = client.newRequest(newURI()).send();
+        Assert.assertEquals(HttpStatus.OK_200, response2.getStatus());
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
new file mode 100644
index 0000000..c9d3a03
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java
@@ -0,0 +1,253 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.http.client;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.util.BytesContentProvider;
+import org.eclipse.jetty.client.util.FutureResponseListener;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class HttpClientTest extends AbstractTest
+{
+    public HttpClientTest(Transport transport)
+    {
+        super(transport);
+    }
+
+    @Test
+    public void testRequestWithoutResponseContent() throws Exception
+    {
+        final int status = HttpStatus.NO_CONTENT_204;
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                response.setStatus(status);
+            }
+        });
+
+        ContentResponse response = client.newRequest(newURI())
+                .timeout(5, TimeUnit.SECONDS)
+                .send();
+
+        Assert.assertEquals(status, response.getStatus());
+        Assert.assertEquals(0, response.getContent().length);
+    }
+
+    @Test
+    public void testRequestWithSmallResponseContent() throws Exception
+    {
+        testRequestWithResponseContent(1024);
+    }
+
+    @Test
+    public void testRequestWithLargeResponseContent() throws Exception
+    {
+        testRequestWithResponseContent(1024 * 1024);
+    }
+
+    private void testRequestWithResponseContent(int length) throws Exception
+    {
+        final byte[] bytes = new byte[length];
+        new Random().nextBytes(bytes);
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                response.setContentLength(length);
+                response.getOutputStream().write(bytes);
+            }
+        });
+
+        org.eclipse.jetty.client.api.Request request = client.newRequest(newURI());
+        FutureResponseListener listener = new FutureResponseListener(request, length);
+        request.timeout(10, TimeUnit.SECONDS).send(listener);
+        ContentResponse response = listener.get();
+
+        Assert.assertEquals(200, response.getStatus());
+        Assert.assertArrayEquals(bytes, response.getContent());
+    }
+
+    @Test
+    public void testRequestWithSmallResponseContentChunked() throws Exception
+    {
+        testRequestWithResponseContentChunked(512);
+    }
+
+    @Test
+    public void testRequestWithLargeResponseContentChunked() throws Exception
+    {
+        testRequestWithResponseContentChunked(512 * 512);
+    }
+
+    private void testRequestWithResponseContentChunked(int length) throws Exception
+    {
+        final byte[] chunk1 = new byte[length];
+        final byte[] chunk2 = new byte[length];
+        Random random = new Random();
+        random.nextBytes(chunk1);
+        random.nextBytes(chunk2);
+        byte[] bytes = new byte[chunk1.length + chunk2.length];
+        System.arraycopy(chunk1, 0, bytes, 0, chunk1.length);
+        System.arraycopy(chunk2, 0, bytes, chunk1.length, chunk2.length);
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                ServletOutputStream output = response.getOutputStream();
+                output.write(chunk1);
+                output.flush();
+                output.write(chunk2);
+            }
+        });
+
+        org.eclipse.jetty.client.api.Request request = client.newRequest(newURI());
+        FutureResponseListener listener = new FutureResponseListener(request, 2 * length);
+        request.timeout(10, TimeUnit.SECONDS).send(listener);
+        ContentResponse response = listener.get();
+
+        Assert.assertEquals(200, response.getStatus());
+        Assert.assertArrayEquals(bytes, response.getContent());
+    }
+
+    @Test
+    public void testUploadZeroLengthWithoutResponseContent() throws Exception
+    {
+        testUploadWithoutResponseContent(0);
+    }
+
+    @Test
+    public void testUploadSmallWithoutResponseContent() throws Exception
+    {
+        testUploadWithoutResponseContent(1024);
+    }
+
+    @Test
+    public void testUploadLargeWithoutResponseContent() throws Exception
+    {
+        testUploadWithoutResponseContent(1024 * 1024);
+    }
+
+    private void testUploadWithoutResponseContent(int length) throws Exception
+    {
+        final byte[] bytes = new byte[length];
+        new Random().nextBytes(bytes);
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+                ServletInputStream input = request.getInputStream();
+                for (int i = 0; i < bytes.length; ++i)
+                    Assert.assertEquals(bytes[i] & 0xFF, input.read());
+                Assert.assertEquals(-1, input.read());
+            }
+        });
+
+        ContentResponse response = client.newRequest(newURI())
+                .method(HttpMethod.POST)
+                .content(new BytesContentProvider(bytes))
+                .timeout(15, TimeUnit.SECONDS)
+                .send();
+
+        Assert.assertEquals(200, response.getStatus());
+        Assert.assertEquals(0, response.getContent().length);
+    }
+
+    @Test
+    public void testClientManyWritesSlowServer() throws Exception
+    {
+        start(new AbstractHandler()
+        {
+            @Override
+            public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+            {
+                baseRequest.setHandled(true);
+
+                long sleep = 1024;
+                long total = 0;
+                ServletInputStream input = request.getInputStream();
+                byte[] buffer = new byte[1024];
+                while (true)
+                {
+                    int read = input.read(buffer);
+                    if (read < 0)
+                        break;
+                    total += read;
+                    if (total >= sleep)
+                    {
+                        sleep(250);
+                        sleep += 256;
+                    }
+                }
+
+                response.getOutputStream().print(total);
+            }
+        });
+
+        int chunks = 256;
+        int chunkSize = 16;
+        byte[][] bytes = IntStream.range(0, chunks).mapToObj(x -> new byte[chunkSize]).toArray(byte[][]::new);
+        BytesContentProvider contentProvider = new BytesContentProvider("application/octet-stream", bytes);
+        ContentResponse response = client.newRequest(newURI())
+                .method(HttpMethod.POST)
+                .content(contentProvider)
+                .timeout(15, TimeUnit.SECONDS)
+                .send();
+
+        Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+        Assert.assertEquals(chunks * chunkSize, Integer.parseInt(response.getContentAsString()));
+    }
+
+    private void sleep(long time) throws IOException
+    {
+        try
+        {
+            Thread.sleep(time);
+        }
+        catch (InterruptedException x)
+        {
+            throw new InterruptedIOException();
+        }
+    }
+}
diff --git a/tests/test-http-client-transport/src/test/resources/jetty-logging.properties b/tests/test-http-client-transport/src/test/resources/jetty-logging.properties
new file mode 100644
index 0000000..607ee96
--- /dev/null
+++ b/tests/test-http-client-transport/src/test/resources/jetty-logging.properties
@@ -0,0 +1,6 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+#org.eclipse.jetty.LEVEL=DEBUG
+#org.eclipse.jetty.client.LEVEL=DEBUG
+#org.eclipse.jetty.http2.LEVEL=DEBUG
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.client.LEVEL=DEBUG
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/keystore.jks b/tests/test-http-client-transport/src/test/resources/keystore.jks
similarity index 100%
rename from jetty-spdy/spdy-http-client-transport/src/test/resources/keystore.jks
rename to tests/test-http-client-transport/src/test/resources/keystore.jks
Binary files differ
diff --git a/jetty-spdy/spdy-http-client-transport/src/test/resources/truststore.jks b/tests/test-http-client-transport/src/test/resources/truststore.jks
similarity index 100%
rename from jetty-spdy/spdy-http-client-transport/src/test/resources/truststore.jks
rename to tests/test-http-client-transport/src/test/resources/truststore.jks
Binary files differ
diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml
index 6095e6b..8095ccc 100644
--- a/tests/test-integration/pom.xml
+++ b/tests/test-integration/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-integration</artifactId>
@@ -31,6 +31,8 @@
     <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir>
     <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir>
     <test-dist-dir>${project.build.directory}/test-dist</test-dist-dir>
+    <bundle-symbolic-name>${project.groupId}.integrations</bundle-symbolic-name>
+
   </properties>
   <build>
     <plugins>
@@ -117,13 +119,20 @@
       <type>pom</type>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-http</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty.toolchain</groupId>
       <artifactId>jetty-test-helper</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
-      <artifactId>jetty-jsp</artifactId>
+      <artifactId>apache-jsp</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -133,5 +142,17 @@
       <type>war</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.alpn</groupId>
+      <artifactId>alpn-api</artifactId>
+      <version>${alpn.api.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-alpn-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java
index 6dde8f6..4cd504b 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/DefaultHandlerTest.java
@@ -18,7 +18,8 @@
 
 package org.eclipse.jetty.test;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -26,7 +27,6 @@
 import java.net.Socket;
 import java.net.URL;
 import java.net.URLConnection;
-import java.util.List;
 
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.http.HttpStatus;
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/HttpInputIntegrationTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/HttpInputIntegrationTest.java
new file mode 100644
index 0000000..958ed1e
--- /dev/null
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/HttpInputIntegrationTest.java
@@ -0,0 +1,718 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.test;
+
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.SSLSocket;
+import javax.servlet.AsyncContext;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpChannelState;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
+import org.eclipse.jetty.server.NetworkConnector;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.hamcrest.Matchers;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class HttpInputIntegrationTest
+{
+    
+    enum Mode { BLOCKING, ASYNC_DISPATCHED, ASYNC_OTHER_DISPATCHED, ASYNC_OTHER_WAIT }
+    public final static String EOF = "__EOF__";
+    public final static String DELAY = "__DELAY__";
+    public final static String ABORT = "__ABORT__";
+    
+    private static Server __server;
+    private static HttpConfiguration __config;
+    private static HttpConfiguration __sslConfig;
+    private static SslContextFactory __sslContextFactory;
+    
+    @BeforeClass
+    public static void beforeClass() throws Exception
+    {
+        __config = new HttpConfiguration();
+        
+        __server = new Server();
+        LocalConnector local=new LocalConnector(__server,new HttpConnectionFactory(__config));
+        local.setIdleTimeout(4000);
+        __server.addConnector(local);
+        
+        ServerConnector http = new ServerConnector(__server,new HttpConnectionFactory(__config),new HTTP2CServerConnectionFactory(__config));
+        http.setIdleTimeout(4000);
+        __server.addConnector(http);
+        
+
+        // SSL Context Factory for HTTPS and HTTP/2
+        String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution");
+        __sslContextFactory = new SslContextFactory();
+        __sslContextFactory.setKeyStorePath(jetty_distro + "/../../../jetty-server/src/test/config/etc/keystore");
+        __sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
+        __sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
+
+        // HTTPS Configuration
+        __sslConfig = new HttpConfiguration(__config);
+        __sslConfig.addCustomizer(new SecureRequestCustomizer());
+
+        // HTTP/1 Connection Factory
+        HttpConnectionFactory h1=new HttpConnectionFactory(__sslConfig);
+        /* TODO
+        // HTTP/2 Connection Factory
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(__sslConfig);
+        
+        NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(h1.getProtocol());
+        */
+        
+        // SSL Connection Factory
+        SslConnectionFactory ssl = new SslConnectionFactory(__sslContextFactory,h1.getProtocol() /*TODO alpn.getProtocol()*/);
+        
+        // HTTP/2 Connector
+        ServerConnector http2 = new ServerConnector(__server,ssl,/*TODO alpn,h2,*/ h1);
+        http2.setIdleTimeout(4000);
+        __server.addConnector(http2);
+        
+        
+        ServletContextHandler context = new ServletContextHandler(__server,"/ctx");
+        ServletHolder holder = new ServletHolder(new TestServlet());
+        holder.setAsyncSupported(true);
+        context.addServlet(holder,"/*");
+        
+        
+        
+        __server.start();
+    }
+    
+    @AfterClass
+    public static void afterClass() throws Exception
+    {
+        __server.stop();
+    }
+    
+    interface TestClient
+    {        
+        /* ------------------------------------------------------------ */
+        /**
+         * @param uri The URI to test, typically /ctx/test?mode=THE_MODE
+         * @param delayMs the delay in MS to use.
+         * @param delayInFrame If null, send the request with no delays, if FALSE then send with delays between frames, if TRUE send with delays within frames
+         * @param contentLength The content length header to send.
+         * @param content The content to send, with each string to be converted to a chunk or a frame 
+         * @return The response received in HTTP/1 format
+         * @throws Exception
+         */
+        String send(String uri,int delayMs, Boolean delayInFrame, int contentLength, List<String> content) throws Exception; 
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data()
+    {
+        List<Object[]> tests = new ArrayList<>();
+        
+
+        // TODO other client types!
+        // test with the following clients/protocols:
+        //   + Local
+        //   + HTTP/1
+        //   + SSL + HTTP/1
+        //   + HTTP/2
+        //   + SSL + HTTP/2
+        //   + FASTCGI
+        for (Class<? extends TestClient> client : new Class[]{LocalClient.class,H1Client.class,H1SClient.class})
+        {
+
+            // test async actions that are run:
+            //   + By a thread in a container callback
+            //   + By another thread while a container callback is active
+            //   + By another thread while no container callback is active
+            for (Mode mode: Mode.values())
+            {
+
+                // test servlet dispatch with:
+                //   + Delayed dispatch on
+                //   + Delayed dispatch off
+                for (Boolean dispatch : new Boolean[]{false,true})
+                {
+                    // test send with 
+                    //   + No delays between frames
+                    //   + Delays between frames
+                    //   + Delays within frames!
+                    for (Boolean delayWithinFrame : new Boolean[]{null,false,true})
+                    {
+                        // test content 
+                        // + unknown length + EOF
+                        // + unknown length + content + EOF
+                        // + unknown length + content + content + EOF
+                        
+                        // + known length + EOF
+                        // + known length + content + EOF
+                        // + known length + content + content + EOF
+                        
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,0,-1,new String[]{}});
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,8,-1,new String[]{"content0"}});
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,16,-1,new String[]{"content0","CONTENT1"}});
+                        
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,0,0,new String[]{}});
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,8,8,new String[]{"content0"}});
+                        tests.add(new Object[]{tests.size(),client,mode,dispatch,delayWithinFrame,200,16,16,new String[]{"content0","CONTENT1"}});
+                        
+                    }
+                }
+            }
+        }
+        return tests;
+    }
+    
+
+    final int _id;
+    final Class<? extends TestClient> _client;
+    final Mode _mode;
+    final Boolean _delay;
+    final int _status;
+    final int _read;
+    final int _length;
+    final List<String> _send;
+    
+    public HttpInputIntegrationTest(int id,Class<? extends TestClient> client, Mode mode,boolean dispatch,Boolean delay,int status,int read,int length,String... send)
+    {
+        _id=id;
+        _client=client;
+        _mode=mode;
+        __config.setDelayDispatchUntilContent(dispatch);
+        _delay=delay;
+        _status=status;
+        _read=read;
+        _length=length;
+        _send = Arrays.asList(send);
+    }
+    
+    
+    private static void runmode(Mode mode,final Request request, final Runnable test)
+    {
+        switch(mode)
+        {
+            case ASYNC_DISPATCHED:
+            {
+                test.run();
+                break;
+            }   
+            case ASYNC_OTHER_DISPATCHED:
+            {
+                final CountDownLatch latch = new CountDownLatch(1);
+                new Thread()
+                {
+                    @Override
+                    public void run()
+                    {
+                        try
+                        {
+                            test.run();
+                        }
+                        finally
+                        {
+                            latch.countDown();
+                        }
+                    }
+                }.start();
+                // prevent caller returning until other thread complete
+                try
+                {
+                    if (!latch.await(5,TimeUnit.SECONDS))
+                        Assert.fail();
+                }
+                catch(Exception e)
+                {
+                    Assert.fail();
+                }
+                break;
+            }   
+            case ASYNC_OTHER_WAIT:
+            {
+                final CountDownLatch latch = new CountDownLatch(1);
+                final HttpChannelState.State S=request.getHttpChannelState().getState();
+                new Thread()
+                {
+                    @Override
+                    public void run()
+                    {
+                        try
+                        {
+                            if (!latch.await(5,TimeUnit.SECONDS))
+                                Assert.fail();
+                            
+                            // Spin until state change
+                            HttpChannelState.State s=request.getHttpChannelState().getState();
+                            while(request.getHttpChannelState().getState()==S )
+                            {
+                                Thread.yield();
+                                s=request.getHttpChannelState().getState();
+                            }
+                            test.run();
+                        }
+                        catch (Exception e)
+                        {
+                            e.printStackTrace();
+                        }
+                    }
+                }.start();
+                // ensure other thread running before trying to return
+                latch.countDown();
+                break;
+            }
+                
+            default:
+                throw new IllegalStateException();
+        }
+        
+    }
+    
+    @Test
+    public void testOne() throws Exception
+    {
+        System.err.printf("[%d] TEST   c=%s, m=%s, delayDispatch=%b delayInFrame=%s content-length:%d expect=%d read=%d content:%s%n",_id,_client.getSimpleName(),_mode,__config.isDelayDispatchUntilContent(),_delay,_length,_status,_read,_send);
+
+        TestClient client=_client.newInstance();
+        String response = client.send("/ctx/test?mode="+_mode,50,_delay,_length,_send);
+        
+        int sum=0;
+        for (String s:_send)
+            for (char c : s.toCharArray())
+                sum+=c;
+        
+        assertThat(response,startsWith("HTTP"));
+        assertThat(response,Matchers.containsString(" "+_status+" "));
+        assertThat(response,Matchers.containsString("read="+_read));
+        assertThat(response,Matchers.containsString("sum="+sum));
+    }
+    
+    @Test
+    public void testStress() throws Exception
+    {
+        System.err.printf("[%d] STRESS c=%s, m=%s, delayDispatch=%b delayInFrame=%s content-length:%d expect=%d read=%d content:%s%n",_id,_client.getSimpleName(),_mode,__config.isDelayDispatchUntilContent(),_delay,_length,_status,_read,_send);
+
+        int sum=0;
+        for (String s:_send)
+            for (char c : s.toCharArray())
+                sum+=c;
+        final int summation=sum;
+        
+        
+        final int threads=10;
+        final int loops=10;
+        
+        final AtomicInteger count = new AtomicInteger(0);
+        Thread[] t = new Thread[threads];
+        
+        Runnable run = new Runnable()
+        {
+            @Override 
+            public void run()
+            {
+                try
+                {
+                    TestClient client=_client.newInstance();
+                    for (int j=0;j<loops;j++)
+                    {
+                        String response = client.send("/ctx/test?mode="+_mode,10,_delay,_length,_send);
+                        assertThat(response,startsWith("HTTP"));
+                        assertThat(response,Matchers.containsString(" "+_status+" "));
+                        assertThat(response,Matchers.containsString("read="+_read));
+                        assertThat(response,Matchers.containsString("sum="+summation));
+                        count.incrementAndGet();
+                    }
+                }
+                catch(Exception e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        };
+        
+        for (int i=0;i<threads;i++)
+        {
+            t[i]=new Thread(run);
+            t[i].start();
+        }
+        for (int i=0;i<threads;i++)
+            t[i].join();
+        
+        assertThat(count.get(),Matchers.is(threads*loops));
+    }
+    
+    
+    public static class TestServlet extends HttpServlet
+    {
+        String expected ="content0CONTENT1";
+        
+        @Override
+        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException
+        {
+            final Mode mode = Mode.valueOf(req.getParameter("mode"));
+            resp.setContentType("text/plain");
+                        
+            if (mode==Mode.BLOCKING)
+            {
+                try
+                {
+                    String content = IO.toString(req.getInputStream());
+                    resp.setStatus(200);
+                    resp.setContentType("text/plain");
+                    resp.getWriter().println("read="+content.length());
+                    int sum = 0;
+                    for (char c:content.toCharArray())
+                        sum+=c;
+                    resp.getWriter().println("sum="+sum);
+                }
+                catch(Exception e)
+                {
+                    e.printStackTrace();
+                    resp.setStatus(500);
+                    resp.getWriter().println("read="+e);
+                    resp.getWriter().println("sum=-1");
+                }
+            }
+            else
+            {
+                // we are asynchronous
+                final AsyncContext context = req.startAsync();
+                context.setTimeout(10000);
+                final ServletInputStream in = req.getInputStream();
+                final Request request = Request.getBaseRequest(req);
+                final AtomicInteger read = new AtomicInteger(0);
+                final AtomicInteger sum = new AtomicInteger(0);
+
+                runmode(mode,request,new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        in.setReadListener(new ReadListener()
+                        {
+                            @Override
+                            public void onError(Throwable t)
+                            {
+                                t.printStackTrace();
+                                try
+                                {
+                                    resp.sendError(500);
+                                }
+                                catch (IOException e)
+                                {
+                                    e.printStackTrace();
+                                    throw new RuntimeException(e);
+                                }
+                                context.complete();
+                            }
+
+                            @Override
+                            public void onDataAvailable() throws IOException
+                            {
+                                runmode(mode,request,new Runnable()
+                                {
+                                    @Override
+                                    public void run()
+                                    {
+                                        while(in.isReady() && !in.isFinished())
+                                        {
+                                            try
+                                            {
+                                                int b = in.read();
+                                                if (b<0)
+                                                    return;
+                                                sum.addAndGet(b);
+                                                int i=read.getAndIncrement();
+                                                if (b!=expected.charAt(i))
+                                                {
+                                                    System.err.printf("XXX '%c'!='%c' at %d%n",expected.charAt(i),(char)b,i);
+                                                    System.err.println("    "+request.getHttpChannel());
+                                                    System.err.println("    "+request.getHttpChannel().getHttpTransport());
+                                                }
+                                                
+                                            }
+                                            catch (IOException e)
+                                            {
+                                                onError(e);
+                                            }
+                                        }
+                                    }
+                                });
+                            }
+
+                            @Override
+                            public void onAllDataRead() throws IOException
+                            {
+                                resp.setStatus(200);
+                                resp.setContentType("text/plain");
+                                resp.getWriter().println("read="+read.get());
+                                resp.getWriter().println("sum="+sum.get());
+                                context.complete();
+                            }
+                        });
+                    }
+                });
+            }
+        }
+    }
+    
+
+    public static class LocalClient implements TestClient
+    {
+        StringBuilder flushed = new StringBuilder();
+        @Override
+        public String send(String uri,int delayMs, Boolean delayInFrame,int contentLength, List<String> content) throws Exception
+        {
+            LocalConnector connector = __server.getBean(LocalConnector.class);
+
+            StringBuilder buffer = new StringBuilder();
+            buffer.append("GET ").append(uri).append(" HTTP/1.1\r\n");
+            buffer.append("Host: localhost\r\n");
+            buffer.append("Connection: close\r\n");
+
+            LocalEndPoint local = connector.executeRequest("");
+            
+            flush(local,buffer,delayMs,delayInFrame,true);
+
+            boolean chunked=contentLength<0;
+            if (chunked)
+                buffer.append("Transfer-Encoding: chunked\r\n");
+            else
+                buffer.append("Content-Length: ").append(contentLength).append("\r\n");
+
+            if (contentLength>0)
+                buffer.append("Content-Type: text/plain\r\n");
+            buffer.append("\r\n");
+
+            flush(local,buffer,delayMs,delayInFrame,false);
+
+            for (String c : content)
+            {
+                if (chunked)
+                {
+                    buffer.append(Integer.toHexString(c.length())).append("\r\n");
+                    flush(local,buffer,delayMs,delayInFrame,true);
+                }
+
+                buffer.append(c.substring(0,1));
+                flush(local,buffer,delayMs,delayInFrame,true);
+                buffer.append(c.substring(1));
+                if (chunked)
+                    buffer.append("\r\n"); 
+                flush(local,buffer,delayMs,delayInFrame,false);
+            }
+
+            if (chunked)
+            {
+                buffer.append("0");
+                flush(local,buffer,delayMs,delayInFrame,true);
+                buffer.append("\r\n\r\n");
+            }
+
+            flush(local,buffer);
+            local.waitUntilClosed();
+            return local.takeOutputString();
+        }
+          
+
+        private void flush(LocalEndPoint local, StringBuilder buffer,int delayMs, Boolean delayInFrame, boolean inFrame) throws Exception
+        {
+            // Flush now if we should delay
+            if (delayInFrame!=null && delayInFrame.equals(inFrame))
+            {
+                flush(local,buffer);
+                Thread.sleep(delayMs);
+            }
+        }
+        
+        private void flush(final LocalEndPoint local, StringBuilder buffer) throws Exception
+        {
+            final String flush=buffer.toString();
+            buffer.setLength(0);
+            flushed.append(flush);
+            local.addInputAndExecute(BufferUtil.toBuffer(flush));
+        }
+
+    }
+
+    public static class H1Client implements TestClient
+    {
+        NetworkConnector _connector;
+
+        public H1Client()
+        {
+            for (Connector c:__server.getConnectors())
+            {
+                if (c instanceof NetworkConnector && c.getDefaultConnectionFactory().getProtocol().equals(HttpVersion.HTTP_1_1.asString()))
+                {
+                    _connector=(NetworkConnector)c;
+                    break;
+                }
+            }
+        }
+
+        @Override
+        public String send(String uri, int delayMs, Boolean delayInFrame,int contentLength, List<String> content) throws Exception
+        {
+            int port=_connector.getLocalPort();
+            
+            try (Socket client = newSocket("localhost", port))
+            {
+                client.setSoTimeout(5000);
+                client.setTcpNoDelay(true);
+                client.setSoLinger(true,1);
+                OutputStream out = client.getOutputStream();
+
+                StringBuilder buffer = new StringBuilder();
+                buffer.append("GET ").append(uri).append(" HTTP/1.1\r\n");
+                buffer.append("Host: localhost:").append(port).append("\r\n");
+                buffer.append("Connection: close\r\n");
+
+                flush(out,buffer,delayMs,delayInFrame,true);
+
+                boolean chunked=contentLength<0;
+                if (chunked)
+                    buffer.append("Transfer-Encoding: chunked\r\n");
+                else
+                    buffer.append("Content-Length: ").append(contentLength).append("\r\n");
+                    
+                if (contentLength>0)
+                    buffer.append("Content-Type: text/plain\r\n");
+                buffer.append("\r\n");
+
+                flush(out,buffer,delayMs,delayInFrame,false);
+                
+                for (String c : content)
+                {
+                    if (chunked)
+                    {
+                        buffer.append(Integer.toHexString(c.length())).append("\r\n");
+                       flush(out,buffer,delayMs,delayInFrame,true);
+                    }
+                    
+                    buffer.append(c.substring(0,1));
+                    flush(out,buffer,delayMs,delayInFrame,true);
+                    buffer.append(c.substring(1));
+                    flush(out,buffer,delayMs,delayInFrame,false);
+                    if (chunked)
+                        buffer.append("\r\n"); 
+                }
+
+                if (chunked)
+                {
+                    buffer.append("0");
+                    flush(out,buffer,delayMs,delayInFrame,true);
+                    buffer.append("\r\n\r\n");
+                }
+                
+                flush(out,buffer);
+                
+                return IO.toString(client.getInputStream());
+            }
+            
+        }
+
+        private void flush(OutputStream out, StringBuilder buffer, int delayMs, Boolean delayInFrame, boolean inFrame) throws Exception
+        {
+            // Flush now if we should delay
+            if (delayInFrame!=null && delayInFrame.equals(inFrame))
+            {
+                flush(out,buffer);
+                Thread.sleep(delayMs);
+            }
+        }
+        
+        private void flush(OutputStream out, StringBuilder buffer) throws Exception
+        {
+            String flush=buffer.toString();
+            buffer.setLength(0);
+            out.write(flush.getBytes(StandardCharsets.ISO_8859_1));
+            out.flush();
+        }
+
+        public Socket newSocket(String host, int port) throws IOException
+        {
+            return new Socket(host, port);
+        }
+    }
+    
+    public static class H1SClient extends H1Client
+    {
+        public H1SClient()
+        {
+            for (Connector c:__server.getConnectors())
+            {
+                if (c instanceof NetworkConnector && c.getDefaultConnectionFactory().getProtocol().equals("SSL"))
+                {
+                    _connector=(NetworkConnector)c;
+                    break;
+                }
+            }
+        }
+
+        public Socket newSocket(String host, int port) throws IOException
+        {
+            SSLSocket socket = __sslContextFactory.newSslSocket();
+            socket.connect(new InetSocketAddress(Inet4Address.getByName(host),port));
+            return socket;
+        }
+    }
+
+    
+}
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/FakeJspServlet.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/FakeJspServlet.java
index e6c3ed5..47548bf 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/FakeJspServlet.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/FakeJspServlet.java
@@ -20,7 +20,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.net.URISyntaxException;
 import java.net.URL;
 
 import javax.servlet.ServletException;
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java
index a9d2370..75c301a 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithAliasesTest.java
@@ -18,7 +18,9 @@
 
 package org.eclipse.jetty.test.jsp;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java
index 1b57b01..299a096 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspAndDefaultWithoutAliasesTest.java
@@ -18,7 +18,9 @@
 
 package org.eclipse.jetty.test.jsp;
 
-import static org.hamcrest.Matchers.*;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java
index 3097bcf..4ebb0c5 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java
@@ -18,15 +18,14 @@
 
 package org.eclipse.jetty.test.rfcs;
 
+import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.*;
-import static org.junit.matchers.JUnitMatchers.*;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.Socket;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.List;
@@ -42,7 +41,6 @@
 import org.eclipse.jetty.toolchain.test.FS;
 import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
 import org.eclipse.jetty.toolchain.test.StringAssert;
-import org.eclipse.jetty.util.MultiPartInputStreamParser;
 import org.hamcrest.Matchers;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -146,7 +144,7 @@
 
         // Test formatting
         fields.putDateField("Date",expected.getTime().getTime());
-        Assert.assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.getStringField("Date"));
+        Assert.assertEquals("3.3.1 RFC 822 preferred","Sun, 06 Nov 1994 08:49:37 GMT",fields.get("Date"));
     }
 
     /**
@@ -1159,12 +1157,12 @@
         req4.append("\n");
 
         HttpTester.Response response = http.request(req4);
-
+        
         String specId = "10.3 Redirection HTTP/1.1 w/content";
-        assertEquals(specId,HttpStatus.FOUND_302, response.getStatus());
-        assertEquals(specId,server.getScheme() + "://localhost/tests/R2.txt", response.get("Location"));
-        assertEquals(specId,"close", response.get("Connection"));
-        assertTrue(specId,response.get("Content-Length") == null);
+        assertThat(specId + " [status]",response.getStatus(),is(HttpStatus.FOUND_302));
+        assertThat(specId + " [location]",response.get("Location"),is(server.getScheme() + "://localhost/tests/R2.txt"));
+        assertThat(specId + " [connection]",response.get("Connection"),is("close"));
+        assertThat(specId + " [content-length]",response.get("Content-Length"), nullValue());
     }
 
     /**
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java
index 4e69693..4e06d74 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java
@@ -525,7 +525,7 @@
         // Do a dry run first to get the exact command line for Jetty process
         commands.add("-jar");
         commands.add("start.jar");
-        commands.add("jetty.port=0");
+        commands.add("jetty.http.port=0");
         if (_debug)
         {
             commands.add("-D.DEBUG=true");
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java
index d6700d2..70344ff 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java
@@ -178,7 +178,6 @@
 
         // Find the active server port.
         this._serverPort = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort();
-        System.err.println("Server Port="+_serverPort);
         Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + _serverPort + ">",(1 <= this._serverPort) && (this._serverPort <= 65535));
     }
 
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java
index 8fa6231..344e1cc 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpResponseTesterTest.java
@@ -18,6 +18,10 @@
 
 package org.eclipse.jetty.test.support.rawhttp;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
 import java.io.IOException;
 import java.util.List;
 
@@ -27,10 +31,6 @@
 import org.junit.Assert;
 import org.junit.Test;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertThat;
-
 public class HttpResponseTesterTest
 {
     @Test
@@ -104,21 +104,21 @@
         Assert.assertEquals("Responses.size",3,responses.size());
 
         HttpTester.Response resp1 = responses.get(0);
-        System.err.println(resp1.toString());
+        // System.err.println(resp1.toString());
         Assert.assertEquals(HttpStatus.OK_200, resp1.getStatus());
         Assert.assertEquals("text/plain", resp1.get("Content-Type"));
         Assert.assertTrue(resp1.getContent().contains("ABCDEFGHIJKLMNOPQRSTTUVWXYZ\n"));
         assertThat(resp1.get("Connection"),is(not("close")));
 
         HttpTester.Response resp2 = responses.get(1);
-        System.err.println(resp2.toString());
+        // System.err.println(resp2.toString());
         Assert.assertEquals(HttpStatus.OK_200, resp2.getStatus());
         Assert.assertEquals("text/plain", resp2.get("Content-Type"));
         Assert.assertTrue(resp2.getContent().contains("Host=Default\nResource=R1\n"));
         assertThat(resp2.get("Connection"),is(not("close")));
 
         HttpTester.Response resp3 = responses.get(2);
-        System.err.println(resp3.toString());
+        // System.err.println(resp3.toString());
         Assert.assertEquals(HttpStatus.OK_200, resp3.getStatus());
         Assert.assertEquals("text/plain", resp3.get("Content-Type"));
         Assert.assertTrue(resp3.getContent().contains("Host=Default\nResource=R2\n"));
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java
index 66be35a..88347fd 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/rawhttp/HttpsSocketImpl.java
@@ -29,8 +29,6 @@
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
diff --git a/tests/test-integration/src/test/resources/DefaultHandler.xml b/tests/test-integration/src/test/resources/DefaultHandler.xml
index 644e7f9..a050408 100644
--- a/tests/test-integration/src/test/resources/DefaultHandler.xml
+++ b/tests/test-integration/src/test/resources/DefaultHandler.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the Jetty Server                                      -->
diff --git a/tests/test-integration/src/test/resources/NIOHttp.xml b/tests/test-integration/src/test/resources/NIOHttp.xml
index c766d10..d58befb 100644
--- a/tests/test-integration/src/test/resources/NIOHttp.xml
+++ b/tests/test-integration/src/test/resources/NIOHttp.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
@@ -20,9 +20,8 @@
             </Item>
           </Array>
         </Arg>
-        <Set name="host"><Property name="jetty.host" /></Set>
-        <Set name="port">0</Set>
-        <Set name="idleTimeout"><Property name="http.timeout" default="30000"/></Set>
+        <Set name="host"><Property name="jetty.http.host" /></Set>
+        <Set name="idleTimeout"><Property name="jetty.http.idleTimeout" default="30000"/></Set>
       </New>
     </Arg>
   </Call>
diff --git a/tests/test-integration/src/test/resources/NIOHttps.xml b/tests/test-integration/src/test/resources/NIOHttps.xml
index 5e90fdb..5146752 100644
--- a/tests/test-integration/src/test/resources/NIOHttps.xml
+++ b/tests/test-integration/src/test/resources/NIOHttps.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
@@ -25,8 +25,7 @@
               </Item>
             </Array>
           </Arg>
-          <Set name="host"><Property name="jetty.host" /></Set>
-          <Set name="port">0</Set>
+          <Set name="host"><Property name="jetty.http.host" /></Set>
           <Set name="idleTimeout">30000</Set>
         </New>
     </Arg>
diff --git a/tests/test-integration/src/test/resources/RFC2616Base.xml b/tests/test-integration/src/test/resources/RFC2616Base.xml
index 2c300d1..a35088f 100644
--- a/tests/test-integration/src/test/resources/RFC2616Base.xml
+++ b/tests/test-integration/src/test/resources/RFC2616Base.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the Jetty Server                                      -->
diff --git a/tests/test-integration/src/test/resources/RFC2616_Filters.xml b/tests/test-integration/src/test/resources/RFC2616_Filters.xml
index a798bfd..73dbb38 100644
--- a/tests/test-integration/src/test/resources/RFC2616_Filters.xml
+++ b/tests/test-integration/src/test/resources/RFC2616_Filters.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
 
diff --git a/tests/test-integration/src/test/resources/RFC2616_Redirects.xml b/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
index a3cc7a3..a777ad1 100644
--- a/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
+++ b/tests/test-integration/src/test/resources/RFC2616_Redirects.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
     <!-- =========================================================== -->
diff --git a/tests/test-integration/src/test/resources/ssl.xml b/tests/test-integration/src/test/resources/ssl.xml
index 84de070..eecff79 100644
--- a/tests/test-integration/src/test/resources/ssl.xml
+++ b/tests/test-integration/src/test/resources/ssl.xml
@@ -1,9 +1,9 @@
 <Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
-  <Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.keystore" default="keystore"/></Set>
-  <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
-  <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
-  <Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.truststore" default="keystore"/></Set>
-  <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
+  <Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.keyStorePath" default="keystore"/></Set>
+  <Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
+  <Set name="KeyManagerPassword"><Property name="jetty.sslContext.keyManagerPassword" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
+  <Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.trustStorePath" default="keystore"/></Set>
+  <Set name="TrustStorePassword"><Property name="jetty.sslContext.trustStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
   <Set name="EndpointIdentificationAlgorithm"></Set>
   <Set name="ExcludeCipherSuites">
     <Array type="String">
diff --git a/tests/test-integration/src/test/resources/webapp-contexts/RFC2616/rfc2616-webapp.xml b/tests/test-integration/src/test/resources/webapp-contexts/RFC2616/rfc2616-webapp.xml
index 74d2fe9..36e624f 100644
--- a/tests/test-integration/src/test/resources/webapp-contexts/RFC2616/rfc2616-webapp.xml
+++ b/tests/test-integration/src/test/resources/webapp-contexts/RFC2616/rfc2616-webapp.xml
@@ -1,8 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
-	<Set name="contextPath">/rfc2616-webapp</Set>
-	<Set name="war">
-		<Property name="test.webapps" default="." />/test-webapp-rfc2616.war
-	</Set>
+  <Set name="contextPath">/rfc2616-webapp</Set>
+  <Set name="war"><Property name="test.webapps" default="." />/test-webapp-rfc2616.war</Set>
+  <Set name="gzipHandler">
+    <New class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
+      <Set name="minGzipSize">1024</Set>
+    </New>
+  </Set>
 </Configure>
diff --git a/tests/test-integration/src/test/resources/webdefault.xml b/tests/test-integration/src/test/resources/webdefault.xml
index d87a7e2..d54d76f 100644
--- a/tests/test-integration/src/test/resources/webdefault.xml
+++ b/tests/test-integration/src/test/resources/webdefault.xml
@@ -1,113 +1,142 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!-- ===================================================================== -->
-<!-- This file contains the default descriptor for web applications.       -->
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<!-- The intent of this descriptor is to include jetty specific or common  -->
-<!-- configuration for all webapps.   If a context has a webdefault.xml    -->
-<!-- descriptor, it is applied before the contexts own web.xml file        -->
-<!--                                                                       -->
-<!-- A context may be assigned a default descriptor by:                    -->
-<!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
-<!--  + Passed an arg to addWebApplications                                -->
-<!--                                                                       -->
-<!-- This file is used both as the resource within the jetty.jar (which is -->
-<!-- used as the default if no explicit defaults descriptor is set) and it -->
-<!-- is copied to the etc directory of the Jetty distro and explicitly     -->
-<!-- by the jetty.xml file.                                                -->
-<!--                                                                       -->
-<!-- ===================================================================== -->
 <web-app 
-   xmlns="http://java.sun.com/xml/ns/javaee" 
+   xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
-   metadata-complete="true"
-   version="2.5"> 
+   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+   metadata-complete="false"
+   version="3.1"> 
+
+  <!-- ===================================================================== -->
+  <!-- This file contains the default descriptor for web applications.       -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+  <!-- The intent of this descriptor is to include jetty specific or common  -->
+  <!-- configuration for all webapps.   If a context has a webdefault.xml    -->
+  <!-- descriptor, it is applied before the context's own web.xml file       -->
+  <!--                                                                       -->
+  <!-- A context may be assigned a default descriptor by calling             -->
+  <!-- WebAppContext.setDefaultsDescriptor(String).                          -->
+  <!--                                                                       -->
+  <!-- This file is present in the jetty-webapp.jar, and is used as the      -->
+  <!-- defaults descriptor if no other is explicitly set on a context.       -->
+  <!--                                                                       -->
+  <!-- A copy of this file is also placed into the $JETTY_HOME/etc dir of    -->
+  <!-- the  distribution, and is referenced by some of the other xml files,  -->
+  <!-- eg the jetty-deploy.xml file.                                         -->
+  <!-- ===================================================================== -->
 
   <description>
     Default web.xml file.  
     This file is applied to a Web application before it's own WEB_INF/web.xml file
   </description>
 
+  <!-- ==================================================================== -->
+  <!-- Removes static references to beans from javax.el.BeanELResolver to   -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.ELContextCleaner</listener-class>
+  </listener>
+  
+  <!-- ==================================================================== -->
+  <!-- Removes static cache of Methods from java.beans.Introspector to      -->
+  <!-- ensure webapp classloader can be released on undeploy                -->
+  <!-- ==================================================================== -->  
+  <listener>
+   <listener-class>org.eclipse.jetty.servlet.listener.IntrospectorCleaner</listener-class>
+  </listener>
+  
 
   <!-- ==================================================================== -->
   <!-- Context params to control Session Cookies                            -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- UNCOMMENT TO ACTIVATE
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
-    <param-value>127.0.0.1</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
-    <param-value>/</param-value>
-  </context-param>
-
-  <context-param>
-    <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
-    <param-value>-1</param-value>
-  </context-param>
+  <!--
+    UNCOMMENT TO ACTIVATE 
+    <context-param> 
+      <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> 
+      <param-value>127.0.0.1</param-value> 
+    </context-param> 
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
+      <param-value>/</param-value>
+    </context-param>
+    <context-param>
+      <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
+      <param-value>-1</param-value>
+    </context-param>
   -->
 
-
   <!-- ==================================================================== -->
   <!-- The default servlet.                                                 -->
   <!-- This servlet, normally mapped to /, provides the handling for static -->
   <!-- content, OPTIONS and TRACE methods for the context.                  -->
   <!-- The following initParameters are supported:                          -->
-  <!--                                                                      -->
-  <!--   acceptRanges     If true, range requests and responses are         -->
-  <!--                    supported                                         -->
-  <!--                                                                      -->
-  <!--   dirAllowed       If true, directory listings are returned if no    -->
-  <!--                    welcome file is found. Else 403 Forbidden.        -->
-  <!--                                                                      -->
-  <!--   welcomeServlets  If true, attempt to dispatch to welcome files     -->
-  <!--                    that are servlets, if no matching static          -->
-  <!--                    resources can be found.                           -->
-  <!--                                                                      -->
-  <!--   redirectWelcome  If true, redirect welcome file requests           -->
-  <!--                    else use request dispatcher forwards              -->
-  <!--                                                                      -->
-  <!--   gzip             If set to true, then static content will be served--> 
-  <!--                    as gzip content encoded if a matching resource is -->
-  <!--                    found ending with ".gz"                           -->
-  <!--                                                                      -->
-  <!--   resoureBase      Can be set to replace the context resource base   -->
-  <!--                                                                      -->
-  <!--   relativeResourceBase                                               -->
-  <!--                    Set with a pathname relative to the base of the   -->
-  <!--                    servlet context root. Useful for only serving     -->
-  <!--                    static content from only specific subdirectories. -->
-  <!--                                                                      -->
-  <!--   useFileMappedBuffer                                                -->
-  <!--                    If set to true (the default), a  memory mapped    -->
-  <!--                    file buffer will be used to serve static content  -->
-  <!--                    when using an NIO connector. Setting this value   -->
-  <!--                    to false means that a direct buffer will be used  -->
-  <!--                    instead. If you are having trouble with Windows   -->
-  <!--                    file locking, set this to false.                  -->
-  <!--                                                                      -->
-  <!--  cacheControl      If set, all static content will have this value   -->
-  <!--                    set as the cache-control header.                  -->
-  <!--                                                                      -->
-  <!--  maxCacheSize      Maximum size of the static resource cache         -->
-  <!--                                                                      -->
-  <!--  maxCachedFileSize Maximum size of any single file in the cache      -->
-  <!--                                                                      -->
-  <!--  maxCachedFiles    Maximum number of files in the cache              -->
-  <!--                                                                      -->
-  <!--  cacheType         "nio", "bio" or "both" to determine the type(s)   -->
-  <!--                    of resource cache. A bio cached buffer may be used-->
-  <!--                    by nio but is not as efficient as a nio buffer.   -->
-  <!--                    An nio cached buffer may not be used by bio.      -->
-  <!--                                                                      -->
-  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!--  
+ *  acceptRanges      If true, range requests and responses are
+ *                    supported
+ *
+ *  dirAllowed        If true, directory listings are returned if no
+ *                    welcome file is found. Else 403 Forbidden.
+ *
+ *  welcomeServlets   If true, attempt to dispatch to welcome files
+ *                    that are servlets, but only after no matching static
+ *                    resources could be found. If false, then a welcome
+ *                    file must exist on disk. If "exact", then exact
+ *                    servlet matches are supported without an existing file.
+ *                    Default is true.
+ *
+ *                    This must be false if you want directory listings,
+ *                    but have index.jsp in your welcome file list.
+ *
+ *  redirectWelcome   If true, welcome files are redirected rather than
+ *                    forwarded to.
+ *
+ *  gzip              If set to true, then static content will be served as
+ *                    gzip content encoded if a matching resource is
+ *                    found ending with ".gz"
+ *
+ *  resourceBase      Set to replace the context resource base
+ *
+ *  resourceCache     If set, this is a context attribute name, which the servlet
+ *                    will use to look for a shared ResourceCache instance.
+ *
+ *  relativeResourceBase
+ *                    Set with a pathname relative to the base of the
+ *                    servlet context root. Useful for only serving static content out
+ *                    of only specific subdirectories.
+ *
+ *  pathInfoOnly      If true, only the path info will be applied to the resourceBase
+ *
+ *  stylesheet        Set with the location of an optional stylesheet that will be used
+ *                    to decorate the directory listing html.
+ *
+ *  aliases           If True, aliases of resources are allowed (eg. symbolic
+ *                    links and caps variations). May bypass security constraints.
+ *                    
+ *  etags             If True, weak etags will be generated and handled.
+ *
+ *  maxCacheSize      The maximum total size of the cache or 0 for no cache.
+ *  maxCachedFileSize The maximum size of a file to cache
+ *  maxCachedFiles    The maximum number of files to cache
+ *
+ *  useFileMappedBuffer
+ *                    If set to true, it will use mapped file buffers to serve static content
+ *                    when using an NIO connector. Setting this value to false means that
+ *                    a direct buffer will be used instead of a mapped file buffer.
+ *                    This file sets the value to true.
+ *
+ *  cacheControl      If set, all static content will have this value set as the cache-control
+ *                    header.
+ *
+ -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet>
     <servlet-name>default</servlet-name>
     <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
     <init-param>
+      <param-name>aliases</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
       <param-name>acceptRanges</param-name>
       <param-value>true</param-value>
     </init-param>
@@ -117,8 +146,8 @@
     </init-param>
     <init-param>
       <param-name>welcomeServlets</param-name>
- 	    <param-value>false</param-value>
- 	  </init-param>
+      <param-value>false</param-value>
+    </init-param>
     <init-param>
       <param-name>redirectWelcome</param-name>
       <param-value>false</param-value>
@@ -129,24 +158,30 @@
     </init-param>
     <init-param>
       <param-name>maxCachedFileSize</param-name>
-      <param-value>10000000</param-value>
+      <param-value>200000000</param-value>
     </init-param>
     <init-param>
       <param-name>maxCachedFiles</param-name>
-      <param-value>1000</param-value>
-    </init-param>
-    <init-param>
-      <param-name>cacheType</param-name>
-      <param-value>both</param-value>
+      <param-value>2048</param-value>
     </init-param>
     <init-param>
       <param-name>gzip</param-name>
-      <param-value>true</param-value>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>etags</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
       <param-name>useFileMappedBuffer</param-name>
       <param-value>true</param-value>
-    </init-param>  
+    </init-param>
+    <!--
+    <init-param>
+      <param-name>resourceCache</param-name>
+      <param-value>resourceCache</param-value>
+    </init-param>
+    -->
     <!--
     <init-param>
       <param-name>cacheControl</param-name>
@@ -154,20 +189,23 @@
     </init-param>
     -->
     <load-on-startup>0</load-on-startup>
-  </servlet> 
+  </servlet>
 
-  <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-  
+  <servlet-mapping>
+    <servlet-name>default</servlet-name>
+    <url-pattern>/</url-pattern>
+  </servlet-mapping>
+
 
   <!-- ==================================================================== -->
   <!-- JSP Servlet                                                          -->
-  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- This is the jasper JSP servlet.                                      -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
-  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
-  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
-  <!-- following initialization parameters (default values are in square    -->
-  <!-- brackets):                                                           -->
+  <!-- used by the jsp container to support JSP pages.  Traditionally,      -->
+  <!-- this servlet is mapped to URL pattern "*.jsp".  This servlet         -->
+  <!-- supports the following initialization parameters (default values     -->
+  <!-- are in square brackets):                                             -->
   <!--                                                                      -->
   <!--   checkInterval       If development is false and reloading is true, -->
   <!--                       background compiles are enabled. checkInterval -->
@@ -175,7 +213,7 @@
   <!--                       if a JSP page needs to be recompiled. [300]    -->
   <!--                                                                      -->
   <!--   compiler            Which compiler Ant should use to compile JSP   -->
-  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       pages.  See the Ant documentation for more     -->
   <!--                       information. [javac]                           -->
   <!--                                                                      -->
   <!--   classdebuginfo      Should the class file be compiled with         -->
@@ -236,28 +274,29 @@
   <!--   xpoweredBy          Determines whether X-Powered-By response       -->
   <!--                       header is added by generated servlet  [false]  -->
   <!--                                                                      -->
-  <!-- If you wish to use Jikes to compile JSP pages:                       -->
-  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
-  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
-  <!--   to cause Jikes to emit error messages in a format compatible with  -->
-  <!--   Jasper.                                                            -->
-  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
-  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <servlet id="jsp">
     <servlet-name>jsp</servlet-name>
-    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <servlet-class>org.eclipse.jetty.jsp.JettyJspServlet</servlet-class>
     <init-param>
-        <param-name>logVerbosityLevel</param-name>
-        <param-value>DEBUG</param-value>
+      <param-name>logVerbosityLevel</param-name>
+      <param-value>DEBUG</param-value>
     </init-param>
     <init-param>
-        <param-name>fork</param-name>
-        <param-value>false</param-value>
+      <param-name>fork</param-name>
+      <param-value>false</param-value>
     </init-param>
     <init-param>
-        <param-name>xpoweredBy</param-name>
-        <param-value>false</param-value>
+      <param-name>xpoweredBy</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerTargetVM</param-name>
+      <param-value>1.7</param-value>
+    </init-param>
+    <init-param>
+      <param-name>compilerSourceVM</param-name>
+      <param-value>1.7</param-value>
     </init-param>
     <!--  
     <init-param>
@@ -268,62 +307,22 @@
     <load-on-startup>0</load-on-startup>
   </servlet>
 
-  <servlet-mapping> 
-    <servlet-name>jsp</servlet-name> 
-    <url-pattern>*.jsp</url-pattern> 
+  <servlet-mapping>
+    <servlet-name>jsp</servlet-name>
+    <url-pattern>*.jsp</url-pattern>
     <url-pattern>*.jspf</url-pattern>
     <url-pattern>*.jspx</url-pattern>
     <url-pattern>*.xsp</url-pattern>
-    <url-pattern>*.JSP</url-pattern> 
+    <url-pattern>*.JSP</url-pattern>
     <url-pattern>*.JSPF</url-pattern>
     <url-pattern>*.JSPX</url-pattern>
     <url-pattern>*.XSP</url-pattern>
   </servlet-mapping>
-  
+
+
   <!-- ==================================================================== -->
-  <!-- Dynamic Servlet Invoker.                                             -->
-  <!-- This servlet invokes anonymous servlets that have not been defined   -->
-  <!-- in the web.xml or by other means. The first element of the pathInfo  -->
-  <!-- of a request passed to the envoker is treated as a servlet name for  -->
-  <!-- an existing servlet, or as a class name of a new servlet.            -->
-  <!-- This servlet is normally mapped to /servlet/*                        -->
-  <!-- This servlet support the following initParams:                       -->
-  <!--                                                                      -->
-  <!--  nonContextServlets       If false, the invoker can only load        -->
-  <!--                           servlets from the contexts classloader.    -->
-  <!--                           This is false by default and setting this  -->
-  <!--                           to true may have security implications.    -->
-  <!--                                                                      -->
-  <!--  verbose                  If true, log dynamic loads                 -->
-  <!--                                                                      -->
-  <!--  *                        All other parameters are copied to the     -->
-  <!--                           each dynamic servlet as init parameters    -->
+  <!-- Default session configuration                                        -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
-  <!-- Uncomment for dynamic invocation
-  <servlet>
-    <servlet-name>invoker</servlet-name>
-    <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class>
-    <init-param>
-      <param-name>verbose</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>nonContextServlets</param-name>
-      <param-value>false</param-value>
-    </init-param>
-    <init-param>
-      <param-name>dynamicParam</param-name>
-      <param-value>anyValue</param-value>
-    </init-param>
-    <load-on-startup>0</load-on-startup>
-  </servlet>
-
-  <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
-  -->
-
-
-
-  <!-- ==================================================================== -->
   <session-config>
     <session-timeout>30</session-timeout>
   </session-config>
@@ -331,7 +330,7 @@
   <!-- ==================================================================== -->
   <!-- Default MIME mappings                                                -->
   <!-- The default MIME mappings are provided by the mime.properties        -->
-  <!-- resource in the org.eclipse.jetty.server.jar file.  Additional or modified  -->
+  <!-- resource in the jetty-http.jar file.  Additional or modified         -->
   <!-- mappings may be specified here                                       -->
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <!-- UNCOMMENT TO ACTIVATE
@@ -342,6 +341,8 @@
   -->
 
   <!-- ==================================================================== -->
+  <!-- Default welcome files                                                -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <welcome-file-list>
     <welcome-file>index.html</welcome-file>
     <welcome-file>index.htm</welcome-file>
@@ -349,48 +350,170 @@
   </welcome-file-list>
 
   <!-- ==================================================================== -->
+  <!-- Default locale encodings                                             -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <locale-encoding-mapping-list>
-    <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>     
-    <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
-    <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>   
+    <locale-encoding-mapping>
+      <locale>ar</locale>
+      <encoding>ISO-8859-6</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>be</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>bg</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ca</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>cs</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>da</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>de</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>el</locale>
+      <encoding>ISO-8859-7</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>en</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>es</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>et</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fi</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>fr</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hr</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>hu</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>is</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>it</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>iw</locale>
+      <encoding>ISO-8859-8</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ja</locale>
+      <encoding>Shift_JIS</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ko</locale>
+      <encoding>EUC-KR</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lt</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>lv</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>mk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>nl</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>no</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>pt</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ro</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>ru</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sh</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sk</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sl</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sq</locale>
+      <encoding>ISO-8859-2</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sr</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>sv</locale>
+      <encoding>ISO-8859-1</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>tr</locale>
+      <encoding>ISO-8859-9</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>uk</locale>
+      <encoding>ISO-8859-5</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh</locale>
+      <encoding>GB2312</encoding>
+    </locale-encoding-mapping>
+    <locale-encoding-mapping>
+      <locale>zh_TW</locale>
+      <encoding>Big5</encoding>
+    </locale-encoding-mapping>
   </locale-encoding-mapping-list>
-  
+
+  <!-- ==================================================================== -->
+  <!-- Disable TRACE method with security constraint                        -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
   <security-constraint>
     <web-resource-collection>
       <web-resource-name>Disable TRACE</web-resource-name>
@@ -399,6 +522,13 @@
     </web-resource-collection>
     <auth-constraint/>
   </security-constraint>
-  
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Enable everything but TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method-omission>TRACE</http-method-omission>
+    </web-resource-collection>
+  </security-constraint>
+
 </web-app>
 
diff --git a/tests/test-jmx/jmx-webapp-it/pom.xml b/tests/test-jmx/jmx-webapp-it/pom.xml
index 1a482dd..71df1da 100644
--- a/tests/test-jmx/jmx-webapp-it/pom.xml
+++ b/tests/test-jmx/jmx-webapp-it/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-jmx-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>jmx-webapp-it</artifactId>
diff --git a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java
index eb67f06..56bec0f 100644
--- a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java
+++ b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java
@@ -18,17 +18,16 @@
 
 package org.eclipse.jetty.test.jmx;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
 
 import java.io.IOException;
 
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanException;
 import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
-import javax.management.ReflectionException;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXServiceURL;
@@ -81,7 +80,7 @@
         ObjectName serverName = new ObjectName("org.eclipse.jetty.server:type=server,id=0");
         String version = getStringAttribute(serverName,"version");
         System.err.println("Running version: " + version);
-        assertThat("Version",version,startsWith("9.2."));
+        assertThat("Version",version,startsWith("9.3."));
     }
 
     @Test
diff --git a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java
index 8e76ac1..fb104f9 100644
--- a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java
+++ b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java
@@ -18,8 +18,8 @@
 
 package org.eclipse.jetty.test.jmx;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
 
 import java.net.URI;
 
diff --git a/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh b/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh
index 1d0f9eb..ea7843b 100755
--- a/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh
+++ b/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh
@@ -11,7 +11,7 @@
 cd "$JETTY_BASE"
 
 "$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \
-    jetty.port=58080 \
+    jetty.http.port=58080 \
     STOP.PORT=58181 STOP.KEY=it
 
 
diff --git a/tests/test-jmx/jmx-webapp/pom.xml b/tests/test-jmx/jmx-webapp/pom.xml
index c4b053b..e9cfd53 100644
--- a/tests/test-jmx/jmx-webapp/pom.xml
+++ b/tests/test-jmx/jmx-webapp/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-jmx-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>jmx-webapp</artifactId>
   <packaging>war</packaging>
diff --git a/tests/test-jmx/pom.xml b/tests/test-jmx/pom.xml
index 38d0126..bc1bc48 100644
--- a/tests/test-jmx/pom.xml
+++ b/tests/test-jmx/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>test-jmx-parent</artifactId>
diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml
index 842aa28..fe390c9 100644
--- a/tests/test-loginservice/pom.xml
+++ b/tests/test-loginservice/pom.xml
@@ -21,11 +21,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-loginservice</artifactId>
   <name>Jetty Tests :: Login Service</name>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.loginservice</bundle-symbolic-name>
+  </properties>
  <dependencies>
 	<dependency>
 		<groupId>org.eclipse.jetty</groupId>
diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java
index d68d48b..4c7b1e9 100644
--- a/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java
+++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java
@@ -19,8 +19,10 @@
 
 package org.eclipse.jetty;
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 import java.io.File;
 import java.io.FileOutputStream;
diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
index b1ad1e3..2f6acdd 100644
--- a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
+++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java
@@ -20,8 +20,10 @@
 
 
 
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/tests/test-quickstart/pom.xml b/tests/test-quickstart/pom.xml
index 55b236c..4a52b9c 100644
--- a/tests/test-quickstart/pom.xml
+++ b/tests/test-quickstart/pom.xml
@@ -2,7 +2,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -11,6 +11,9 @@
   <name>Test :: Jetty Quick Start</name>
   <description>Jetty Quick Start Test</description>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.tests.quickstart</bundle-symbolic-name>
+  </properties>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java
index 10dbd4c..34a9230 100644
--- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java
+++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.quickstart;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.server.Server;
diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java
index 19b5fa2..25dc854 100644
--- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java
+++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.quickstart;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.server.Server;
diff --git a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java
index 739b47b..e531d23 100644
--- a/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java
+++ b/tests/test-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.quickstart;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.server.Server;
diff --git a/tests/test-quickstart/src/test/resources/test-jndi.xml b/tests/test-quickstart/src/test/resources/test-jndi.xml
index 14c0934..5f4ab4f 100644
--- a/tests/test-quickstart/src/test/resources/test-jndi.xml
+++ b/tests/test-quickstart/src/test/resources/test-jndi.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the test-jndi webapp                                  -->
diff --git a/tests/test-quickstart/src/test/resources/test-spec.xml b/tests/test-quickstart/src/test/resources/test-spec.xml
index 99fc577..a136d28 100644
--- a/tests/test-quickstart/src/test/resources/test-spec.xml
+++ b/tests/test-quickstart/src/test/resources/test-spec.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/tests/test-quickstart/src/test/resources/test.xml b/tests/test-quickstart/src/test/resources/test.xml
index 41eba0c..8515656 100644
--- a/tests/test-quickstart/src/test/resources/test.xml
+++ b/tests/test-quickstart/src/test/resources/test.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"  encoding="ISO-8859-1"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ==================================================================
 Configure and deploy the test web application in $(jetty.home)/webapps/test
diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml
index ae5e15a..ff56074 100644
--- a/tests/test-sessions/pom.xml
+++ b/tests/test-sessions/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-sessions-parent</artifactId>
   <name>Jetty Tests :: Sessions :: Parent</name>
@@ -33,7 +33,8 @@
     <module>test-sessions-common</module>
     <module>test-hash-sessions</module>
     <module>test-jdbc-sessions</module>
-    <!-- Requires mongodb server running -->
     <module>test-mongodb-sessions</module>
+    <module>test-infinispan-sessions</module>
+    <module>test-gcloud-sessions</module>
   </modules>
 </project>
diff --git a/tests/test-sessions/test-gcloud-sessions/pom.xml b/tests/test-sessions/test-gcloud-sessions/pom.xml
new file mode 100644
index 0000000..dc7bba4
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/pom.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+// ========================================================================
+// Copyright (c) Webtide LLC
+// 
+// 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.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses. 
+// ========================================================================
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.eclipse.jetty.tests</groupId>
+    <artifactId>test-sessions-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <artifactId>test-gcloud-sessions</artifactId>
+  <name>Jetty Tests :: Sessions :: GCloud</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.gcloud</bundle-symbolic-name>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <!-- DO NOT DEPLOY (or Release) -->
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <skipTests>true</skipTests>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+       <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-webapp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.tests</groupId>
+            <artifactId>test-sessions-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.gcloud</groupId>
+            <artifactId>gcloud-session-manager</artifactId>
+            <version>${project.version}</version>
+         </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <profiles>
+      <profile>
+        <id>gcloud</id>
+        <activation>
+          <property>
+            <name>gcloud.enabled</name>
+            <value>true</value>
+          </property>
+        </activation>
+        <build>
+          <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-surefire-plugin</artifactId>
+              <configuration>
+                <skipTests>false</skipTests>
+                <systemPropertyVariables>
+                  <DATASTORE_DATASET>jetty9-work</DATASTORE_DATASET>
+                  <DATASTORE_HOST>http://localhost:8088</DATASTORE_HOST>
+                </systemPropertyVariables>
+              </configuration>
+            </plugin>
+          </plugins>
+        </build>
+      </profile>
+  </profiles>
+
+</project>
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java
new file mode 100644
index 0000000..b69aeb0
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ClientCrossContextSessionTest
+ *
+ *
+ */
+public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testCrossContextDispatch() throws Exception
+    {
+        super.testCrossContextDispatch();
+    }
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java
new file mode 100644
index 0000000..fae7a6a
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractForwardedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractForwardedSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+       return new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java
new file mode 100644
index 0000000..060efda
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java
@@ -0,0 +1,357 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.resource.JarResource;
+import org.eclipse.jetty.util.resource.Resource;
+
+import com.google.api.client.util.Strings;
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.GqlQuery;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.ProjectionEntity;
+import com.google.gcloud.datastore.Query;
+import com.google.gcloud.datastore.Query.ResultType;
+import com.google.gcloud.datastore.QueryResults;
+import com.google.gcloud.datastore.StructuredQuery;
+import com.google.gcloud.datastore.StructuredQuery.Projection;
+
+/**
+ * GCloudSessionTestSupport
+ *
+ *
+ */
+public class GCloudSessionTestSupport
+{
+    
+    private static class ProcessOutputReader implements Runnable
+    {
+        private InputStream _is;
+        private String _startupSentinel;
+        private BufferedReader _reader;
+
+        public ProcessOutputReader (InputStream is, String startupSentinel)
+        throws Exception
+        {
+            _is = is;
+            _startupSentinel = startupSentinel;
+            _reader = new BufferedReader(new InputStreamReader(_is));
+            if (!Strings.isNullOrEmpty(_startupSentinel))
+            {
+                String line;
+                while ((line = _reader.readLine()) != (null) && !line.contains(_startupSentinel))
+                {
+                    //System.err.println(line);
+                }
+            }
+        }
+
+
+        public void run()
+        {
+            String line;
+            try
+            {
+                while ((line = _reader.readLine()) != (null))
+                {
+                }
+            }
+            catch (IOException ignore)
+            {
+                /* ignore */
+            }
+            finally
+            {
+                IO.close(_reader);
+            }
+        }
+    }
+    
+
+    public static String DEFAULT_PROJECTID = "jetty9-work";
+    public static String DEFAULT_PORT = "8088";
+    public static String DEFAULT_HOST = "http://localhost:"+DEFAULT_PORT;
+    public static String DEFAULT_GCD_ZIP = "gcd-v1beta2-rev1-2.1.2b.zip";
+    public static String DEFAULT_GCD_UNPACKED = "gcd-v1beta2-rev1-2.1.2b";
+    public static String DEFAULT_DOWNLOAD_URL = "http://storage.googleapis.com/gcd/tools/";
+    
+ 
+    String _projectId;
+    String _testServerUrl;
+    String _testPort;
+    File _datastoreDir;
+    File _gcdInstallDir;
+    File _gcdUnpackedDir;
+    Datastore _ds;
+    
+    public GCloudSessionTestSupport (File gcdInstallDir)
+    {
+        _gcdInstallDir = gcdInstallDir;
+        if (_gcdInstallDir == null)
+            _gcdInstallDir = new File (System.getProperty("java.io.tmpdir"));
+        
+        _projectId = System.getProperty("DATASTORE_DATASET", System.getenv("DATASTORE_DATASET"));
+        if (_projectId == null)
+        {
+            _projectId = DEFAULT_PROJECTID;
+            System.setProperty("DATASTORE_DATASET", _projectId);
+        }
+        _testServerUrl = System.getProperty("DATASTORE_HOST", System.getenv("DATASTORE_HOST"));
+        if (_testServerUrl == null)
+        {
+            _testServerUrl = DEFAULT_HOST;
+            _testPort = DEFAULT_PORT;
+            System.setProperty("DATASTORE_HOST", _testServerUrl);
+        }
+        else
+        {
+            int i = _testServerUrl.lastIndexOf(':');
+            _testPort = _testServerUrl.substring(i+1);
+        }
+    }
+    
+    public GCloudSessionTestSupport ()
+    {
+        this(null);
+    }
+
+    public GCloudConfiguration getConfiguration ()
+    {
+        return new GCloudConfiguration();
+    }
+    
+    
+    public void setUp()
+    throws Exception
+    {
+       downloadGCD();
+       createDatastore();
+       startDatastore();
+    }
+    
+    
+    public void downloadGCD()
+    throws Exception
+    {
+        File zipFile = new File (_gcdInstallDir, DEFAULT_GCD_ZIP);       
+        _gcdUnpackedDir = new File (_gcdInstallDir, DEFAULT_GCD_UNPACKED);
+        File gcdSh = new File (_gcdUnpackedDir, "gcd.sh");
+        if (gcdSh.exists())
+            return;
+        
+        
+        if (_gcdInstallDir.exists() && !zipFile.exists())
+        {
+           //download it
+            ReadableByteChannel rbc = Channels.newChannel(new URL(DEFAULT_DOWNLOAD_URL+DEFAULT_GCD_ZIP).openStream());
+            try (FileOutputStream fos = new FileOutputStream(zipFile)) 
+            {
+              fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+            }
+        }
+        
+        if (zipFile.exists())
+        {
+            //unpack it
+            Resource zipResource = JarResource.newJarResource(Resource.newResource(zipFile));
+            zipResource.copyTo(_gcdInstallDir);
+        }
+        
+        System.err.println("GCD downloaded and unpacked");
+    }
+    
+    
+    
+    public void createDatastore ()
+    throws Exception
+    {
+    
+        _datastoreDir = Files.createTempDirectory("gcloud-sessions").toFile();
+        _datastoreDir.deleteOnExit();
+        
+        ProcessBuilder processBuilder = new ProcessBuilder();
+        processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
+        processBuilder.directory(_datastoreDir);
+        if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")) 
+        {
+          processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "create", "-p", _projectId, _projectId);
+          processBuilder.redirectOutput(new File("NULL:"));
+        } 
+        else 
+        {
+          processBuilder.redirectOutput(new File("/tmp/run.out"));
+          processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "create", "-p",_projectId, _projectId);
+        }
+
+        Process temp = processBuilder.start();
+        System.err.println("Create outcome: "+temp.waitFor());
+    }
+    
+    
+    public void startDatastore()
+    throws Exception
+    {
+        //start the datastore for the test
+        ProcessBuilder processBuilder = new ProcessBuilder();
+        processBuilder.directory(_datastoreDir);
+        processBuilder.redirectErrorStream(true);
+        if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows")) 
+        {
+          processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown","--port="+_testPort, _projectId);
+        } 
+        else 
+        {
+          processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown", "--port="+_testPort, _projectId);
+        }
+        
+        System.err.println("Starting datastore");
+        Process temp = processBuilder.start();
+        ProcessOutputReader reader = new ProcessOutputReader(temp.getInputStream(), "Dev App Server is now running");
+        Thread readerThread = new Thread(reader, "GCD reader");
+        readerThread.setDaemon(true);
+        readerThread.start();
+    }
+    
+    public void stopDatastore()
+    throws Exception
+    {
+        //Send request to terminate test datastore
+        URL url = new URL("http", "localhost", Integer.parseInt(_testPort.trim()), "/_ah/admin/quit");
+        HttpURLConnection con = (HttpURLConnection) url.openConnection();
+        con.setRequestMethod("POST");
+        con.setDoOutput(true);
+        con.setDoInput(true);
+        OutputStream out = con.getOutputStream();
+        out.write("".getBytes());
+        out.flush();
+        InputStream in = con.getInputStream();
+        while (in.read() != -1)
+        {
+            // consume input
+          
+        }
+
+        System.err.println("Stop issued");
+    }
+ 
+    
+    public void clearDatastore()
+    {
+        org.eclipse.jetty.util.IO.delete(_datastoreDir);
+    }
+    
+    public void tearDown()
+    throws Exception
+    {
+        stopDatastore();
+        clearDatastore();
+    }
+    
+    public void ensureDatastore()
+    throws Exception
+    {
+        if (_ds == null)
+            _ds = DatastoreFactory.instance().get(getConfiguration().getDatastoreOptions());
+    }
+    public void listSessions () throws Exception
+    {
+        ensureDatastore();
+        GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionManager.KIND);
+       
+        Query<Entity> query = builder.build();
+    
+        QueryResults<Entity> results = _ds.run(query);
+        assertNotNull(results);
+        System.err.println("SESSIONS::::::::");
+        while (results.hasNext())
+        {
+            
+            Entity e = results.next();
+            System.err.println(e.getString("clusterId")+" expires at "+e.getLong("expiry"));
+        }
+        System.err.println("END OF SESSIONS::::::::");
+    }
+    
+    public void assertSessions(int count) throws Exception
+    {
+        ensureDatastore();
+        StructuredQuery<ProjectionEntity> keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder()
+                .kind(GCloudSessionManager.KIND)
+                .projection(Projection.property("__key__"))
+                .limit(100)
+                .build();  
+        QueryResults<ProjectionEntity> results =   _ds.run(keyOnlyProjectionQuery);
+        assertNotNull(results);
+        int actual = 0;
+        while (results.hasNext())
+        { 
+            results.next();
+            ++actual;
+        }       
+        assertEquals(count, actual);
+    }
+    
+    public void deleteSessions () throws Exception
+    {
+       ensureDatastore();
+        StructuredQuery<ProjectionEntity> keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder()
+                .kind(GCloudSessionManager.KIND)
+                .projection(Projection.property("__key__"))
+                .limit(100)
+                .build();  
+        QueryResults<ProjectionEntity> results =   _ds.run(keyOnlyProjectionQuery);
+        if (results != null)
+        {
+            List<Key> keys = new ArrayList<Key>();
+            
+            while (results.hasNext())
+            { 
+                ProjectionEntity pe = results.next();
+                keys.add(pe.key());
+            }
+            
+            _ds.delete(keys.toArray(new Key[keys.size()]));
+        }
+        
+        assertSessions(0);
+    }
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java
new file mode 100644
index 0000000..69cd07e
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java
@@ -0,0 +1,97 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.SessionIdManager;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.SessionHandler;
+
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+
+/**
+ * GCloudTestServer
+ *
+ *
+ */
+public class GCloudTestServer extends AbstractTestServer
+{
+    static int __workers=0;
+    public static int STALE_INTERVAL_SEC = 1;
+
+ 
+
+    /**
+     * @param port
+     * @param maxInactivePeriod
+     * @param scavengePeriod
+     * @param sessionIdMgrConfig
+     */
+    public GCloudTestServer(int port, int maxInactivePeriod, int scavengePeriod, GCloudConfiguration config)
+    {
+        super(port, maxInactivePeriod, scavengePeriod, config);
+    }
+
+    /**
+     * @param port
+     * @param configuration
+     */
+    public GCloudTestServer(int port, GCloudConfiguration configuration)
+    {
+        super(port, 30,10, configuration);
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager(java.lang.Object)
+     */
+    @Override
+    public SessionIdManager newSessionIdManager(Object config)
+    {
+        GCloudSessionIdManager idManager = new GCloudSessionIdManager(getServer());
+        idManager.setWorkerName("w"+(__workers++));
+        idManager.setConfig((GCloudConfiguration)config);
+        return idManager;
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionManager()
+     */
+    @Override
+    public SessionManager newSessionManager()
+    {
+        GCloudSessionManager sessionManager = new GCloudSessionManager();
+        sessionManager.setSessionIdManager((GCloudSessionIdManager)_sessionIdManager);
+        sessionManager.setStaleIntervalSec(STALE_INTERVAL_SEC);
+        sessionManager.setScavengeIntervalSec(_scavengePeriod);
+        return sessionManager;
+        
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionHandler(org.eclipse.jetty.server.SessionManager)
+     */
+    @Override
+    public SessionHandler newSessionHandler(SessionManager sessionManager)
+    {
+        return new SessionHandler(sessionManager);
+    }
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java
new file mode 100644
index 0000000..3b853d2
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractImmortalSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ImmortalSessionTest
+ *
+ *
+ */
+public class ImmortalSessionTest extends AbstractImmortalSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    /**
+     * @throws Exception
+     */
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs)
+    {
+       return new GCloudTestServer(port, port, scavengeMs, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testImmortalSession() throws Exception
+    {
+        super.testImmortalSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java
new file mode 100644
index 0000000..b1bd9ff
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java
@@ -0,0 +1,78 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * InvalidationSessionTest
+ *
+ *
+ */
+public class InvalidationSessionTest extends AbstractInvalidationSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause()
+     */
+    @Override
+    public void pause()
+    {
+        //This test moves around a session between 2 nodes. After it is invalidated on the 1st node,
+        //it will still be in the memory of the 2nd node. We need to wait until after the stale time
+        //has expired on node2 for it to reload the session and discover it has been deleted.
+        try
+        {
+            Thread.currentThread().sleep((2*GCloudTestServer.STALE_INTERVAL_SEC)*1000);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        
+    }
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java
new file mode 100644
index 0000000..cfb0b59
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractLastAccessTimeTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * LastAccessTimeTest
+ *
+ *
+ */
+public class LastAccessTimeTest extends AbstractLastAccessTimeTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractLastAccessTimeTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testLastAccessTime() throws Exception
+    {
+        super.testLastAccessTime();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java
new file mode 100644
index 0000000..da2d115
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * LocalSessionScavengingTest
+ *
+ *
+ */
+public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest
+{
+  static GCloudSessionTestSupport _testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testLocalSessionsScavenging() throws Exception
+    {
+        super.testLocalSessionsScavenging();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java
new file mode 100644
index 0000000..8437492
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.session.AbstractNewSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * NewSessionTest
+ *
+ *
+ */
+public class NewSessionTest extends AbstractNewSessionTest
+{
+    GCloudSessionTestSupport _testSupport;
+    
+    @Before
+    public void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @After
+    public void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+       return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    public void testNewSession() throws Exception
+    {
+        super.testNewSession();
+    }
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java
new file mode 100644
index 0000000..982b4a2
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractOrphanedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * OrphanedSessionTest
+ *
+ *
+ */
+public class OrphanedSessionTest extends AbstractOrphanedSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractOrphanedSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testOrphanedSession() throws Exception
+    {
+        super.testOrphanedSession();
+        _testSupport.assertSessions(0);
+    }
+    
+    
+    
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java
new file mode 100644
index 0000000..2036115
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ReentrantRequestSessionTest
+ *
+ *
+ */
+public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return  new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testReentrantRequestSession() throws Exception
+    {
+        super.testReentrantRequestSession();
+    }
+    
+    
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java
new file mode 100644
index 0000000..88ca81f
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractRemoveSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * RemoveSessionTest
+ *
+ *
+ */
+public class RemoveSessionTest extends AbstractRemoveSessionTest
+{
+   static GCloudSessionTestSupport _testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractRemoveSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    { 
+        return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testRemoveSession() throws Exception
+    {
+        super.testRemoveSession();
+    }
+    
+    
+
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java
new file mode 100644
index 0000000..bbb1fcf
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSameNodeLoadTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SameNodeLoadTest
+ *
+ *
+ */
+public class SameNodeLoadTest extends AbstractSameNodeLoadTest
+{
+  static GCloudSessionTestSupport _testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return  new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testLoad() throws Exception
+    {
+        super.testLoad();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java
new file mode 100644
index 0000000..91e25be
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ServerCrossContextSessionTest
+ *
+ *
+ */
+public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest
+{
+
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return  new GCloudTestServer(port, _testSupport.getConfiguration()); 
+    }
+
+    @Test
+    @Override
+    public void testCrossContextDispatch() throws Exception
+    {
+        super.testCrossContextDispatch();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java
new file mode 100644
index 0000000..c8fde49
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java
@@ -0,0 +1,98 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionExpiryTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionExpiryTest
+ *
+ *
+ */
+public class SessionExpiryTest extends AbstractSessionExpiryTest
+{
+
+    static GCloudSessionTestSupport _testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testSessionNotExpired() throws Exception
+    {
+        super.testSessionNotExpired();
+        _testSupport.deleteSessions();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#testSessionExpiry()
+     */
+    @Test
+    @Override
+    public void testSessionExpiry() throws Exception
+    {
+        super.testSessionExpiry();
+        _testSupport.assertSessions(0);
+    }
+
+    @Override
+    public void verifySessionCreated(TestHttpSessionListener listener, String sessionId)
+    {
+        super.verifySessionCreated(listener, sessionId);
+        try{ _testSupport.listSessions(); _testSupport.assertSessions(1);}catch(Exception e) {e.printStackTrace();} 
+    }
+
+    @Override
+    public void verifySessionDestroyed(TestHttpSessionListener listener, String sessionId)
+    {
+        super.verifySessionDestroyed(listener, sessionId);
+        try{ _testSupport.listSessions(); _testSupport.assertSessions(0);}catch(Exception e) {e.printStackTrace();}
+    }
+
+    
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java
new file mode 100644
index 0000000..559af10
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionInvalidateAndCreateTest
+ *
+ *
+ */
+public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest
+{
+
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testSessionScavenge() throws Exception
+    {
+        super.testSessionScavenge();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java
new file mode 100644
index 0000000..4836f3a
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionMigrationTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionMigrationTest
+ *
+ *
+ */
+public class SessionMigrationTest extends AbstractSessionMigrationTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionMigrationTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return  new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    
+    @Test
+    @Override
+    public void testSessionMigration() throws Exception
+    {
+        super.testSessionMigration();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java
new file mode 100644
index 0000000..c825b18
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionRenewTest
+ *
+ *
+ */
+public class SessionRenewTest extends AbstractSessionRenewTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port,max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testSessionRenewal() throws Exception
+    {
+        super.testSessionRenewal();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java
new file mode 100644
index 0000000..0b832d8
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionValueSavingTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionValueSavingTest
+ *
+ *
+ */
+public class SessionValueSavingTest extends AbstractSessionValueSavingTest
+{
+
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionValueSavingTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return  new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+    }
+
+    @Test
+    @Override
+    public void testSessionValueSaving() throws Exception
+    {
+        super.testSessionValueSaving();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java
new file mode 100644
index 0000000..41c57ff
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java
@@ -0,0 +1,95 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.gcloud.session;
+
+import static org.junit.Assert.fail;
+import org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * StopSessionManagerPreserveSessionTest
+ *
+ *
+ */
+public class StopSessionManagerPreserveSessionTest extends AbstractStopSessionManagerPreserveSessionTest
+{
+    static GCloudSessionTestSupport _testSupport;
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        _testSupport = new GCloudSessionTestSupport();
+        _testSupport.setUp();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        _testSupport.tearDown();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#checkSessionPersisted(boolean)
+     */
+    @Override
+    public void checkSessionPersisted(boolean expected)
+    {
+        try
+        {
+            _testSupport.assertSessions(1);
+        }
+        catch (Exception e)
+        {
+            fail(e.getMessage());
+        }
+
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return  new GCloudTestServer(port, _testSupport.getConfiguration());
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#configureSessionManagement(org.eclipse.jetty.servlet.ServletContextHandler)
+     */
+    @Override
+    public void configureSessionManagement(ServletContextHandler context)
+    {
+        
+    }
+
+    @Test
+    @Override
+    public void testStopSessionManagerPreserveSession() throws Exception
+    {
+        super.testStopSessionManagerPreserveSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml
index 1a3f6f8..d15852b 100644
--- a/tests/test-sessions/test-hash-sessions/pom.xml
+++ b/tests/test-sessions/test-hash-sessions/pom.xml
@@ -21,11 +21,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-hash-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: Hash</name>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.hash</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
new file mode 100644
index 0000000..1a6c5d0
--- /dev/null
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
@@ -0,0 +1,91 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.util.IO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{ 
+   File tmpDir;
+    
+    @Before
+    public void before() throws Exception
+    {
+        tmpDir = File.createTempFile("hash-session-forward-test", null);
+        tmpDir.delete();
+        tmpDir.mkdirs();
+        tmpDir.deleteOnExit();
+    }
+    
+    @After 
+    public void after()
+    {
+        IO.delete(tmpDir);
+    }
+    
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new HashTestServer(port)
+        {
+
+            @Override
+            public SessionManager newSessionManager()
+            {
+                HashSessionManager sessionManager = (HashSessionManager)super.newSessionManager();
+                sessionManager.setSavePeriod(2);
+                
+                try
+                {
+                    sessionManager.setStoreDirectory(tmpDir);
+                }
+                catch (Exception e)
+                {
+                    throw new IllegalStateException(e);
+                }
+                return sessionManager;
+            }
+
+        };
+    }
+
+    
+    
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        super.testSessionCreateInForward();
+    }
+
+  
+
+
+}
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
index 69e47a3..05bd34f 100644
--- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
@@ -38,7 +38,7 @@
     }
 
 
-    public SessionIdManager newSessionIdManager(String config)
+    public SessionIdManager newSessionIdManager(Object config)
     {
         return new HashSessionIdManager();
     }
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
index a38b524..13f2b89 100644
--- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
@@ -133,7 +133,7 @@
             //make a request to set up a session on the server
             ContentResponse response = client.GET(url + "?action=init");
             assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-            String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+            String sessionCookie = response.getHeaders().get("Set-Cookie");
             assertTrue(sessionCookie != null);
             // Mangle the cookie, replacing Path with $Path, etc.
             sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java
deleted file mode 100644
index b6f9107..0000000
--- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server.session;
-
-import org.junit.Test;
-
-/**
- * LightLoadTest
- */
-public class LightLoadTest extends AbstractLightLoadTest
-{
-
-    public AbstractTestServer createServer(int port)
-    {
-        return new HashTestServer(port);
-    }
-
-    @Test
-    public void testLightLoad() throws Exception
-    {
-        super.testLightLoad();
-    }
-
-}
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java
new file mode 100644
index 0000000..05d18a2
--- /dev/null
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java
@@ -0,0 +1,40 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.Test;
+
+/**
+ * ScatterGunLoadTest
+ */
+public class ScatterGunLoadTest extends AbstractScatterGunLoadTest
+{
+
+    public AbstractTestServer createServer(int port)
+    {
+        return new HashTestServer(port);
+    }
+
+    @Test
+    public void testLightLoad() throws Exception
+    {
+        super.testLightLoad();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/pom.xml b/tests/test-sessions/test-infinispan-sessions/pom.xml
new file mode 100644
index 0000000..dc5e338
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/pom.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+// ========================================================================
+// Copyright (c) Webtide LLC
+//
+// 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.apache.org/licenses/LICENSE-2.0.txt
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.eclipse.jetty.tests</groupId>
+    <artifactId>test-sessions-parent</artifactId>
+    <version>9.3.7-SNAPSHOT</version>
+  </parent>
+  <artifactId>test-infinispan-sessions</artifactId>
+  <name>Jetty Tests :: Sessions :: Infinispan</name>
+  <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.infinispan</bundle-symbolic-name>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <!-- DO NOT DEPLOY (or Release) -->
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+              <include>org/eclipse/jetty/server/session/*.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack</id>
+            <phase>generate-test-resources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.eclipse.jetty.toolchain</groupId>
+                  <artifactId>jetty-test-policy</artifactId>
+                  <version>${jetty-test-policy-version}</version>
+                  <type>jar</type>
+                  <overWrite>true</overWrite>
+                  <includes>**/*.keystore,**/*.pem</includes>
+                  <outputDirectory>${jetty.test.policy.loc}</outputDirectory>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+       <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-webapp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.tests</groupId>
+            <artifactId>test-sessions-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-infinispan</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-jmx</artifactId>
+          <version>${project.version}</version>
+          <optional>true</optional>
+        </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.toolchain</groupId>
+      <artifactId>jetty-test-helper</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.infinispan</groupId>
+      <artifactId>infinispan-client-hotrod</artifactId>
+      <version>7.1.1.Final</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <profiles>
+  <!-- to test hotrod, configure a cache called "remote-session-test" -->
+      <profile>
+        <id>remote</id>
+        <activation>
+          <property>
+            <name>hotrod.enabled</name>
+            <value>true</value>
+          </property>
+        </activation>
+        <build>
+          <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-surefire-plugin</artifactId>
+              <configuration>
+                <includes>
+                  <include>**/*.java</include>
+                </includes>
+              </configuration>
+            </plugin>
+          </plugins>
+        </build>
+      </profile>
+  </profiles>
+</project>
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java
new file mode 100644
index 0000000..ac1034a
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java
@@ -0,0 +1,60 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+    
+    @Test
+    public void testCrossContextDispatch() throws Exception
+    {
+        super.testCrossContextDispatch();
+    }
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
new file mode 100644
index 0000000..377acad
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        super.testSessionCreateInForward();
+    }
+   
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java
new file mode 100644
index 0000000..da63d3a
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java
@@ -0,0 +1,71 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ImmortalSessionTest
+ *
+ *
+ */
+public class ImmortalSessionTest extends AbstractImmortalSessionTest
+{
+
+
+    public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs)
+    {
+        return new InfinispanTestSessionServer(port, maxInactiveMs, scavengeMs, __testSupport.getCache());
+    }
+
+    @Override
+    public void testImmortalSession() throws Exception
+    {
+        super.testImmortalSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java
new file mode 100644
index 0000000..4b098cc
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java
@@ -0,0 +1,117 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.eclipse.jetty.server.SessionIdManager;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager;
+import org.eclipse.jetty.session.infinispan.InfinispanSessionManager;
+import org.infinispan.Cache;
+import org.infinispan.commons.api.BasicCache;
+import org.infinispan.commons.util.CloseableIteratorSet;
+
+public class InfinispanTestSessionServer extends AbstractTestServer
+{
+    static int __workers=0;
+    
+
+
+    
+    
+    public InfinispanTestSessionServer(int port, BasicCache config)
+    {
+        this(port, 30, 10, config);
+    }
+    
+  
+    
+    public InfinispanTestSessionServer(int port, int maxInactivePeriod, int scavengePeriod, BasicCache config)
+    {
+        super(port, maxInactivePeriod, scavengePeriod, config);
+    }
+    
+    
+
+    @Override
+    public SessionIdManager newSessionIdManager(Object config)
+    {
+        InfinispanSessionIdManager idManager = new InfinispanSessionIdManager(getServer());
+        idManager.setWorkerName("w"+(__workers++));
+        idManager.setCache((BasicCache)config);
+        return idManager;
+    }
+
+    @Override
+    public SessionManager newSessionManager()
+    {
+        InfinispanSessionManager sessionManager = new InfinispanSessionManager();
+        sessionManager.setSessionIdManager((InfinispanSessionIdManager)_sessionIdManager);
+        sessionManager.setCache(((InfinispanSessionIdManager)_sessionIdManager).getCache());
+        sessionManager.setStaleIntervalSec(1);
+        sessionManager.setScavengeInterval(_scavengePeriod);
+        
+        return sessionManager;
+    }
+
+    @Override
+    public SessionHandler newSessionHandler(SessionManager sessionManager)
+    {
+        return new SessionHandler(sessionManager);
+    }
+
+    public boolean exists (String id)
+    {
+        BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
+        if (cache != null)
+        {
+            return cache.containsKey(id);      
+        }
+        
+        return false;
+    }
+    
+    public Object get (String id)
+    {
+        BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
+        if (cache != null)
+        {
+            return cache.get(id);      
+        }
+        
+        return null;
+    }
+
+    public void dumpCache ()
+    {
+        BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
+        if (cache != null)
+        {
+            System.err.println(cache.getName()+" contains "+cache.size()+" entries");         
+        }
+    }
+
+    public void clearCache ()
+    { 
+        BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache();
+        if (cache != null)
+            cache.clear();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java
new file mode 100644
index 0000000..38ae417
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java
@@ -0,0 +1,114 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import java.io.File;
+
+import org.eclipse.jetty.util.IO;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+
+/**
+ * InfinispanTestSupport
+ *
+ *
+ */
+public class InfinispanTestSupport
+{
+    public static final String DEFAULT_CACHE_NAME =  "session_test_cache";
+    public  Cache _cache;
+ 
+    public ConfigurationBuilder _builder;
+    private  File _tmpdir;
+    private boolean _useFileStore;
+    private String _name;
+    public static  EmbeddedCacheManager _manager;
+    
+    static
+    {
+        try
+        {
+            _manager = new DefaultCacheManager(new GlobalConfigurationBuilder().globalJmxStatistics().allowDuplicateDomains(true).build());
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+    
+    public InfinispanTestSupport ()
+    {
+        this (null);
+    }
+    
+    public InfinispanTestSupport(String cacheName)
+    {     
+        if (cacheName == null)
+            cacheName = DEFAULT_CACHE_NAME+System.currentTimeMillis();
+        
+        _name = cacheName;
+        _builder = new ConfigurationBuilder();
+    }
+    
+    public void setUseFileStore (boolean useFileStore)
+    {
+        _useFileStore = useFileStore;
+    }
+  
+    public Cache getCache ()
+    {
+        return _cache;
+    }
+    
+    public void setup () throws Exception
+    {
+       if (_useFileStore)
+       {      
+        _tmpdir = File.createTempFile("infini", "span");
+        _tmpdir.delete();
+        _tmpdir.mkdir();
+        System.err.println("Temp file: "+_tmpdir);
+        Configuration config = _builder.persistence().addSingleFileStore().location(_tmpdir.getAbsolutePath()).storeAsBinary().build();
+        _manager.defineConfiguration(_name, config);
+       }
+       else
+       {
+           _manager.defineConfiguration(_name, _builder.build());
+       }
+       _cache = _manager.getCache(_name);
+    }
+
+
+    public void teardown () throws Exception
+    {
+        _manager.removeCache(_name);
+        if (_useFileStore)
+        {
+            if (_tmpdir != null)
+            {
+                IO.delete(_tmpdir);
+            }
+        }
+    }
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java
new file mode 100644
index 0000000..fe0974f
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java
@@ -0,0 +1,91 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * InvalidationSessionTest
+ *
+ *
+ */
+public class InvalidationSessionTest extends AbstractInvalidationSessionTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    public static long __staleSec = 3L;
+   
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+      __testSupport = new InfinispanTestSupport();
+      __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    
+    
+    
+    @Override
+    public void testInvalidation() throws Exception
+    {
+        super.testInvalidation();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause()
+     */
+    @Override
+    public void pause()
+    {
+        //This test moves a session from node 1 to node 2, then invalidates the session back on node1. This
+        //should never happen with a decent load balancer.
+        //The infinispan session manager on node 2 will hold the session in local memory for a specific (configurable)
+        //amount of time. We've set the stale session time to 3 sec, so we need to pause for at least this long before making
+        //another request to node2
+        
+        //that the node will re-load the session from the database and discover that it has gone.
+        try
+        {
+            Thread.sleep(2 * __staleSec * 1000);
+        }
+        catch (InterruptedException e)
+        {
+        }
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java
new file mode 100644
index 0000000..e537017
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java
@@ -0,0 +1,65 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import java.io.File;
+
+import org.eclipse.jetty.util.IO;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class LastAccessTimeTest extends AbstractLastAccessTimeTest
+{ 
+   public static InfinispanTestSupport __testSupport;
+   
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+       __testSupport = new InfinispanTestSupport();
+       __testSupport.setUseFileStore(true);
+       __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Override
+    public void testLastAccessTime() throws Exception
+    {
+        super.testLastAccessTime();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java
new file mode 100644
index 0000000..1f21f6b
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java
@@ -0,0 +1,59 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * LocalSessionScavengingTest
+ *
+ *
+ */
+public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setUseFileStore(true);
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java
new file mode 100644
index 0000000..05b1c21
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * NewSessionTest
+ *
+ *
+ */
+public class NewSessionTest extends AbstractNewSessionTest
+{
+
+   public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+  
+    @Override
+    public void testNewSession() throws Exception
+    {
+        super.testNewSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java
new file mode 100644
index 0000000..f0d2e0e
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ReentrantRequestSessionTest
+ *
+ *
+ */
+public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
+{
+    public static InfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+       return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    @Override
+    public void testReentrantRequestSession() throws Exception
+    {
+        super.testReentrantRequestSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java
new file mode 100644
index 0000000..4d2a236
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java
@@ -0,0 +1,58 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RemoveSessionTest extends AbstractRemoveSessionTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+       InfinispanTestSessionServer s = new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+       return s;
+    }
+
+    @Test
+    public void testRemoveSession() throws Exception
+    {
+        super.testRemoveSession();
+    }
+   
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java
new file mode 100644
index 0000000..59e9b43
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * SameNodeLoadTest
+ *
+ *
+ */
+public class SameNodeLoadTest extends AbstractSameNodeLoadTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+
+    @Override
+    public void testLoad() throws Exception
+    {
+        super.testLoad();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java
new file mode 100644
index 0000000..9319f04
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SessionExpiryTest extends AbstractSessionExpiryTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+       InfinispanTestSessionServer server =  new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+       return server;
+    }
+
+    @Test
+    @Override
+    public void testSessionNotExpired() throws Exception
+    {
+        super.testSessionNotExpired();
+    }
+
+    @Test
+    @Override
+    public void testSessionExpiry() throws Exception
+    {
+       super.testSessionExpiry();
+    }
+    
+    @Override
+    public void verifySessionDestroyed (TestHttpSessionListener listener, String sessionId)
+    {
+        //noop - sessions that expired when the InfinispanSessionManager was not running are not reloaded and do not have their listeners called on them.
+    }
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java
new file mode 100644
index 0000000..3178bf2
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java
@@ -0,0 +1,66 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * SessionInvalidateAndCreateTest
+ *
+ *
+ */
+public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest
+{
+    public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Override
+    public void testSessionScavenge() throws Exception
+    {
+        super.testSessionScavenge();
+    }
+
+    
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java
new file mode 100644
index 0000000..856d86b
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java
@@ -0,0 +1,64 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * SessionMigrationTest
+ *
+ *
+ */
+public class SessionMigrationTest extends AbstractSessionMigrationTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionMigrationTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    @Override
+    public void testSessionMigration() throws Exception
+    {
+        super.testSessionMigration();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java
new file mode 100644
index 0000000..6365824
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionRenewTest
+ *
+ *
+ */
+public class SessionRenewTest extends AbstractSessionRenewTest
+{
+
+    public static InfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new InfinispanTestSupport();
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Test
+    public void testSessionRenewal() throws Exception
+    {
+        super.testSessionRenewal();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java
new file mode 100644
index 0000000..1b6fd11
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+
+import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * RemoteClientCrossContextSessionTest
+ *
+ *
+ */
+public class RemoteClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
+{
+  public static RemoteInfinispanTestSupport __testSupport;
+
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+    
+    @Test
+    public void testCrossContextDispatch() throws Exception
+    {
+        super.testCrossContextDispatch();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java
new file mode 100644
index 0000000..44dd561
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractForwardedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * RemoteForwardedSessionTest
+ *
+ *
+ */
+public class RemoteForwardedSessionTest extends AbstractForwardedSessionTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+
+
+
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+
+
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        super.testSessionCreateInForward();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java
new file mode 100644
index 0000000..f166182
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java
@@ -0,0 +1,74 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractImmortalSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ImmortalSessionTest
+ *
+ *
+ */
+public class RemoteImmortalSessionTest extends AbstractImmortalSessionTest
+{
+
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs)
+    {
+        return new InfinispanTestSessionServer(port, maxInactiveMs, scavengeMs, __testSupport.getCache());
+    }
+
+    @Override
+    public void testImmortalSession() throws Exception
+    {
+        super.testImmortalSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java
new file mode 100644
index 0000000..0dc792b
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java
@@ -0,0 +1,88 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import java.io.File;
+
+import org.eclipse.jetty.util.IO;
+import org.infinispan.Cache;
+import org.infinispan.client.hotrod.RemoteCache;
+import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+
+/**
+ * RemoteInfinispanTestSupport
+ *
+ *
+ */
+public class RemoteInfinispanTestSupport
+{
+    public static final String DEFAULT_CACHE_NAME =  "session_test_cache";
+    public  RemoteCache _cache;
+    private String _name;
+    public static  RemoteCacheManager _manager;
+    
+    static
+    {
+        try
+        {
+            _manager = new RemoteCacheManager();
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+    
+    public RemoteInfinispanTestSupport ()
+    {
+        this (null);
+    }
+    
+    public RemoteInfinispanTestSupport(String cacheName)
+    {     
+        if (cacheName == null)
+            cacheName = DEFAULT_CACHE_NAME+System.currentTimeMillis();
+        
+        _name = cacheName;
+    }
+    
+ 
+  
+    public RemoteCache getCache ()
+    {
+        return _cache;
+    }
+    
+    public void setup () throws Exception
+    {
+       _cache = _manager.getCache(_name);
+    }
+
+
+    public void teardown () throws Exception
+    {
+        
+    }
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java
new file mode 100644
index 0000000..ba44d8f
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java
@@ -0,0 +1,93 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * InvalidationSessionTest
+ *
+ *
+ */
+public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    public static long __staleSec = 3L;
+   
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+      __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+      __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    
+    
+    
+    @Override
+    public void testInvalidation() throws Exception
+    {
+        super.testInvalidation();
+    }
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause()
+     */
+    @Override
+    public void pause()
+    {
+        //This test moves a session from node 1 to node 2, then invalidates the session back on node1. This
+        //should never happen with a decent load balancer.
+        //The infinispan session manager on node 2 will hold the session in local memory for a specific (configurable)
+        //amount of time. We've set the stale session time to 3 sec, so we need to pause for at least this long before making
+        //another request to node2 so 
+        //that the node will re-load the session from the database and discover that it has gone.
+        try
+        {
+            Thread.sleep(2 * __staleSec * 1000);
+        }
+        catch (InterruptedException e)
+        {
+        }
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java
new file mode 100644
index 0000000..a5dc98a
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session.remote;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.session.AbstractLastAccessTimeTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.eclipse.jetty.util.IO;
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class RemoteLastAccessTimeTest extends AbstractLastAccessTimeTest
+{ 
+   public static RemoteInfinispanTestSupport __testSupport;
+   
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+       __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+       __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Override
+    public void testLastAccessTime() throws Exception
+    {
+        super.testLastAccessTime();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java
new file mode 100644
index 0000000..44ada4b
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java
@@ -0,0 +1,61 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * LocalSessionScavengingTest
+ *
+ *
+ */
+public class RemoteLocalSessionScavengingTest extends AbstractLocalSessionScavengingTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java
new file mode 100644
index 0000000..0a05bc9
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractNewSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * NewSessionTest
+ *
+ *
+ */
+public class RemoteNewSessionTest extends AbstractNewSessionTest
+{
+
+   public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+  
+    @Override
+    public void testNewSession() throws Exception
+    {
+        super.testNewSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java
new file mode 100644
index 0000000..a1a115c
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java
@@ -0,0 +1,67 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ReentrantRequestSessionTest
+ *
+ *
+ */
+public class RemoteReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
+{
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+       return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    @Override
+    public void testReentrantRequestSession() throws Exception
+    {
+        super.testReentrantRequestSession();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java
new file mode 100644
index 0000000..7a20bc4
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java
@@ -0,0 +1,61 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractRemoveSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RemoteRemoveSessionTest extends AbstractRemoveSessionTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+       InfinispanTestSessionServer s = new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+       return s;
+    }
+
+    @Test
+    public void testRemoveSession() throws Exception
+    {
+        super.testRemoveSession();
+    }
+   
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java
new file mode 100644
index 0000000..4313588
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractSameNodeLoadTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * SameNodeLoadTest
+ *
+ *
+ */
+public class RemoteSameNodeLoadTest extends AbstractSameNodeLoadTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+       __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache());
+        return server;
+    }
+
+    @Override
+    public void testLoad() throws Exception
+    {
+        super.testLoad();
+    }
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java
new file mode 100644
index 0000000..4e6ea1f
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java
@@ -0,0 +1,73 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractSessionExpiryTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class RemoteSessionExpiryTest extends AbstractSessionExpiryTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+       InfinispanTestSessionServer server =  new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+       return server;
+    }
+
+    @Test
+    @Override
+    public void testSessionNotExpired() throws Exception
+    {
+        super.testSessionNotExpired();
+    }
+
+    @Test
+    @Override
+    public void testSessionExpiry() throws Exception
+    {
+       super.testSessionExpiry();
+    }
+    
+    @Override
+    public void verifySessionDestroyed (TestHttpSessionListener listener, String sessionId)
+    {
+        //noop - sessions that expired when the InfinispanSessionManager was not running are not reloaded and do not have their listeners called on them.
+    }
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java
new file mode 100644
index 0000000..d48b037
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java
@@ -0,0 +1,69 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * SessionInvalidateAndCreateTest
+ *
+ *
+ */
+public class RemoteSessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest
+{
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Override
+    public void testSessionScavenge() throws Exception
+    {
+        super.testSessionScavenge();
+    }
+
+    
+    
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java
new file mode 100644
index 0000000..31ad12a
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java
@@ -0,0 +1,68 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractSessionMigrationTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * RemoteSessionMigrationTest
+ *
+ *
+ */
+public class RemoteSessionMigrationTest extends AbstractSessionMigrationTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionMigrationTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new InfinispanTestSessionServer(port, __testSupport.getCache());
+    }
+
+    @Override
+    public void testSessionMigration() throws Exception
+    {
+        super.testSessionMigration();
+    }
+   
+
+}
diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java
new file mode 100644
index 0000000..d7e7c80
--- /dev/null
+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java
@@ -0,0 +1,70 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session.remote;
+
+import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionRenewTest
+ *
+ *
+ */
+public class RemoteSessionRenewTest extends AbstractSessionRenewTest
+{
+
+    public static RemoteInfinispanTestSupport __testSupport;
+    
+    
+    @BeforeClass
+    public static void setup () throws Exception
+    {
+        __testSupport = new RemoteInfinispanTestSupport("remote-session-test");
+        __testSupport.setup();
+    }
+    
+    @AfterClass
+    public static void teardown () throws Exception
+    {
+        __testSupport.teardown();
+    }
+    
+    
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port, int max, int scavenge)
+    {
+        return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache());
+    }
+
+    @Test
+    public void testSessionRenewal() throws Exception
+    {
+        super.testSessionRenewal();
+    }
+
+    
+}
diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml
index fd43aa6..1c71823 100644
--- a/tests/test-sessions/test-jdbc-sessions/pom.xml
+++ b/tests/test-sessions/test-jdbc-sessions/pom.xml
@@ -21,11 +21,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-jdbc-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: JDBC</name>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.jdbc</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
index 1445f33..5f638a9 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java
@@ -77,7 +77,7 @@
                 ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create");
                 
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
new file mode 100644
index 0000000..e0fce13
--- /dev/null
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java
@@ -0,0 +1,50 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+
+package org.eclipse.jetty.server.session;
+
+import org.junit.Test;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractForwardedSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new JdbcTestServer(port);
+    }
+
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        super.testSessionCreateInForward();
+    }
+    
+    
+    
+
+}
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java
index 8003b09..05b3786 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java
@@ -76,14 +76,14 @@
      * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager(String)
      */
     @Override
-    public  SessionIdManager newSessionIdManager(String config)
+    public  SessionIdManager newSessionIdManager(Object config)
     {
         synchronized(JdbcTestServer.class)
         {
             JDBCSessionIdManager idManager = new JDBCSessionIdManager(_server);
             idManager.setScavengeInterval(_scavengePeriod);
             idManager.setWorkerName("w"+(__workers++));
-            idManager.setDriverInfo(DRIVER_CLASS, (config==null?DEFAULT_CONNECTION_URL:config));
+            idManager.setDriverInfo(DRIVER_CLASS, (config==null?DEFAULT_CONNECTION_URL:(String)config));
             JDBCSessionIdManager.SessionIdTableSchema idTableSchema = new JDBCSessionIdManager.SessionIdTableSchema();
             idTableSchema.setTableName("mysessionids");
             idTableSchema.setIdColumn("myid");
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java
index 80a82f8..760f86b 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/MaxInactiveMigrationTest.java
@@ -103,7 +103,7 @@
         ContentResponse response = request.send();
         assertEquals(HttpServletResponse.SC_OK, response.getStatus());
 
-        sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+        sessionCookie = response.getHeaders().get("Set-Cookie");
         assertTrue( sessionCookie != null );
         // Mangle the cookie, replacing Path with $Path, etc.
         sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java
index 941f1e6..16ead94 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java
@@ -70,7 +70,7 @@
                 ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create");
                 
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java
index fe3ac56..6b010f0 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java
@@ -104,7 +104,7 @@
                 ContentResponse response = client.GET("http://localhost:" + port1 + contextPath +"/bar?action=set");
                 
                 assertEquals( HttpServletResponse.SC_OK, response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 String sessionId = (String)webApp.getServletContext().getAttribute("foo");
                 assertNotNull(sessionId);
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java
index ce32690..0652cf3 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SaveIntervalTest.java
@@ -35,8 +35,8 @@
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
-import org.junit.Test;
 import org.junit.Ignore;
+import org.junit.Test;
 
 /**
  *  SaveIntervalTest
@@ -77,7 +77,7 @@
                 // Perform a request to create a session              
                 ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java
index 0c55e84..99038d6 100644
--- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java
+++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java
@@ -18,23 +18,9 @@
 
 package org.eclipse.jetty.server.session;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
 import java.sql.DriverManager;
 import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionListener;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
 import org.junit.After;
 import org.junit.Test;
 
@@ -47,22 +33,6 @@
 public class SessionExpiryTest extends AbstractSessionExpiryTest
 {
 
-    public class TestHttpSessionListener implements HttpSessionListener
-    {
-        public List<String> createdSessions = new ArrayList<String>();
-        public List<String> destroyedSessions = new ArrayList<String>();
-        
-        public void sessionDestroyed(HttpSessionEvent se)
-        {
-            destroyedSessions.add(se.getSession().getId());
-        }
-        
-        public void sessionCreated(HttpSessionEvent se)
-        {
-            createdSessions.add(se.getSession().getId());
-        }
-    };
-    
     /** 
      * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int)
      */
@@ -75,70 +45,9 @@
     @Test
     public void testSessionExpiry() throws Exception
     {
-     
-        
-        String contextPath = "";
-        String servletMapping = "/server";
-        int inactivePeriod = 2;
-        int scavengePeriod = 1;
-        AbstractTestServer server1 = createServer(0, inactivePeriod, scavengePeriod);
-        TestServlet servlet = new TestServlet();
-        ServletHolder holder = new ServletHolder(servlet);
-        ServletContextHandler context = server1.addContext(contextPath);
-        context.addServlet(holder, servletMapping);
-        TestHttpSessionListener listener = new TestHttpSessionListener();
-        
-        context.getSessionHandler().addEventListener(listener);
-        
-        server1.start();
-        int port1 = server1.getPort();
-
-        try
-        {
-            HttpClient client = new HttpClient();
-            client.start();
-            String url = "http://localhost:" + port1 + contextPath + servletMapping;
-
-            //make a request to set up a session on the server
-            ContentResponse response1 = client.GET(url + "?action=init");
-            assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-            String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
-            assertTrue(sessionCookie != null);
-            // Mangle the cookie, replacing Path with $Path, etc.
-            sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
-            
-            String sessionId = extractSessionId(sessionCookie);     
-            
-            assertTrue(listener.createdSessions.contains(sessionId));
-            //now stop the server
-            server1.stop();
-
-            //and wait until the expiry time has passed
-            pause(inactivePeriod);
-
-            //restart the server
-            server1.start();
-            
-            port1 = server1.getPort();
-            url = "http://localhost:" + port1 + contextPath + servletMapping;
-
-            //make another request, the session should have expired
-            Request request = client.newRequest(url + "?action=test");
-            request.getHeaders().add("Cookie", sessionCookie);
-            ContentResponse response2 = request.send();
-            assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
-            
-            //and wait until the expiry time has passed
-            pause(inactivePeriod);
-            
-            assertTrue(listener.destroyedSessions.contains(sessionId));
-        }
-        finally
-        {
-            server1.stop();
-        }     
+        super.testSessionExpiry();
     }
-  
+    
     
     
     
@@ -149,24 +58,7 @@
         super.testSessionNotExpired();
     }
 
-    
-    
-    public String extractSessionId (String sessionCookie)
-    {
-        if (sessionCookie == null)
-            return null;
-        sessionCookie = sessionCookie.trim();
-        int i = sessionCookie.indexOf(';');
-        if (i >= 0)
-            sessionCookie = sessionCookie.substring(0,i);
-        if (sessionCookie.startsWith("JSESSIONID"))
-            sessionCookie = sessionCookie.substring("JSESSIONID=".length());
-        i = sessionCookie.indexOf('.');
-        if (i >=0)
-            sessionCookie = sessionCookie.substring(0,i);
-        return sessionCookie;
-    }
-
+  
     
     
     @After
diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml
index f049953..4d9bde7 100644
--- a/tests/test-sessions/test-mongodb-sessions/pom.xml
+++ b/tests/test-sessions/test-mongodb-sessions/pom.xml
@@ -21,11 +21,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-mongodb-sessions</artifactId>
   <name>Jetty Tests :: Sessions :: Mongo</name>
   <url>http://www.eclipse.org/jetty</url>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.mongo</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java
index 8f6cdd8..3525b2c 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java
@@ -33,6 +33,7 @@
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.nosql.NoSqlSession;
 import org.eclipse.jetty.server.session.AbstractTestServer;
 import org.junit.Test;
@@ -94,7 +95,8 @@
                 assertEquals("a.b.c",sessionTestResponse[0]);
  
 
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get(HttpHeader.SET_COOKIE);
+                      
                 assertTrue(sessionCookie != null);
                 //Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path=");
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java
index a44f800..e30476d 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java
new file mode 100644
index 0000000..7697ab2
--- /dev/null
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java
@@ -0,0 +1,48 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.nosql.mongodb;
+
+import org.eclipse.jetty.server.session.AbstractForwardedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.Test;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{
+
+    /** 
+     * @see org.eclipse.jetty.server.session.AbstractForwardedSessionTest#createServer(int)
+     */
+    @Override
+    public AbstractTestServer createServer(int port)
+    {
+        return new MongoTestServer(port);
+    }
+    
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        super.testSessionCreateInForward();
+    }
+}
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java
deleted file mode 100644
index 184e6a0..0000000
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.nosql.mongodb;
-
-import org.eclipse.jetty.server.session.AbstractLightLoadTest;
-import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
-import org.junit.Test;
-
-/**
- * LightLoadTest
- */
-public class LightLoadTest extends AbstractLightLoadTest
-{
-
-    public AbstractTestServer createServer(int port)
-    {
-        return new MongoTestServer(port);
-    }
-
-    @Test
-    public void testLightLoad() throws Exception
-    {
-        super.testLightLoad();
-    }
-
-}
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java
index 97c72cf..3a6a7c5 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java
@@ -27,7 +27,9 @@
     @Override
     public AbstractTestServer createServer(int port, int max, int scavenge)
     {
-       return new MongoTestServer(port,max,scavenge);
+       MongoTestServer mserver=new MongoTestServer(port,max,scavenge);
+       ((MongoSessionIdManager)mserver.getServer().getSessionIdManager()).setScavengeBlockSize(0);
+       return mserver;
     }
 
     @Override
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java
index f1cda54..5a5bfac 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java
@@ -18,15 +18,19 @@
 
 package org.eclipse.jetty.nosql.mongodb;
 
-import java.util.concurrent.TimeUnit;
+import java.net.UnknownHostException;
 
-import org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager;
-import org.eclipse.jetty.nosql.mongodb.MongoSessionManager;
+import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.SessionManager;
 import org.eclipse.jetty.server.session.AbstractTestServer;
 import org.eclipse.jetty.server.session.SessionHandler;
 
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCursor;
+import com.mongodb.DBObject;
+import com.mongodb.MongoException;
+
 
 /**
  * @version $Revision$ $Date$
@@ -36,6 +40,28 @@
     static int __workers=0;
     private boolean _saveAllAttributes = false; // false save dirty, true save all
     
+    
+    public static class TestMongoSessionIdManager extends MongoSessionIdManager 
+    {
+
+        public TestMongoSessionIdManager(Server server) throws UnknownHostException, MongoException
+        {
+            super(server);
+        }
+        
+        
+        public void deleteAll ()
+        {
+            
+            DBCursor checkSessions = _sessions.find();
+
+            for (DBObject session : checkSessions)
+            {
+                _sessions.remove(session);
+            }
+        }
+    }
+    
     public MongoTestServer(int port)
     {
         super(port, 30, 10);
@@ -54,12 +80,12 @@
         _saveAllAttributes = saveAllAttributes;
     }
 
-    public SessionIdManager newSessionIdManager(String config)
+    public SessionIdManager newSessionIdManager(Object config)
     {
         try
         {
             System.err.println("MongoTestServer:SessionIdManager scavenge: delay:"+ _scavengePeriod + " period:"+_scavengePeriod);
-            MongoSessionIdManager idManager = new MongoSessionIdManager(_server);
+            MongoSessionIdManager idManager = new TestMongoSessionIdManager(_server);
             idManager.setWorkerName("w"+(__workers++));
             idManager.setScavengePeriod(_scavengePeriod);                  
 
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java
index 84763e1..91fa831 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractNewSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java
index fa93c75..b4c792a 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractOrphanedSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java
index 61a9d35..7b9cd4d 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeInvalidSessionTest.java
@@ -19,8 +19,8 @@
 package org.eclipse.jetty.nosql.mongodb;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.net.UnknownHostException;
@@ -73,7 +73,7 @@
         MongoTestServer server = createServer(0, 1, 0);
         ServletContextHandler context = server.addContext(contextPath);
         context.addServlet(TestServlet.class, servletMapping);
-        
+
         MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
         MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
         idManager.setPurge(true);
@@ -94,7 +94,7 @@
                 //Create a session
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -124,8 +124,83 @@
         }
 
     }
-    
-    
+
+
+    @Test
+    public void testPurgeInvalidSessionsWithLimit() throws Exception
+    {
+        String contextPath = "";
+        String servletMapping = "/server";
+        long purgeInvalidAge = 1000; //1 sec
+        int purgeLimit = 5; // only purge 5 sessions for each purge run
+
+        //ensure scavenging is turned off so the purger gets a chance to find the session
+        MongoTestServer server = createServer(0, 1, 0);
+        ServletContextHandler context = server.addContext(contextPath);
+        context.addServlet(TestServlet.class, servletMapping);
+
+        // disable purging so we can call it manually below
+        MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
+        MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
+        idManager.setPurge(false);
+        idManager.setPurgeLimit(purgeLimit);
+        idManager.setPurgeInvalidAge(purgeInvalidAge);
+        // don't purge valid sessions
+        idManager.setPurgeValidAge(0);
+
+
+        server.start();
+        int port=server.getPort();
+        try
+        {
+            // cleanup any previous sessions that are invalid so that we are starting fresh
+            idManager.purgeFully();
+            long sessionCountAtTestStart = sessionManager.getSessionStoreCount();
+
+            HttpClient client = new HttpClient();
+            client.start();
+            try
+            {
+                // create double the purge limit of sessions, and make them all invalid
+                for (int i = 0; i < purgeLimit * 2; i++)
+                {
+                    ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
+                    assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+                    String sessionCookie = response.getHeaders().get("Set-Cookie");
+                    assertTrue(sessionCookie != null);
+                    // Mangle the cookie, replacing Path with $Path, etc.
+                    sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
+
+
+                    Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=invalidate");
+                    request.header("Cookie", sessionCookie);
+                    response = request.send();
+                    assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+                }
+
+                // sleep for our invalid age period so that the purge below does something
+                Thread.sleep(purgeInvalidAge * 2);
+
+                // validate that we have the right number of sessions before we purge
+                assertEquals("Expected to find right number of sessions before purge", sessionCountAtTestStart + (purgeLimit * 2), sessionManager.getSessionStoreCount());
+
+                // run our purge we should still have items in the DB
+                idManager.purge();
+                assertEquals("Expected to find sessions remaining in db after purge run with limit set",
+                        sessionCountAtTestStart + purgeLimit, sessionManager.getSessionStoreCount());
+            }
+            finally
+            {
+                client.stop();
+            }
+        }
+        finally
+        {
+            server.stop();
+        }
+    }
+
+
     public static class TestServlet extends HttpServlet
     {
         DBCollection _sessions;
@@ -163,6 +238,8 @@
                 dbSession = _sessions.findOne(new BasicDBObject("id", id));       
                 assertNotNull(dbSession);
                 assertTrue(dbSession.containsField(MongoSessionManager.__INVALIDATED));
+                assertTrue(dbSession.containsField(MongoSessionManager.__VALID));
+                assertTrue(dbSession.get(MongoSessionManager.__VALID).equals(false));
             }
             else if ("test".equals(action))
             {
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java
index c8583df..16ed847 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/PurgeValidSessionTest.java
@@ -19,8 +19,8 @@
 package org.eclipse.jetty.nosql.mongodb;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.net.UnknownHostException;
@@ -31,10 +31,10 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-
 import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.nosql.mongodb.MongoTestServer.TestMongoSessionIdManager;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.junit.Test;
 
@@ -97,7 +97,7 @@
                 //Create a session
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -124,6 +124,75 @@
     }
 
 
+    @Test
+    public void testPurgeValidSessionWithPurgeLimitSet() throws Exception
+    {
+        String contextPath = "";
+        String servletMapping = "/server";
+        long purgeDelay = 1000; //1 sec
+        long purgeValidAge = 1000; // 1 sec
+        int purgeLimit = 5; // only purge 5 items in each purge run
+
+        //ensure scavenging is turned off so the purger gets a chance to find the session
+        MongoTestServer server = createServer(0, 1, 0);
+        ServletContextHandler context = server.addContext(contextPath);
+        context.addServlet(TestServlet.class, servletMapping);
+
+        MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
+        MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
+        // disable purging we will run it manually below
+        idManager.setPurge(false);
+        idManager.setPurgeLimit(purgeLimit);
+        idManager.setPurgeDelay(purgeDelay);
+        idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
+
+        server.start();
+        int port=server.getPort();
+
+        try
+        {
+            // start with no sessions
+            ((TestMongoSessionIdManager)idManager).deleteAll();
+
+            HttpClient client = new HttpClient();
+            client.start();
+            try
+            {
+                // create double our purgeLmit number of sessions
+                for (int i = 0; i < purgeLimit * 2; i++)
+                {
+                    ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
+                    assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+                    String sessionCookie = response.getHeaders().get("Set-Cookie");
+                    assertTrue(sessionCookie != null);
+                    // don't remember our cookies from call to call
+                    client.getCookieStore().removeAll();
+                }
+
+                // delay long enough for purgeValidAge to apply
+                Thread.sleep(2* purgeValidAge);
+
+                // validate that we have the right number of sessions before we purge
+                assertEquals("Expected to find right number of sessions before purge", purgeLimit * 2, sessionManager.getSessionStoreCount());
+
+                // run our purge
+                idManager.purge();
+
+                assertEquals("Expected to find sessions remaining in db after purge run with limit set",
+                        purgeLimit, sessionManager.getSessionStoreCount());
+            }
+            finally
+            {
+                client.stop();
+            }
+        }
+        finally
+        {
+            server.stop();
+        }
+
+    }
+
     public static class TestServlet extends HttpServlet
     {
         DBCollection _sessions;
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java
index 528815d..af7a885 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java
index d0f63a0..670aeb7 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractRemoveSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class RemoveSessionTest extends AbstractRemoveSessionTest
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java
new file mode 100644
index 0000000..107d046
--- /dev/null
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java
@@ -0,0 +1,42 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting 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.nosql.mongodb;
+
+import org.eclipse.jetty.server.session.AbstractScatterGunLoadTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.Test;
+
+/**
+ * ScatterGunLoadTest
+ */
+public class ScatterGunLoadTest extends AbstractScatterGunLoadTest
+{
+
+    public AbstractTestServer createServer(int port)
+    {
+        return new MongoTestServer(port);
+    }
+
+    @Test
+    public void testLightLoad() throws Exception
+    {
+        super.testLightLoad();
+    }
+
+}
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java
index 61d0f17..dab0a75 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java
index 21bcb62..111b3ac 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java
@@ -20,7 +20,6 @@
 
 import org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest;
 import org.eclipse.jetty.server.session.AbstractTestServer;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java
index 236ad01..3744498 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java
@@ -26,7 +26,6 @@
 import java.io.Serializable;
 import java.lang.management.ManagementFactory;
 import java.net.MalformedURLException;
-import java.util.concurrent.Future;
 
 import javax.management.remote.JMXServiceURL;
 import javax.servlet.ServletException;
@@ -117,7 +116,7 @@
 
                 sessionTestValue = sessionTestResponse;
 
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path=");
@@ -144,7 +143,7 @@
 
                     sessionTestValue = sessionTestResponse;
 
-                    String setCookie = response2.getHeaders().getStringField("Set-Cookie");
+                    String setCookie = response2.getHeaders().get("Set-Cookie");
                     if (setCookie != null)
                         sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path=");
 
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java
index 0431012..37a91c6 100644
--- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java
+++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/StopSessionManagerDeleteSessionTest.java
@@ -86,7 +86,7 @@
                 //Create a session
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml
index 04c3463..398ef01 100644
--- a/tests/test-sessions/test-sessions-common/pom.xml
+++ b/tests/test-sessions/test-sessions-common/pom.xml
@@ -21,11 +21,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-sessions-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-sessions-common</artifactId>
   <name>Jetty Tests :: Sessions :: Common</name>
   <url>http://www.eclipse.org/jetty</url>
+    <properties>
+    <bundle-symbolic-name>${project.groupId}.sessions.common</bundle-symbolic-name>
+  </properties>
   <build>
   </build>
   <dependencies>
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java
index cab83ae..0daaf73 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClientCrossContextSessionTest.java
@@ -74,7 +74,7 @@
                 ContentResponse response = client.GET("http://localhost:" + port + contextA + servletMapping);
 
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractForwardedSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractForwardedSessionTest.java
new file mode 100644
index 0000000..cf50507
--- /dev/null
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractForwardedSessionTest.java
@@ -0,0 +1,183 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.junit.Test;
+
+
+/**
+ * AbstractForwardedSessionTest
+ *
+ * Test that creating a session inside a forward on the same context works, and that
+ * attributes set after the forward returns are preserved.
+ * 
+ * This test requires that the sessions will be persisted, as the server is stopped and
+ * then restarted in order to check that all the attributes were saved.
+ */
+public abstract class AbstractForwardedSessionTest
+{
+   
+
+    public abstract AbstractTestServer createServer(int port);
+    
+    
+    @Test
+    public void testSessionCreateInForward() throws Exception
+    {
+        AbstractTestServer testServer = createServer(0);
+        ServletContextHandler testServletContextHandler = testServer.addContext("/context");
+        testServletContextHandler.addServlet(Servlet1.class, "/one");
+        testServletContextHandler.addServlet(Servlet2.class, "/two");
+        testServletContextHandler.addServlet(Servlet3.class, "/three");
+        testServletContextHandler.addServlet(Servlet4.class, "/four");
+       
+      
+
+        try
+        {
+            testServer.start();
+            int serverPort=testServer.getPort();
+            HttpClient client = new HttpClient();
+            client.start();
+            try
+            {
+                //make a request to the first servlet, which will forward it to other servlets
+                ContentResponse response = client.GET("http://localhost:" + serverPort + "/context/one");
+                assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
+                assertTrue(sessionCookie != null);
+                // Mangle the cookie, replacing Path with $Path, etc.
+                sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
+
+                //test that the session was created, and that it contains the attributes from servlet3 and servlet1
+                
+                //stop the server, to make sure any session persistence has happened
+                testServer.stop();
+                            
+                //restart
+                testServer.start();
+                serverPort = testServer.getPort();
+       
+                //Make a fresh request
+                Request request = client.newRequest("http://localhost:" + serverPort + "/context/four");
+                request.header("Cookie", sessionCookie);
+                response = request.send();
+                assertEquals(HttpServletResponse.SC_OK, response.getStatus());
+                
+            }
+            finally
+            {
+                client.stop();
+            }
+        }
+        finally
+        {
+            testServer.stop();
+        }
+        
+    }
+    
+
+    public static class Servlet1 extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            //Don't create a session, just forward to another session in the same context
+            assertNull(request.getSession(false));
+            
+            //The session will be created by the other servlet, so will exist as this dispatch returns
+            RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher("/two");
+            dispatcher.forward(request, response);
+   
+            HttpSession sess = request.getSession(false);
+            assertNotNull(sess);
+            sess.setAttribute("servlet1", "servlet1");
+        }
+    }
+
+    public static class Servlet2 extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {
+            //forward to yet another servlet to do the creation
+            assertNull(request.getSession(false));
+
+            RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher("/three");
+            dispatcher.forward(request, response);
+            
+            //the session should exist after the forward
+            HttpSession sess = request.getSession(false);
+            assertNotNull(sess);
+        }
+    }
+
+
+
+    public static class Servlet3 extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {    
+            //No session yet
+            assertNull(request.getSession(false));
+            
+            //Create it
+            HttpSession session = request.getSession();
+            assertNotNull(session);
+            
+            //Set an attribute on it
+            session.setAttribute("servlet3", "servlet3");
+        }
+    }
+    
+    
+    public static class Servlet4 extends HttpServlet
+    {
+        @Override
+        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+        {    
+            //Check that the session contains attributes set during and after the session forward
+            HttpSession session = request.getSession();
+            assertNotNull(session);
+            assertNotNull(session.getAttribute("servlet1"));
+            assertNotNull(session.getAttribute("servlet3"));
+        }
+    }
+    
+}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java
index fa569a0..0d004e8 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractImmortalSessionTest.java
@@ -64,7 +64,7 @@
                 int value = 42;
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=set&value=" + value);
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java
index a8415e9..1953bc0 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractInvalidationSessionTest.java
@@ -79,23 +79,26 @@
                     ContentResponse response1 = client.GET(urls[0] + "?action=init");
 
                     assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue(sessionCookie != null);
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
-
+                    
+                    
                     // Be sure the session is also present in node2
 
                     Request request2 = client.newRequest(urls[1] + "?action=increment");
                     request2.header("Cookie", sessionCookie);
                     ContentResponse response2 = request2.send();
                     assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
+ 
 
                     // Invalidate on node1
                     Request request1 = client.newRequest(urls[0] + "?action=invalidate");
                     request1.header("Cookie", sessionCookie);
                     response1 = request1.send();
                     assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
+           
 
                     pause();
 
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java
index c720dc6..574a528 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLastAccessTimeTest.java
@@ -87,7 +87,7 @@
                     ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init");
                     assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
                     assertEquals("test", response1.getContentAsString());
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue( sessionCookie != null );
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -106,7 +106,7 @@
                         assertEquals(HttpServletResponse.SC_OK , response2.getStatus());
                         assertEquals("test", response2.getContentAsString());
 
-                        String setCookie = response2.getHeaders().getStringField("Set-Cookie");
+                        String setCookie = response2.getHeaders().get("Set-Cookie");
                         if (setCookie!=null)
                             sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
 
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java
deleted file mode 100644
index 35bbd31..0000000
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java
+++ /dev/null
@@ -1,234 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
-//  ------------------------------------------------------------------------
-//  All rights reserved. This program and the accompanying materials
-//  are made available under the terms of the Eclipse Public License v1.0
-//  and Apache License v2.0 which accompanies this distribution.
-//
-//      The Eclipse Public License is available at
-//      http://www.eclipse.org/legal/epl-v10.html
-//
-//      The Apache License v2.0 is available at
-//      http://www.opensource.org/licenses/apache2.0.php
-//
-//  You may elect to redistribute this code under either of these licenses.
-//  ========================================================================
-//
-
-package org.eclipse.jetty.server.session;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Random;
-import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.eclipse.jetty.client.HttpClient;
-import org.eclipse.jetty.client.api.ContentResponse;
-import org.eclipse.jetty.client.api.Request;
-import org.junit.Test;
-
-
-/**
- * AbstractLightLoadTest
- */
-public abstract class AbstractLightLoadTest
-{
-    protected boolean _stress = Boolean.getBoolean( "STRESS" );
-
-    public abstract AbstractTestServer createServer(int port);
-
-    @Test
-    public void testLightLoad()
-        throws Exception
-    {
-        if ( _stress )
-        {
-            String contextPath = "";
-            String servletMapping = "/server";
-            AbstractTestServer server1 = createServer( 0 );
-            server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
-
-            try
-            {
-                server1.start();
-                int port1 = server1.getPort();
-                AbstractTestServer server2 = createServer( 0 );
-                server2.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
-
-                try
-                {
-                    server2.start();
-                    int port2=server2.getPort();
-                    HttpClient client = new HttpClient();
-                    client.start();
-                    try
-                    {
-                        String[] urls = new String[2];
-                        urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
-                        urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
-
-                        ContentResponse response1 = client.GET(urls[0] + "?action=init");
-                        assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                        String sessionCookie = response1.getHeaders().getStringField( "Set-Cookie" );
-                        assertTrue(sessionCookie != null);
-                        // Mangle the cookie, replacing Path with $Path, etc.
-                        sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
-
-                        ExecutorService executor = Executors.newCachedThreadPool();
-                        int clientsCount = 50;
-                        CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
-                        int requestsCount = 100;
-                        Worker[] workers = new Worker[clientsCount];
-                        for ( int i = 0; i < clientsCount; ++i )
-                        {
-                            workers[i] = new Worker( barrier, requestsCount, sessionCookie, urls );
-                            workers[i].start();
-                            executor.execute( workers[i] );
-                        }
-                        // Wait for all workers to be ready
-                        barrier.await();
-                        long start = System.nanoTime();
-
-                        // Wait for all workers to be done
-                        barrier.await();
-                        long end = System.nanoTime();
-                        long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
-                        System.out.println( "elapsed ms: " + elapsed );
-
-                        for ( Worker worker : workers )
-                            worker.stop();
-                        executor.shutdownNow();
-
-                        // Perform one request to get the result
-                        Request request = client.newRequest( urls[0] + "?action=result" );
-                        request.header("Cookie", sessionCookie);
-                        ContentResponse response2 = request.send();
-                        assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
-                        String response = response2.getContentAsString();
-                        System.out.println( "get = " + response );
-                        assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
-                    }
-                    finally
-                    {
-                        client.stop();
-                    }
-                }
-                finally
-                {
-                    server2.stop();
-                }
-            }
-            finally
-            {
-                server1.stop();
-            }
-        }
-    }
-
-    public static class Worker
-        implements Runnable
-    {
-        private final HttpClient client;
-
-        private final CyclicBarrier barrier;
-
-        private final int requestsCount;
-
-        private final String sessionCookie;
-
-        private final String[] urls;
-
-
-        public Worker( CyclicBarrier barrier, int requestsCount, String sessionCookie, String[] urls )
-        {
-            this.client = new HttpClient();
-            this.barrier = barrier;
-            this.requestsCount = requestsCount;
-            this.sessionCookie = sessionCookie;
-            this.urls = urls;
-        }
-
-        public void start()
-            throws Exception
-        {
-            client.start();
-        }
-
-        public void stop()
-            throws Exception
-        {
-            client.stop();
-        }
-
-        public void run()
-        {
-            try
-            {
-                // Wait for all workers to be ready
-                barrier.await();
-
-                Random random = new Random( System.nanoTime() );
-
-                for ( int i = 0; i < requestsCount; ++i )
-                {
-                    int urlIndex = random.nextInt( urls.length );
-                    Request request = client.newRequest(urls[urlIndex] + "?action=increment");
-                    request.header("Cookie", sessionCookie);
-                    ContentResponse response = request.send();
-                    assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                }
-
-                // Wait for all workers to be done
-                barrier.await();
-            }
-            catch ( Exception x )
-            {
-                throw new RuntimeException( x );
-            }
-        }
-    }
-
-    public static class TestServlet
-        extends HttpServlet
-    {
-        @Override
-        protected void doGet( HttpServletRequest request, HttpServletResponse response )
-            throws ServletException, IOException
-        {
-            String action = request.getParameter( "action" );
-            if ( "init".equals( action ) )
-            {
-                HttpSession session = request.getSession( true );
-                session.setAttribute( "value", 0 );
-            }
-            else if ( "increment".equals( action ) )
-            {
-                // Without synchronization, because it is taken care by Jetty/Terracotta
-                HttpSession session = request.getSession( false );
-                int value = (Integer) session.getAttribute( "value" );
-                session.setAttribute( "value", value + 1 );
-            }
-            else if ( "result".equals( action ) )
-            {
-                HttpSession session = request.getSession( false );
-                int value = (Integer) session.getAttribute( "value" );
-                PrintWriter writer = response.getWriter();
-                writer.println( value );
-                writer.flush();
-            }
-        }
-    }
-}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java
index c3964d0..6c6a79e 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java
@@ -86,7 +86,7 @@
                     // Create the session on node1
                     ContentResponse response1 = client.GET(urls[0] + "?action=init");
                     assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue(sessionCookie != null);
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java
index 1ea6860..1c9b3ef 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNewSessionTest.java
@@ -74,7 +74,7 @@
             {
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java
index 9b8d83d..dc4f146 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractOrphanedSessionTest.java
@@ -46,6 +46,7 @@
     /**
      * If nodeA creates a session, and just afterwards crashes, it is the only node that knows about the session.
      * We want to test that the session data is gone after scavenging.
+     * @throws Exception on test failure
      */
     @Test
     public void testOrphanedSession() throws Exception
@@ -74,7 +75,7 @@
                     // Connect to server1 to create a session and get its session cookie
                     ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init");
                     assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue(sessionCookie != null);
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java
index fa4201d..8753039 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java
@@ -101,7 +101,7 @@
             {
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java
index 0c1b271..4679b43 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractRemoveSessionTest.java
@@ -66,7 +66,7 @@
             {
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -82,8 +82,7 @@
                 assertTrue(testListener.isDestroyed());
 
 
-                // The session is not there anymore, but we present an old cookie
-                // The server creates a new session, we must ensure we released all locks
+                // The session is not there anymore, even if we present an old cookie
                 request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=check");
                 request.header("Cookie", sessionCookie);
                 response = request.send();
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java
new file mode 100644
index 0000000..f60989f
--- /dev/null
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java
@@ -0,0 +1,231 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Random;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.junit.Test;
+
+
+/**
+ * AbstractSameNodeLoadTest
+ * 
+ * This test performs multiple concurrent requests for the same session on the same node.
+ * 
+ */
+public abstract class AbstractSameNodeLoadTest
+{
+    protected boolean _stress = Boolean.getBoolean( "STRESS" );
+
+    public abstract AbstractTestServer createServer(int port);
+
+    @Test
+    public void testLoad() throws Exception
+    {
+        if ( _stress )
+        {
+            String contextPath = "";
+            String servletMapping = "/server";
+            AbstractTestServer server1 = createServer( 0 );
+            server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
+
+            try
+            {
+                server1.start();
+                int port1 = server1.getPort();
+
+                HttpClient client = new HttpClient();
+                client.start();
+                try
+                {
+                    String url = "http://localhost:" + port1 + contextPath + servletMapping;
+
+
+                    //create session via first server
+                    ContentResponse response1 = client.GET(url + "?action=init");
+                    assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
+                    String sessionCookie = response1.getHeaders().getStringField( "Set-Cookie" );
+                    assertTrue(sessionCookie != null);
+                    // Mangle the cookie, replacing Path with $Path, etc.
+                    sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
+
+                    //simulate 10 clients making 100 requests each
+                    ExecutorService executor = Executors.newCachedThreadPool();
+                    int clientsCount = 10;
+                    CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
+                    int requestsCount = 100;
+                    Worker[] workers = new Worker[clientsCount];
+                    for ( int i = 0; i < clientsCount; ++i )
+                    {
+                        workers[i] = new Worker(barrier, client, requestsCount, sessionCookie, url);
+                        executor.execute( workers[i] );
+                    }
+                    // Wait for all workers to be ready
+                    barrier.await();
+                    long start = System.nanoTime();
+
+                    // Wait for all workers to be done
+                    barrier.await();
+                    long end = System.nanoTime();
+                    long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
+                    System.out.println( "elapsed ms: " + elapsed );
+
+                    executor.shutdownNow();
+
+                    // Perform one request to get the result
+                    Request request = client.newRequest( url + "?action=result" );
+                    request.header("Cookie", sessionCookie);
+                    ContentResponse response2 = request.send();
+                    assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
+                    String response = response2.getContentAsString();
+                    System.out.println( "get = " + response );
+                    assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
+                }
+                finally
+                {
+                    client.stop();
+                }
+            }
+            finally
+            {
+                server1.stop();
+            }
+        }
+    }
+
+    public static class Worker implements Runnable
+    {
+        public static int COUNT = 0;
+        
+        private final HttpClient client;
+
+        private final CyclicBarrier barrier;
+
+        private final int requestsCount;
+
+        private final String sessionCookie;
+
+        private final String url;
+        
+        private final String name;
+
+
+        public Worker(CyclicBarrier barrier, HttpClient client, int requestsCount, String sessionCookie, String url)
+        {
+            this.client = client;
+            this.barrier = barrier;
+            this.requestsCount = requestsCount;
+            this.sessionCookie = sessionCookie;
+            this.url = url;
+            this.name = ""+(COUNT++);
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                // Wait for all workers to be ready
+                barrier.await();
+
+                Random random = new Random( System.nanoTime() );
+
+                for ( int i = 0; i < requestsCount; ++i )
+                {
+                    int pauseMsec = random.nextInt(1000);
+
+                    //wait a random number of milliseconds between requests up to 1 second
+                    if (pauseMsec > 0)
+                    {
+                        Thread.currentThread().sleep(pauseMsec);
+                    }
+                    Request request = client.newRequest(url + "?action=increment");
+                    request.header("Cookie", sessionCookie);
+                    ContentResponse response = request.send();
+                    assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+                }
+
+                // Wait for all workers to be done
+                barrier.await();
+            }
+            catch ( Exception x )
+            {
+                throw new RuntimeException( x );
+            }
+        }
+    }
+
+    public static class TestServlet
+        extends HttpServlet
+    {
+        @Override
+        protected void doGet( HttpServletRequest request, HttpServletResponse response )
+            throws ServletException, IOException
+        {
+            String action = request.getParameter( "action" );
+            if ( "init".equals( action ) )
+            {
+                HttpSession session = request.getSession( true );
+                session.setAttribute( "value", 0 );
+            }
+            else if ( "increment".equals( action ) )
+            {
+                HttpSession session = request.getSession( false );
+                assertNotNull(session);
+                synchronized(session)
+                {
+                    int value = (Integer) session.getAttribute( "value" );
+                    session.setAttribute( "value", value + 1 );
+                }
+            }
+            else if ( "result".equals( action ) )
+            {
+                HttpSession session = request.getSession( false );
+                assertNotNull(session);
+                Integer value = null;
+                synchronized (session)
+                {
+                    value = (Integer) session.getAttribute( "value" );
+                }
+                PrintWriter writer = response.getWriter();
+                writer.println( value );
+                writer.flush();
+            }
+        }
+    }
+}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java
new file mode 100644
index 0000000..27d832c
--- /dev/null
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java
@@ -0,0 +1,242 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Random;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.junit.Test;
+
+
+/**
+ * AbstractScatterGunLoadTest
+ * 
+ * This is an unrealistic test. It takes a scatter-gun approach to smearing a
+ * single session across 2 different nodes at once. 
+ * 
+ * In the real world, we must have a load balancer that uses sticky sessions
+ * to keep the session pinned to a particular node.
+ */
+public abstract class AbstractScatterGunLoadTest
+{
+    protected boolean _stress = Boolean.getBoolean( "STRESS" );
+
+    public abstract AbstractTestServer createServer(int port);
+
+    @Test
+    public void testLightLoad()
+        throws Exception
+    {
+        if ( _stress )
+        {
+            String contextPath = "";
+            String servletMapping = "/server";
+            AbstractTestServer server1 = createServer( 0 );
+            server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
+
+            try
+            {
+                server1.start();
+                int port1 = server1.getPort();
+                AbstractTestServer server2 = createServer( 0 );
+                server2.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
+
+                try
+                {
+                    server2.start();
+                    int port2=server2.getPort();
+                    HttpClient client = new HttpClient();
+                    client.start();
+                    try
+                    {
+                        String[] urls = new String[2];
+                        urls[0] = "http://localhost:" + port1 + contextPath + servletMapping;
+                        urls[1] = "http://localhost:" + port2 + contextPath + servletMapping;
+
+                        //create session via first server
+                        ContentResponse response1 = client.GET(urls[0] + "?action=init");
+                        assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
+                        String sessionCookie = response1.getHeaders().get( "Set-Cookie" );
+                        assertTrue(sessionCookie != null);
+                        // Mangle the cookie, replacing Path with $Path, etc.
+                        sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
+
+                        //simulate 50 clients making 100 requests each
+                        ExecutorService executor = Executors.newCachedThreadPool();
+                        int clientsCount = 50;
+                        CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
+                        int requestsCount = 100;
+                        Worker[] workers = new Worker[clientsCount];
+                        for ( int i = 0; i < clientsCount; ++i )
+                        {
+                            workers[i] = new Worker( barrier, requestsCount, sessionCookie, urls );
+                            workers[i].start();
+                            executor.execute( workers[i] );
+                        }
+                        // Wait for all workers to be ready
+                        barrier.await();
+                        long start = System.nanoTime();
+
+                        // Wait for all workers to be done
+                        barrier.await();
+                        long end = System.nanoTime();
+                        long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
+                        System.out.println( "elapsed ms: " + elapsed );
+
+                        for ( Worker worker : workers )
+                            worker.stop();
+                        executor.shutdownNow();
+
+                        // Perform one request to get the result
+                        Request request = client.newRequest( urls[0] + "?action=result" );
+                        request.header("Cookie", sessionCookie);
+                        ContentResponse response2 = request.send();
+                        assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
+                        String response = response2.getContentAsString();
+                        System.out.println( "get = " + response );
+                        assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
+                    }
+                    finally
+                    {
+                        client.stop();
+                    }
+                }
+                finally
+                {
+                    server2.stop();
+                }
+            }
+            finally
+            {
+                server1.stop();
+            }
+        }
+    }
+
+    public static class Worker
+        implements Runnable
+    {
+        private final HttpClient client;
+
+        private final CyclicBarrier barrier;
+
+        private final int requestsCount;
+
+        private final String sessionCookie;
+
+        private final String[] urls;
+
+
+        public Worker( CyclicBarrier barrier, int requestsCount, String sessionCookie, String[] urls )
+        {
+            this.client = new HttpClient();
+            this.barrier = barrier;
+            this.requestsCount = requestsCount;
+            this.sessionCookie = sessionCookie;
+            this.urls = urls;
+        }
+
+        public void start()
+            throws Exception
+        {
+            client.start();
+        }
+
+        public void stop()
+            throws Exception
+        {
+            client.stop();
+        }
+
+        public void run()
+        {
+            try
+            {
+                // Wait for all workers to be ready
+                barrier.await();
+
+                Random random = new Random( System.nanoTime() );
+
+                for ( int i = 0; i < requestsCount; ++i )
+                {
+                    int urlIndex = random.nextInt( urls.length );
+                    Request request = client.newRequest(urls[urlIndex] + "?action=increment");
+                    request.header("Cookie", sessionCookie);
+                    ContentResponse response = request.send();
+                    assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+                }
+
+                // Wait for all workers to be done
+                barrier.await();
+            }
+            catch ( Exception x )
+            {
+                throw new RuntimeException( x );
+            }
+        }
+    }
+
+    public static class TestServlet
+        extends HttpServlet
+    {
+        @Override
+        protected void doGet( HttpServletRequest request, HttpServletResponse response )
+            throws ServletException, IOException
+        {
+            String action = request.getParameter( "action" );
+            if ( "init".equals( action ) )
+            {
+                HttpSession session = request.getSession( true );
+                session.setAttribute( "value", 0 );
+            }
+            else if ( "increment".equals( action ) )
+            {
+                // Without synchronization
+                HttpSession session = request.getSession( false );
+                int value = (Integer) session.getAttribute( "value" );
+                session.setAttribute( "value", value + 1 );
+            }
+            else if ( "result".equals( action ) )
+            {
+                HttpSession session = request.getSession( false );
+                int value = (Integer) session.getAttribute( "value" );
+                PrintWriter writer = response.getWriter();
+                writer.println( value );
+                writer.flush();
+            }
+        }
+    }
+}
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java
index 3b2003f..ef207b5 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCookieTest.java
@@ -39,7 +39,7 @@
 import org.junit.Test;
 
 /**
- * AbstractNewSessionTest
+ * AbstractSessionCookieTest
  */
 public abstract class AbstractSessionCookieTest
 {
@@ -81,7 +81,7 @@
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
 
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 //sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java
index 56da09e..e67d586 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java
@@ -22,16 +22,21 @@
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
 
 import org.eclipse.jetty.client.HttpClient;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.junit.Test;
 
@@ -50,6 +55,23 @@
             e.printStackTrace();
         }
     }
+    
+    public class TestHttpSessionListener implements HttpSessionListener
+    {
+        public List<String> createdSessions = new ArrayList<String>();
+        public List<String> destroyedSessions = new ArrayList<String>();
+        
+        public void sessionDestroyed(HttpSessionEvent se)
+        {
+            destroyedSessions.add(se.getSession().getId());
+        }
+        
+        public void sessionCreated(HttpSessionEvent se)
+        {
+            createdSessions.add(se.getSession().getId());
+        }
+    };
+    
 
     @Test
     public void testSessionNotExpired() throws Exception
@@ -75,7 +97,7 @@
             //make a request to set up a session on the server
             ContentResponse response = client.GET(url + "?action=init");
             assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-            String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+            String sessionCookie = response.getHeaders().get("Set-Cookie");
             assertTrue(sessionCookie != null);
             // Mangle the cookie, replacing Path with $Path, etc.
             sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -101,18 +123,26 @@
             server1.stop();
         }
     }
+    
 
     @Test
     public void testSessionExpiry() throws Exception
     {
+     
+        
         String contextPath = "";
         String servletMapping = "/server";
         int inactivePeriod = 2;
-        int scavengePeriod = 10;
+        int scavengePeriod = 1;
         AbstractTestServer server1 = createServer(0, inactivePeriod, scavengePeriod);
         TestServlet servlet = new TestServlet();
         ServletHolder holder = new ServletHolder(servlet);
-        server1.addContext(contextPath).addServlet(holder, servletMapping);
+        ServletContextHandler context = server1.addContext(contextPath);
+        context.addServlet(holder, servletMapping);
+        TestHttpSessionListener listener = new TestHttpSessionListener();
+        
+        context.getSessionHandler().addEventListener(listener);
+        
         server1.start();
         int port1 = server1.getPort();
 
@@ -125,11 +155,15 @@
             //make a request to set up a session on the server
             ContentResponse response1 = client.GET(url + "?action=init");
             assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-            String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+            String sessionCookie = response1.getHeaders().get("Set-Cookie");
             assertTrue(sessionCookie != null);
             // Mangle the cookie, replacing Path with $Path, etc.
             sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
-
+            
+            String sessionId = AbstractTestServer.extractSessionId(sessionCookie);     
+            
+            verifySessionCreated(listener,sessionId);
+            
             //now stop the server
             server1.stop();
 
@@ -138,6 +172,7 @@
 
             //restart the server
             server1.start();
+            
             port1 = server1.getPort();
             url = "http://localhost:" + port1 + contextPath + servletMapping;
 
@@ -146,12 +181,27 @@
             request.getHeaders().add("Cookie", sessionCookie);
             ContentResponse response2 = request.send();
             assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
+            
+            //and wait until the expiry time has passed
+            pause(inactivePeriod);
+            
+            verifySessionDestroyed (listener, sessionId);
         }
         finally
         {
             server1.stop();
-        }
+        }     
     }
+    public void verifySessionCreated (TestHttpSessionListener listener, String sessionId)
+    {
+        assertTrue(listener.createdSessions.contains(sessionId));
+    }
+    public void verifySessionDestroyed (TestHttpSessionListener listener, String sessionId)
+    {
+        assertTrue (listener.destroyedSessions.contains(sessionId));
+    }
+
+
 
     public static class TestServlet extends HttpServlet
     {
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java
index a06d6a2..4c3a06f 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateAndCreateTest.java
@@ -42,7 +42,6 @@
 import org.eclipse.jetty.client.api.Request;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.servlet.ServletHolder;
-import org.junit.Assert;
 import org.junit.Test;
 
 /**
@@ -119,7 +118,7 @@
                 // Create the session
                 ContentResponse response1 = client.GET(url + "?action=init");
                 assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response1.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java
index cab1465..3e0f608 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionMigrationTest.java
@@ -72,7 +72,7 @@
                     Request request1 = client.POST("http://localhost:" + port1 + contextPath + servletMapping + "?action=set&value=" + value);
                     ContentResponse response1 = request1.send();
                     assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue(sessionCookie != null);
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java
index 16497cb..3468ab3 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java
@@ -70,7 +70,7 @@
             ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
             assertEquals(HttpServletResponse.SC_OK,response.getStatus());
 
-            String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+            String sessionCookie = response.getHeaders().get("Set-Cookie");
             assertTrue(sessionCookie != null);
             assertFalse(testListener.isCalled());
 
@@ -79,7 +79,7 @@
             request.header("Cookie", sessionCookie);
             ContentResponse renewResponse = request.send();
             assertEquals(HttpServletResponse.SC_OK,renewResponse.getStatus());
-            String renewSessionCookie = renewResponse.getHeaders().getStringField("Set-Cookie");
+            String renewSessionCookie = renewResponse.getHeaders().get("Set-Cookie");
             assertNotNull(renewSessionCookie);
             assertNotSame(sessionCookie, renewSessionCookie);
             assertTrue(testListener.isCalled());
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java
index 38d3dbf..da4b976 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionValueSavingTest.java
@@ -37,7 +37,7 @@
 
 
 /**
- * AbstractLastAccessTimeTest
+ * AbstractSessionValueSavingTest
  */
 public abstract class AbstractSessionValueSavingTest
 {
@@ -72,7 +72,7 @@
 
                     sessionTestValue = Long.parseLong(response1.getContentAsString());
 
-                    String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response1.getHeaders().get("Set-Cookie");
                     assertTrue( sessionCookie != null );
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
@@ -95,7 +95,7 @@
                         assertTrue(sessionTestValue < Long.parseLong(response2.getContentAsString()));
                         sessionTestValue = Long.parseLong(response2.getContentAsString());
 
-                        String setCookie = response1.getHeaders().getStringField("Set-Cookie");
+                        String setCookie = response1.getHeaders().get("Set-Cookie");
                         if (setCookie!=null)
                             sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
 
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java
index af8655e..c3da3a4 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.server.session;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
@@ -36,6 +35,11 @@
 import org.eclipse.jetty.servlet.ServletHolder;
 import org.junit.Test;
 
+/**
+ * AbstractStopSessionManagerPreserveSessionTest
+ *
+ *
+ */
 public abstract class AbstractStopSessionManagerPreserveSessionTest
 {
     public String _id;
@@ -74,7 +78,7 @@
                 //Create a session
                 ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping + "?action=create");
                 assertEquals(HttpServletResponse.SC_OK,response.getStatus());
-                String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                String sessionCookie = response.getHeaders().get("Set-Cookie");
                 assertTrue(sessionCookie != null);
                 // Mangle the cookie, replacing Path with $Path, etc.
                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java
index 7de9e84..8806012 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java
@@ -34,17 +34,38 @@
  */
 public abstract class AbstractTestServer
 {
+    public static int DEFAULT_MAX_INACTIVE = 30;
+    public static int DEFAULT_SCAVENGE = 10;
+    
     protected final Server _server;
     protected final int _maxInactivePeriod;
     protected final int _scavengePeriod;
     protected final ContextHandlerCollection _contexts;
     protected SessionIdManager _sessionIdManager;
 
+  
+    
+    public static String extractSessionId (String sessionCookie)
+    {
+        if (sessionCookie == null)
+            return null;
+        sessionCookie = sessionCookie.trim();
+        int i = sessionCookie.indexOf(';');
+        if (i >= 0)
+            sessionCookie = sessionCookie.substring(0,i);
+        if (sessionCookie.startsWith("JSESSIONID"))
+            sessionCookie = sessionCookie.substring("JSESSIONID=".length());
+        i = sessionCookie.indexOf('.');
+        if (i >=0)
+            sessionCookie = sessionCookie.substring(0,i);
+        return sessionCookie;
+    }
+
     
     
     public AbstractTestServer(int port)
     {
-        this(port, 30, 10);
+        this(port, DEFAULT_MAX_INACTIVE, DEFAULT_SCAVENGE);
     }
 
     public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod)
@@ -52,7 +73,7 @@
         this (port, maxInactivePeriod, scavengePeriod, null);
     }
     
-    public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, String sessionIdMgrConfig)
+    public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, Object sessionIdMgrConfig)
     {
         _server = new Server(port);
         _maxInactivePeriod = maxInactivePeriod;
@@ -64,7 +85,7 @@
     
     
 
-    public abstract SessionIdManager newSessionIdManager(String config);
+    public abstract SessionIdManager newSessionIdManager(Object config);
     public abstract SessionManager newSessionManager();
     public abstract SessionHandler newSessionHandler(SessionManager sessionManager);
 
diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
index 6cf6bb6..d924953 100644
--- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractWebAppObjectInSessionTest.java
@@ -120,7 +120,7 @@
 
                     ContentResponse response = request.send();
                     assertEquals( HttpServletResponse.SC_OK, response.getStatus());
-                    String sessionCookie = response.getHeaders().getStringField("Set-Cookie");
+                    String sessionCookie = response.getHeaders().get("Set-Cookie");
                     assertTrue(sessionCookie != null);
                     // Mangle the cookie, replacing Path with $Path, etc.
                     sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml
index 731e61e..33c23a8 100644
--- a/tests/test-webapps/pom.xml
+++ b/tests/test-webapps/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>tests-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>test-webapps-parent</artifactId>
diff --git a/tests/test-webapps/test-dispatch-webapp/pom.xml b/tests/test-webapps/test-dispatch-webapp/pom.xml
index 4a1f2b6..5afe024 100644
--- a/tests/test-webapps/test-dispatch-webapp/pom.xml
+++ b/tests/test-webapps/test-dispatch-webapp/pom.xml
@@ -4,11 +4,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.2-SNAPSHOT</version>
+    <version>9.3.0-SNAPSHOT</version>
   </parent>
   <name>Jetty Tests :: Webapps :: Dispatch Webapp</name>
   <artifactId>test-dispatch-webapp</artifactId>
   <packaging>war</packaging>
+   <properties>
+    <bundle-symbolic-name>${project.groupId}.dispatch</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-webapps/test-jaas-webapp/pom.xml b/tests/test-webapps/test-jaas-webapp/pom.xml
index f006e7a..5d2261b 100644
--- a/tests/test-webapps/test-jaas-webapp/pom.xml
+++ b/tests/test-webapps/test-jaas-webapp/pom.xml
@@ -4,11 +4,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-jaas-webapp</artifactId>
   <name>Jetty Tests :: WebApp :: JAAS</name>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.jaas</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -28,8 +31,8 @@
           <systemProperties>
               <!-- This is for convenience so that the src/etc/login.conf file can stay unmodified when copied to $jetty.home/etc directory -->
             <systemProperty>
-              <name>jetty.home</name>
-              <value>${basedir}/src/main/config</value>
+              <name>jetty.base</name>
+              <value>${basedir}/src/main/config/demo-base</value>
             </systemProperty>
               <!-- Mandatory. This system property tells JAAS where to find the login module configuration file -->
             <systemProperty>
@@ -47,6 +50,13 @@
             </securityHandler>
           </webAppConfig>
         </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.19</version>
+          </dependency>
+        </dependencies>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
diff --git a/tests/test-webapps/test-jaas-webapp/src/main/config/demo-base/webapps/test-jaas.xml b/tests/test-webapps/test-jaas-webapp/src/main/config/demo-base/webapps/test-jaas.xml
index f3b0a18..c56276b 100644
--- a/tests/test-webapps/test-jaas-webapp/src/main/config/demo-base/webapps/test-jaas.xml
+++ b/tests/test-webapps/test-jaas-webapp/src/main/config/demo-base/webapps/test-jaas.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the test-jndi webapp                                  -->
diff --git a/tests/test-webapps/test-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index e7830c6..ecd5e30 100644
--- a/tests/test-webapps/test-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/tests/test-webapps/test-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
   <Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
diff --git a/tests/test-webapps/test-jaas-webapp/src/main/webapp/auth.html b/tests/test-webapps/test-jaas-webapp/src/main/webapp/auth.html
index 249f958..ab12241 100644
--- a/tests/test-webapps/test-jaas-webapp/src/main/webapp/auth.html
+++ b/tests/test-webapps/test-jaas-webapp/src/main/webapp/auth.html
@@ -1,7 +1,7 @@
 <HTML>
   <HEAD>
     <META http-equiv="Pragma" content="no-cache">
-    <META http-equiv="Cache-Control" content="no-cache,no-store">
+    <META http-equiv="Cache-Control" content="no-cache,no-store,must-revalidate">
     <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
   </HEAD>
 
diff --git a/tests/test-webapps/test-jetty-webapp/pom.xml b/tests/test-webapps/test-jetty-webapp/pom.xml
index 7fe045b..a4d590a 100644
--- a/tests/test-webapps/test-jetty-webapp/pom.xml
+++ b/tests/test-webapps/test-jetty-webapp/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -29,6 +29,9 @@
   <name>Test :: Jetty Test Webapp</name>
   <url>http://www.eclipse.org/jetty</url>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.tests.webapp</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -70,15 +73,6 @@
           </execution>
         </executions>
       </plugin>
-      <!-- also make this webapp an osgi bundle -->
-      <plugin>
-        <artifactId>maven-war-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
@@ -87,32 +81,29 @@
           <supportedProjectTypes>
             <supportedProjectType>war</supportedProjectType>
           </supportedProjectTypes>
+          <instructions>
+            <Import-Package>javax.servlet.jsp.*;version="[2.2.0,3.0)",org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",*</Import-Package>
+            <Export-Package>!com.acme*</Export-Package>
+            <!-- the test webapp is configured via a jetty xml file
+            in order to add the security handler. -->
+            <Web-ContextPath>/</Web-ContextPath>
+            <!-- in fact the '.' must not be there
+            but Felix-BND has a bug:
+            http://www.mail-archive.com/users@felix.apache.org/msg04730.html
+            https://issues.apache.org/jira/browse/FELIX-1571
+            -->
+            <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
+          </instructions>
         </configuration>
-        <executions>
-          <execution>
-            <id>bundle-manifest</id>
-            <phase>process-classes</phase>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Bundle-SymbolicName>org.eclipse.jetty.test-jetty-webapp</Bundle-SymbolicName>
-                <Import-Package>javax.servlet.jsp.*;version="[2.2.0, 3.0)",javax.servlet.*;version="[2.6,3.2)",org.eclipse.jetty.*;version="9.1",*</Import-Package>
-                <Export-Package>!com.acme*</Export-Package>
-                <!-- the test webapp is configured via a jetty xml file
-                in order to add the security handler. -->
-                <Web-ContextPath>/</Web-ContextPath>
-                <!-- in fact the '.' must not be there
-                but Felix-BND has a bug:
-                http://www.mail-archive.com/users@felix.apache.org/msg04730.html
-                https://issues.apache.org/jira/browse/FELIX-1571
-                -->
-                <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
+      </plugin>
+      <!-- also make this webapp an osgi bundle -->
+      <plugin>
+        <artifactId>maven-war-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+          </archive>
+        </configuration>
       </plugin>
       <plugin>
         <groupId>org.eclipse.jetty</groupId>
@@ -199,6 +190,13 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.jetty.toolchain</groupId>
       <artifactId>jetty-test-helper</artifactId>
       <scope>test</scope>
@@ -216,12 +214,6 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>jstl</artifactId>
       <version>1.2</version>
@@ -249,10 +241,14 @@
               <goals>
                 <goal>jspc</goal>
               </goals>
+             <!-- example configuration
               <configuration>
-                 <includes>**/*.foo</includes>
-                 <excludes>**/*.fff</excludes>
+                <includes>**/*.foo</includes>
+                <excludes>**/*.fff</excludes>
+                <sourceVersion>1.8</sourceVersion>
+                <targetVersion>1.8</targetVersion>
               </configuration>
+              -->
             </execution>
           </executions>
         </plugin>
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml b/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
index 5d223e3..9b4e892 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/assembly/embedded-jetty-web-for-webbundle.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ==================================================================
 Configure and deploy the test web application in $(jetty.home)/webapps/test
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/demo-rewrite-rules.xml b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/demo-rewrite-rules.xml
index 35a8f87..df2c608 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/demo-rewrite-rules.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/demo-rewrite-rules.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the demos                                             -->
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/test-realm.xml b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/test-realm.xml
index d5c776b..f1b342b 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/test-realm.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/test-realm.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 <Configure id="Server" class="org.eclipse.jetty.server.Server">
     <!-- =========================================================== -->
     <!-- Configure Authentication Login Service                      -->
@@ -12,7 +12,7 @@
       <Arg>
         <New class="org.eclipse.jetty.security.HashLoginService">
           <Set name="name">Test Realm</Set>
-          <Set name="config"><Property name="demo.realm" default="etc/realm.properties"/></Set>
+          <Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set>
           <Set name="refreshInterval">0</Set>
         </New>
       </Arg>
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/start.ini b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/start.ini
index 9a840f4..5921b61 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/start.ini
+++ b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/start.ini
@@ -6,7 +6,7 @@
 
 # Enable security via jaas, and configure it
 --module=jaas
-jaas.login.conf=etc/login.conf
+jetty.jaas.login.conf=etc/login.conf
 
 # Enable rewrite examples
 --module=rewrite
@@ -19,5 +19,5 @@
 
 # Create and configure the test realm
 etc/test-realm.xml
-demo.realm=etc/realm.properties
+jetty.demo.realm=etc/realm.properties
 
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml
index 43047f9..a975ec7 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/webapps/test.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- ==================================================================
 Configure and deploy the test web application in $(jetty.home)/webapps/test
@@ -11,7 +11,7 @@
 detected.
 ===================================================================== -->
 
-<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+<Configure id="testWebapp" class="org.eclipse.jetty.webapp.WebAppContext">
 
   <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
   <!-- Required minimal context configuration :                        -->
@@ -35,6 +35,21 @@
     <Arg type="Boolean">true</Arg>
   </Call>
   
+  <Set name="gzipHandler">
+    <New class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
+      <Set name="minGzipSize">2048</Set>      
+    </New>
+  </Set>
+  
+  <!-- Set Caching Classloader that improves performance on resource searching webapps -->
+  <!--
+  <Set name="classLoader">
+    <New class="org.eclipse.jetty.webapp.CachingWebAppClassLoader">
+      <Arg><Ref refid="testWebapp"/></Arg>
+    </New>
+  </Set>
+  -->
+  
   <!-- Enable symlinks 
   <Call name="addAliasCheck">
     <Arg><New class="org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker"/></Arg>
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java
index 84da9c4..b47d0de 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java
+++ b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/Dump.java
@@ -118,7 +118,7 @@
             }
             catch(ServletException se)
             {
-                se.printStackTrace();
+                getServletContext().log(se.toString());
             }
         }
 
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/SessionDump.java b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/SessionDump.java
index 63fed54..c4290f0 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/SessionDump.java
+++ b/tests/test-webapps/test-jetty-webapp/src/main/java/com/acme/SessionDump.java
@@ -36,6 +36,23 @@
 @SuppressWarnings("serial")
 public class SessionDump extends HttpServlet
 {
+    /** 
+      * Simple object attribute to test serialization
+      */
+    public class ObjectAttributeValue implements java.io.Serializable
+    {
+        long l;
+        
+        public ObjectAttributeValue(long l)
+        {
+            this.l = l;
+        }
+
+        public long getValue()
+        {
+            return l;
+        }
+    }
 
     int redirectCount=0;
     /* ------------------------------------------------------------ */
@@ -64,6 +81,7 @@
             {
                 session = request.getSession(true);
                 session.setAttribute("test","value");
+                session.setAttribute("obj", new ObjectAttributeValue(System.currentTimeMillis()));
             }
             else if (session!=null)
             {
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 19fb028..c04f74c 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!--
 This is the jetty specific web application configuration file.  When starting
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
index a2b3763..bf3f330 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
@@ -10,7 +10,7 @@
   
   <context-param>
     <param-name>org.eclipse.jetty.server.context.ManagedAttributes</param-name>
-    <param-value>QoSFilter,TransparentProxy.ThreadPool,TransparentProxy.HttpClient</param-value>
+    <param-value>PushFilter,QoSFilter,TransparentProxy.ThreadPool,TransparentProxy.HttpClient</param-value>
   </context-param>
   
   <!-- Declare TestListener, which declares TestFilter -->
@@ -18,6 +18,15 @@
     <listener-class>com.acme.TestListener</listener-class>
   </listener>
 
+  <filter>
+    <filter-name>PushFilter</filter-name>
+    <filter-class>org.eclipse.jetty.servlets.PushCacheFilter</filter-class>
+    <async-supported>true</async-supported>
+  </filter>  
+  <filter-mapping>
+    <filter-name>PushFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
 
   <filter>
     <filter-name>QoSFilter</filter-name>
@@ -52,46 +61,6 @@
     <url-pattern>/dump/*</url-pattern>
   </filter-mapping>
   
-
-  <filter>
-    <filter-name>GzipFilter</filter-name>
-    <filter-class>org.eclipse.jetty.servlets.AsyncGzipFilter</filter-class>
-    <async-supported>true</async-supported>
-    <init-param>
-      <param-name>bufferSize</param-name>
-      <param-value>8192</param-value>
-    </init-param>
-    <init-param>
-      <param-name>mimeTypes</param-name>
-      <param-value>text/plain,application/xml,text/html</param-value>
-    </init-param>
-    <init-param>
-      <param-name>minGzipSize</param-name>
-      <param-value>2048</param-value>
-    </init-param>
-    <init-param>
-      <param-name>userAgent</param-name>
-      <param-value>(?:Mozilla[^\(]*\(compatible;\s*+([^;]*);.*)|(?:.*?([^\s]+/[^\s]+).*)</param-value>
-    </init-param>
-    <init-param>
-      <param-name>cacheSize</param-name>
-      <param-value>1024</param-value>
-    </init-param>
-    <init-param>
-      <param-name>excludedAgents</param-name>
-      <param-value>MSIE 6.0</param-value>
-    </init-param>
-    <init-param>
-      <param-name>uncheckedPrintWriter</param-name>
-      <param-value>true</param-value>
-    </init-param>
-  </filter>
-  <filter-mapping>
-    <filter-name>GzipFilter</filter-name>
-    <url-pattern>/dump/gzip/*</url-pattern>
-    <url-pattern>*.txt</url-pattern>
-  </filter-mapping>
-  
   <servlet>
     <servlet-name>Login</servlet-name>
     <servlet-class>com.acme.LoginServlet</servlet-class>
diff --git a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
index 19cde65..d8b8243 100644
--- a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
+++ b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
@@ -93,43 +93,7 @@
         httpConnector.setIdleTimeout(30000);
         server.addConnector(httpConnector);
 
-        /*
-        // SSL configurations
-        SslContextFactory sslContextFactory = new SslContextFactory();
-        sslContextFactory.setKeyStorePath(jetty_root + "/jetty-server/src/main/config/etc/keystore");
-        sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
-        sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
-        sslContextFactory.setTrustStorePath(jetty_root + "/jetty-server/src/main/config/etc/keystore");
-        sslContextFactory.setTrustStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
-        sslContextFactory.setExcludeCipherSuites(
-                "SSL_RSA_WITH_DES_CBC_SHA",
-                "SSL_DHE_RSA_WITH_DES_CBC_SHA",
-                "SSL_DHE_DSS_WITH_DES_CBC_SHA",
-                "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
-                "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
-                "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
-        
-        
-        // Spdy Connector
-        SPDYServerConnectionFactory.checkNPNAvailable();
-        PushStrategy push = new ReferrerPushStrategy();
-        HTTPSPDYServerConnectionFactory spdy2 = new HTTPSPDYServerConnectionFactory(2,config,push);
-        spdy2.setInputBufferSize(8192);
-        spdy2.setInitialWindowSize(32768);
-        HTTPSPDYServerConnectionFactory spdy3 = new HTTPSPDYServerConnectionFactory(3,config,push);
-        spdy2.setInputBufferSize(8192);
-        NPNServerConnectionFactory npn = new NPNServerConnectionFactory(spdy3.getProtocol(),spdy2.getProtocol(),http.getProtocol());
-        npn.setDefaultProtocol(http.getProtocol());
-        npn.setInputBufferSize(1024); 
-        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol()); 
-        ServerConnector spdyConnector = new ServerConnector(server,ssl,npn,spdy3,spdy2,http);
-        spdyConnector.setPort(8443);
-        spdyConnector.setIdleTimeout(15000);
-        server.addConnector(spdyConnector);
-        
-        */
-        
+
         // Handlers
         HandlerCollection handlers = new HandlerCollection();
         ContextHandlerCollection contexts = new ContextHandlerCollection();
@@ -158,6 +122,7 @@
         server.setStopAtShutdown(true);
 
         WebAppContext webapp = new WebAppContext();
+        webapp.setContextPath("/test");
         webapp.setParentLoaderPriority(true);
         webapp.setResourceBase("./src/main/webapp");
         webapp.setAttribute("testAttribute","testValue");
diff --git a/tests/test-webapps/test-jndi-webapp/pom.xml b/tests/test-webapps/test-jndi-webapp/pom.xml
index f222ff1..27de070 100644
--- a/tests/test-webapps/test-jndi-webapp/pom.xml
+++ b/tests/test-webapps/test-jndi-webapp/pom.xml
@@ -4,11 +4,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-jndi-webapp</artifactId>
   <name>Jetty Tests :: WebApp :: JNDI</name>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.jndi</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-webapps/test-jndi-webapp/src/main/templates/jetty-test-jndi-header.xml b/tests/test-webapps/test-jndi-webapp/src/main/templates/jetty-test-jndi-header.xml
index 4f4ded0..484551a 100644
--- a/tests/test-webapps/test-jndi-webapp/src/main/templates/jetty-test-jndi-header.xml
+++ b/tests/test-webapps/test-jndi-webapp/src/main/templates/jetty-test-jndi-header.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the test-jndi webapp                                  -->
diff --git a/tests/test-webapps/test-jndi-webapp/src/main/templates/plugin-context-header.xml b/tests/test-webapps/test-jndi-webapp/src/main/templates/plugin-context-header.xml
index 3e877a5..bd97eb1 100644
--- a/tests/test-webapps/test-jndi-webapp/src/main/templates/plugin-context-header.xml
+++ b/tests/test-webapps/test-jndi-webapp/src/main/templates/plugin-context-header.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <!-- =============================================================== -->
 <!-- Configure the test-jndi webapp                                  -->
diff --git a/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-env.xml b/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-env.xml
index b7fa49f..7899c45 100644
--- a/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-env.xml
+++ b/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-env.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index fd4831e..203f811 100644
--- a/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/tests/test-webapps/test-jndi-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
   <Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
diff --git a/tests/test-webapps/test-mock-resources/pom.xml b/tests/test-webapps/test-mock-resources/pom.xml
index 7ead92e..6485af8 100644
--- a/tests/test-webapps/test-mock-resources/pom.xml
+++ b/tests/test-webapps/test-mock-resources/pom.xml
@@ -3,11 +3,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <name>Jetty Tests :: WebApp :: Mock Resources</name>
   <artifactId>test-mock-resources</artifactId>
   <packaging>jar</packaging>
+  <properties>
+   <bundle-symbolic-name>${project.groupId}.mocks</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -22,7 +25,6 @@
         <extensions>true</extensions>
         <executions>
           <execution>
-            <id>generate-manifest</id>
             <goals>
               <goal>manifest</goal>
             </goals>
@@ -44,23 +46,6 @@
           </execution>
         </executions>
       </plugin>
-     <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>artifact-jar</id>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-          </archive>
-        </configuration>
-      </plugin>
     </plugins>
   </build>
   <dependencies>
@@ -73,12 +58,6 @@
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
     </dependency>
-<!--
-    <dependency>
-      <groupId>javax.mail</groupId>
-      <artifactId>javax.mail-api</artifactId>
-    </dependency>
--->
     <dependency>
       <groupId>org.eclipse.jetty.orbit</groupId>
       <artifactId>javax.mail.glassfish</artifactId>
diff --git a/tests/test-webapps/test-mock-resources/src/main/java/com/acme/MockTransport.java b/tests/test-webapps/test-mock-resources/src/main/java/com/acme/MockTransport.java
index bbcd58c..eb11f95 100644
--- a/tests/test-webapps/test-mock-resources/src/main/java/com/acme/MockTransport.java
+++ b/tests/test-webapps/test-mock-resources/src/main/java/com/acme/MockTransport.java
@@ -28,12 +28,9 @@
 
 /**
  * MockTransport
- *
- *
  */
 public class MockTransport extends Transport
 {
-
     /**
      * @param session
      * @param urlname
diff --git a/tests/test-webapps/test-proxy-webapp/pom.xml b/tests/test-webapps/test-proxy-webapp/pom.xml
index e885cf9..00f658c 100644
--- a/tests/test-webapps/test-proxy-webapp/pom.xml
+++ b/tests/test-webapps/test-proxy-webapp/pom.xml
@@ -20,7 +20,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -28,6 +28,9 @@
   <artifactId>test-proxy-webapp</artifactId>
   <name>Test :: Jetty Proxy Webapp</name>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.proxy</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -83,18 +86,30 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
+      <groupId>org.eclipse.jetty.http2</groupId>
+      <artifactId>http2-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-alpn-server</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>javax.servlet.jsp</groupId>
       <artifactId>jsp-api</artifactId>
       <version>2.1</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jetty.spdy</groupId>
-      <artifactId>spdy-http-server</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>jstl</artifactId>
       <version>1.2</version>
diff --git a/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 030fd19..e2cb8ec 100644
--- a/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
   <Set name="contextPath">/proxy</Set>
diff --git a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java
index 3e9c2fc..22d2dbe 100644
--- a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java
+++ b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java
@@ -20,11 +20,15 @@
 
 import java.lang.management.ManagementFactory;
 
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.http2.HTTP2Cipher;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
 import org.eclipse.jetty.jmx.MBeanContainer;
 import org.eclipse.jetty.server.ForwardedRequestCustomizer;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
 import org.eclipse.jetty.server.SecureRequestCustomizer;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
@@ -32,11 +36,6 @@
 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
 import org.eclipse.jetty.server.handler.DefaultHandler;
 import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory;
-import org.eclipse.jetty.spdy.server.http.PushStrategy;
-import org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.StdErrLog;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -71,7 +70,6 @@
         HttpConfiguration config = new HttpConfiguration();
         config.setSecurePort(8443);
         config.addCustomizer(new ForwardedRequestCustomizer());
-        config.addCustomizer(new SecureRequestCustomizer());
         config.setSendDateHeader(true);
         config.setSendServerVersion(true);
         
@@ -99,24 +97,28 @@
                 "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
                 "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
                 "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+        sslContextFactory.setCipherComparator(new HTTP2Cipher.CipherComparator());
         
+
+        // HTTPS Configuration
+        HttpConfiguration https_config = new HttpConfiguration(config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
         
-        // Spdy Connector
-        SPDYServerConnectionFactory.checkProtocolNegotiationAvailable();
-        PushStrategy push = new ReferrerPushStrategy();
-        HTTPSPDYServerConnectionFactory spdy2 = new HTTPSPDYServerConnectionFactory(2,config,push);
-        spdy2.setInputBufferSize(8192);
-        spdy2.setInitialWindowSize(32768);
-        HTTPSPDYServerConnectionFactory spdy3 = new HTTPSPDYServerConnectionFactory(3,config,push);
-        spdy2.setInputBufferSize(8192);
-        NPNServerConnectionFactory npn = new NPNServerConnectionFactory(spdy3.getProtocol(),spdy2.getProtocol(),http.getProtocol());
-        npn.setDefaultProtocol(http.getProtocol());
-        npn.setInputBufferSize(1024); 
-        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,npn.getProtocol()); 
-        ServerConnector spdyConnector = new ServerConnector(server,ssl,npn,spdy3,spdy2,http);
-        spdyConnector.setPort(8443);
-        spdyConnector.setIdleTimeout(15000);
-        server.addConnector(spdyConnector);
+        // HTTP2 factory
+        HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
+        NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
+        ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+        alpn.setDefaultProtocol(h2.getProtocol());
+        
+        // SSL Factory
+        SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory,alpn.getProtocol());
+        
+        // HTTP2 Connector
+        ServerConnector http2Connector = 
+            new ServerConnector(server,ssl,alpn,h2,new HttpConnectionFactory(https_config));
+        http2Connector.setPort(8443);
+        http2Connector.setIdleTimeout(15000);
+        server.addConnector(http2Connector);
         
         // Handlers
         HandlerCollection handlers = new HandlerCollection();
diff --git a/tests/test-webapps/test-servlet-spec/pom.xml b/tests/test-webapps/test-servlet-spec/pom.xml
index 2a0f703..4f23914 100644
--- a/tests/test-webapps/test-servlet-spec/pom.xml
+++ b/tests/test-webapps/test-servlet-spec/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-servlet-spec-parent</artifactId>
   <name>Jetty Tests :: Spec Test WebApp :: Parent</name>
diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml
index c82a26f..7b367e5 100644
--- a/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml
+++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml
@@ -3,11 +3,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-servlet-spec-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-container-initializer</artifactId>
   <packaging>jar</packaging>
   <name>Jetty Tests :: WebApp :: Servlet Spec :: ServletContainerInitializer Test Jar</name>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.sci</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
        <plugin>
@@ -37,15 +40,6 @@
           <groupId>org.apache.felix</groupId>
           <artifactId>maven-bundle-plugin</artifactId>
           <extensions>true</extensions>
-          <executions>
-              <execution>
-                  <id>bundle-manifest</id>
-                  <phase>process-classes</phase>
-                  <goals>
-                      <goal>manifest</goal>
-                  </goals>
-              </execution>
-          </executions>
           <configuration>
               <instructions>
                   <Bundle-SymbolicName>org.eclipse.jetty.tests.test-servlet-container-initializer;singleton:=true</Bundle-SymbolicName>
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml
index c7fbb24..b90045d 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml
@@ -4,11 +4,14 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-servlet-spec-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <name>Jetty Tests :: Webapps :: Spec Webapp</name>
   <artifactId>test-spec-webapp</artifactId>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.spec</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -68,37 +71,26 @@
           <supportedProjectTypes>
             <supportedProjectType>war</supportedProjectType>
           </supportedProjectTypes>
+          <instructions>
+            <Bundle-SymbolicName>org.eclipse.jetty.tests.test-spec-webapp</Bundle-SymbolicName>
+            <Bundle-Description>Test Webapp for Servlet 3.1 Features</Bundle-Description>
+            <Import-Package>
+              javax.servlet.jsp.*;version="[2.2.0, 3.0)",
+              javax.transaction*;version="[1.1,1.3)",
+              javax.servlet*;version="[2.6,3.2)",
+              org.eclipse.jetty*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))",
+              org.eclipse.jetty.webapp;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:="optional",
+              org.eclipse.jetty.plus.jndi;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))";resolution:="optional",
+              com.acme;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
+              *
+            </Import-Package>
+            <_nouses/>
+            <Export-Package>com.acme.test;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";-noimport:=true</Export-Package>
+            <Web-ContextPath>/</Web-ContextPath>
+            <Bundle-ClassPath>.,WEB-INF/classes,WEB-INF/lib</Bundle-ClassPath>
+            <Jetty-ContextFilePath>/META-INF/plugin-context.xml</Jetty-ContextFilePath>
+          </instructions>
         </configuration>
-        <executions>
-          <execution>
-            <id>bundle-manifest</id>
-            <phase>process-classes</phase>
-            <goals>
-              <goal>manifest</goal>
-            </goals>
-            <configuration>
-              <instructions>
-                <Bundle-SymbolicName>org.eclipse.jetty.tests.test-spec-webapp</Bundle-SymbolicName>
-                <Bundle-Description>Test Webapp for Servlet 3.1 Features</Bundle-Description>
-                <Import-Package>
-                  javax.servlet.jsp.*;version="[2.2.0, 3.0)",
-                  javax.transaction.*;version="[1.1, 2.0)", 
-                  javax.servlet.*;version="3.0",
-                  javax.sql,
-                  org.eclipse.jetty.webapp;version="9.2",org.eclipse.jetty.plus.jndi;version="9.2",
-                  org.eclipse.jetty.security;version="9.2",
-                  com.acme;version="9.2",
-                  *
-                </Import-Package>
-                <Export-Package>com.acme.test;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
-                <Web-ContextPath>/</Web-ContextPath>
-                <Bundle-ClassPath>.,WEB-INF/classes,WEB-INF/lib</Bundle-ClassPath>
-                <Jetty-ContextFilePath>./META-INF/plugin-context.xml</Jetty-ContextFilePath>
-                <_nouses>true</_nouses>
-              </instructions>
-            </configuration>
-           </execution>
-        </executions>
       </plugin>
 
 
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/TestListener.java b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/TestListener.java
index 63ebe7a..fb02b91 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/TestListener.java
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/TestListener.java
@@ -19,7 +19,6 @@
 package com.acme.test;
 import java.util.EventListener;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener;
@@ -112,8 +111,6 @@
 
     public void contextInitialized(ServletContextEvent sce)
     {
-        System.err.println("Calling TestListener.contextInitialized");
-        
         sce.getServletContext().setAttribute("com.acme.AnnotationTest.sclInjectTest", Boolean.valueOf(maxAmount != null));
         
         //Can't add a ServletContextListener from a ServletContextListener even if it is declared in web.xml
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/annotations-context-header.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/annotations-context-header.xml
index 50b5981..ff2f6a1 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/annotations-context-header.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/annotations-context-header.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 
 <!-- =============================================================== -->
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/plugin-context-header.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/plugin-context-header.xml
index 450edda..36ff548 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/plugin-context-header.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/templates/plugin-context-header.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 
 <!-- =============================================================== -->
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-env.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-env.xml
index c15926b..909ac83 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-env.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-env.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 62b92f9..e360f5c 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure class="org.eclipse.jetty.webapp.WebAppContext">
   <Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html
index d3ec487..2db5dd5 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html
@@ -29,13 +29,21 @@
   <button type="submit">Test</button>
 </form>
 
-<h3>DeclaresRoles</h3>
+<h3>Test Static Content from Fragment </h3>
+<p>Click the link to test accessing static content from a fragment's META-INF/resources</p>
+<a href="fragmentA/index.html">Static resource from a fragment </a>
+
+<h3>Test Servlet from Fragment </h3>
+<p>Click the link to test accessing a servlet added from a fragment's web-fragment.xml</p>
+<a href="fragment">Servlet added by web-fragment.xml</a>
+
+<h3>Test DeclaresRoles</h3>
 <p>Login as user <code>admin</code> with password <code>admin</code> when prompted after clicking the button below to test @DeclareRoles annotation</p>
 <form action="role" method="post">
   <button type="submit">Test Role Annotations</button>
 </form>
 
-<h3>ServletSecurity</h3>
+<h3>Test Servlet Security</h3>
 <p>Login as user <code>admin</code> with password <code>admin</code> when prompted after clicking the button below to test @ServletSecurity annotation</p>
 <form action="sec/foo" method="post">
   <button type="submit">Test ServletSecurity Annotation</button>
diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/test/jetty-plugin-env.xml b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/test/jetty-plugin-env.xml
index 7741843..23c4b5b 100644
--- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/test/jetty-plugin-env.xml
+++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/test/jetty-plugin-env.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
 
 <Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
 
diff --git a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml
index d2a5afe..801a63a 100644
--- a/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml
+++ b/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml
@@ -3,12 +3,15 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-servlet-spec-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <name>Jetty Tests :: WebApp :: Servlet Spec :: Fragment Jar</name>
   <groupId>org.eclipse.jetty.tests</groupId>
   <artifactId>test-web-fragment</artifactId>
   <packaging>jar</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.fragment</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
@@ -17,46 +20,6 @@
           <verbose>false</verbose>
         </configuration>
       </plugin>
-       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-            <execution>
-                <id>artifact-jar</id>
-                <goals>
-                    <goal>jar</goal>
-                </goals>
-            </execution>
-        </executions>
-        <configuration>
-            <archive>
-                <manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
-            </archive>
-        </configuration>
-      </plugin>
-      <plugin>
-          <groupId>org.apache.felix</groupId>
-          <artifactId>maven-bundle-plugin</artifactId>
-          <extensions>true</extensions>
-          <executions>
-              <execution>
-                  <id>bundle-manifest</id>
-                  <phase>process-classes</phase>
-                  <goals>
-                      <goal>manifest</goal>
-                  </goals>
-              </execution>
-          </executions>
-          <configuration>
-              <instructions>
-                  <Bundle-SymbolicName>org.eclipse.jetty.tests.test-web-fragment;singleton:=true</Bundle-SymbolicName>
-                  <Bundle-Description>A bundle containing web fragment for testing</Bundle-Description>
-                  <Export-Package>com.acme.fragment;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
-                  <_nouses>true</_nouses>
-              </instructions>
-          </configuration>
-      </plugin>
-
     </plugins>
   </build>
   <dependencies>
@@ -64,5 +27,12 @@
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
       </dependency>
+
+<!--
+    <dependency>
+      <groupId>org.eclipse.jetty.orbit</groupId>
+      <artifactId>javax.servlet</artifactId>
+    </dependency>
+-->
   </dependencies>
 </project>
diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml
index 7568150..0c4fd87 100644
--- a/tests/test-webapps/test-webapp-rfc2616/pom.xml
+++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml
@@ -21,12 +21,15 @@
   <parent>
     <groupId>org.eclipse.jetty.tests</groupId>
     <artifactId>test-webapps-parent</artifactId>
-    <version>9.2.15-SNAPSHOT</version>
+    <version>9.3.7-SNAPSHOT</version>
   </parent>
   <artifactId>test-webapp-rfc2616</artifactId>
   <name>Jetty Tests :: WebApp :: RFC2616</name>
   <url>http://www.eclipse.org/jetty</url>
   <packaging>war</packaging>
+  <properties>
+    <bundle-symbolic-name>${project.groupId}.rfc2616</bundle-symbolic-name>
+  </properties>
   <build>
     <plugins>
       <plugin>
diff --git a/tests/test-webapps/test-webapp-rfc2616/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-webapp-rfc2616/src/main/webapp/WEB-INF/web.xml
index 1ea878d..0685977 100644
--- a/tests/test-webapps/test-webapp-rfc2616/src/main/webapp/WEB-INF/web.xml
+++ b/tests/test-webapps/test-webapp-rfc2616/src/main/webapp/WEB-INF/web.xml
@@ -1,25 +1,20 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
   <display-name>rfc2616-webapp</display-name>
+
+  <context-param>
+    <param-name>org.eclipse.jetty.handler.GzipHandler.minGzipSize</param-name>
+    <param-value>1024</param-value>
+  </context-param>
+  <context-param>
+    <param-name>org.eclipse.jetty.handler.GzipHandler.includePaths</param-name>
+    <param-value>/*</param-value>
+  </context-param>
+  
   <welcome-file-list>
     <welcome-file>index.html</welcome-file>
   </welcome-file-list>
-  <filter>
-    <filter-name>GZIPFilter</filter-name>
-    <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
-    <init-param>
-      <param-name>minGzipSize</param-name>
-      <param-value>1024</param-value>
-    </init-param>
-    <init-param>
-      <param-name>bufferSize</param-name>
-      <param-value>16384</param-value>
-    </init-param>
-  </filter>
-  <filter-mapping>
-    <filter-name>GZIPFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
+  
   <servlet>
     <servlet-name>HttpMethodsServlet</servlet-name>
     <servlet-class>org.eclipse.jetty.tests.webapp.HttpMethodsServlet</servlet-class>
@@ -28,4 +23,4 @@
     <servlet-name>HttpMethodsServlet</servlet-name>
     <url-pattern>/httpmethods</url-pattern>
   </servlet-mapping>
-</web-app>
\ No newline at end of file
+</web-app>